Michael Lubas, 2022-12-20
“Limit the number of login attempts for one IP address to 5 in a 30 second period” is a standard rule for many web applications, and makes sense from the perspective of a site owner dealing with malicious credential stuffing. With the rise of cloud computing, it has become much easier for an attacker to access thousands of different IP addresses, for free, to bypass IP based blocking. This article will use a Phoenix application to demonstrate what the attack looks like, and how Paraxial.io stops it.
AWS API Gateway is a service that handling incoming traffic for a web application, such as HTTP requests, and then triggers some application functionality. The important point for attackers is that the gateway can be pointed at a victim web application, so that when the attacker sends traffic to the gateway, it is proxied through an AWS server, changing the IP address. David Yesland from Rhino Security describes this technique in a blog post, and introduces a Burp Suite extension which can be used to proxy traffic through AWS.
blackcatprojects.xyz is a simple Phoenix application, which will be the target of this traffic. Using Burp Suite, we proxy our traffic through API Gateway, then check the backend logs of blackcatprojects.xyz to see the requests:
Each HTTP request has a different IP from AWS, exactly what an attacker needs to bypass the rule, “Limit the number of login attempts for one IP address to 5 in a 30 second period”.
Amazon publishes the IP ranges of AWS, so it is possible to determine if an incoming request originates from AWS. In most cases, traffic from a cloud provider’s IP range is coming from a bot, however not all bots are malicious. For example, tools to monitor your site’s uptime often rely on cloud hosted bots sending HTTP requests. Blocking bot traffic to the site’s main page is not desirable, but it’s exactly what you want on the login page.
The best way to achieve this in Phoenix is with a Plug, one that looks at an incoming conn’s remote_ip, determines if it matches a known list of cloud IPs, and then allows or halts the request. The implementation of such a Plug is covered in the post Classifying Data Center IP Addresses in Phoenix Web Applications with Radix Trees.
There are a few problems with the system described:
Paraxial.io’s Elixir agent is able to retrieve a radix trie at startup, for use with the Paraxial.BlockCloudIP Plug. This plug can block the attack described above, with the added benefit of a web interface to add IPs to an allow list.
In the blackcatprojects.xyz router:
pipeline :block_cloud_requests do
## Authentication routes
scope "/", HavanaWeb do
pipe_through [:browser, :redirect_if_user_is_authenticated, :block_cloud_requests]
get "/users/register", UserRegistrationController, :new
post "/users/register", UserRegistrationController, :create
get "/users/log_in", UserSessionController, :new
post "/users/log_in", UserSessionController, :create
get "/users/reset_password", UserResetPasswordController, :new
post "/users/reset_password", UserResetPasswordController, :create
get "/users/reset_password/:token", UserResetPasswordController, :edit
put "/users/reset_password/:token", UserResetPasswordController, :update
The attack is blocked against the
/users/log_in route, and good bots can continue to access the main page of the site.
IP based rate limiting is an important tool for defenders, and should be implemented as a first line of defense against attackers. The technique described in this article with API Gateway is well known to attackers, low cost, and often bypasses throttling rules. Sensitive endpoints in your application, such as the login form, 2FA code submission, and new user registration should reject attempts coming from a rented cloud server.
Subscribe to stay up to date on new posts.