While routinely working on the security of one e-commerce website, I encountered an unusual type of brute-force attack that was fairly hard to mitigate. It was based on a delicately simple technique that made it stand out from the crowd.
As you know, a classic brute-force boils down to guessing credentials. For instance, threat actors take known user accounts and pick passwords for them based on certain criteria—either by generating them on the fly, or using dictionaries. This is the basic way to hack an account.
In my scenario, though, the perpetrators acted somewhat differently. They did not use VPN services or Tor. Instead, they used a large botnet consisting of several hundred infected computers and smartphones located in different parts of the world. The corporate security monitoring system perceived this traffic as if absolutely different devices with real people behind them were accessing the site. Such an attack can remain undetected for a really long time.
Aside from vast geographic distribution, the second peculiar trait of the attack was that the adversaries were trying to guess usernames rather than passwords. They were probably using dictionaries of popular passwords and stolen lists of usernames. First, they would try to match one known password with one username, then another, and another, and so on. This activity made it look like regular customers using the same ISP kept failing to log in with their valid passwords. At first sight, it did not appear hostile whatsoever. Moreover, the queries were relatively infrequent: one or two per minute.
The third distinctive feature of this attack was that the botnet exhibited very "human-like" behavior: the clients were processing JavaScript and accepting cookies.
This combo of factors helped the incursion fly below the radar for a fairly long time. When I did detect it, though, a nontrivial question popped up: how do we stop this? None of the bots had unique characteristics except a specific user-agent error. However, I decided not to block the attack based on that attribute because, in that case, I would be unable to monitor the perpetrator's activity any longer. I badly needed to identify some other anomalies.
As far as the IP addresses were concerned, nothing offbeat was happening. Blocking usernames that had many failed login attempts was not a good idea either because the frequency was very low, and it was the username, not the password, that the attackers were trying to guess. My last resort was to implement a captcha, but the company that hired us did not want it, thinking that a captcha would push a lot of clients away. Meanwhile, the crooks had managed to guess correct combinations for some accounts.
You must be wondering why on Earth someone might want to hack the accounts of an online store's customers. The thing is, they hold bonus points that can be exchanged for discounts. Someone probably wanted to do significant shopping, or to sell the bonus points online.
At the end of the day, I convinced the client to set up a captcha service offered by F5 Networks. It was supposed to appear after a predefined number of failed login attempts. But first, I needed to configure the login success criteria in the system. It turned out to be a bit harder than it appeared because in some cases, the resource returns the same response code for any attempt to access an account. I ended up choosing the instance of domain cookie delivery to the customer as the criterion of a successful login.
The latest version of F5 ASM (Application Security Manager) goes with a feature that responds to guessing attempts based on Device ID, a unique browser identifier. You add JS code to the page, and when a contaminated machine loads that page, it sends back its unique identifier. In our case, the Device ID was identical for every IP address. It actually meant that one browser was accessing the site from one IP address.
Consequently, I could define the following criterion: if more than five unsuccessful login attempts come from the same browser within 15 minutes, then a captcha should be displayed to that visitor. If it is a regular user, they will easily solve it and log in. I also added an appropriate exception for scenarios where a browser did not support JavaScript. I used a different criterion to keep the defenses high with that one: a captcha would appear if more than 20 unsuccessful login attempts came from the same IP address. Again, this should not be a problem for a normal user.
However, there are methods to get around captcha-based protection these days. For example, botnet operators outsource the job to China or India, where hard-working locals solve captchas for a small reward and send back the text values. Fortunately, there are countermeasures for that, too. If login attempts are unsuccessful even with captchas solved, you can block queries from a specific IP address or Device ID in case the number of failed logins exceeds a predefined value.
The last time the online store was targeted this way, I used captcha and it worked. The brute-force attack started fading away and stopped in its tracks after a while. It has been a year ever since—so far, so good.
Alex Vakulov is a cybersecurity researcher with over 20 years of experience in malware analysis and strong malware removal skills.
Join the Discussion (0)
Become a Member or Sign In to Post a Comment