Amr Shawky's Blog

SMS Pumping Fraud

Introduction

While working on PicPocket, we had a development server online that was connected to our Twilio account with $5 worth of balance, which was used for SMS authentication during user registration. While one of our developers was testing some things on the registration flow, they ended up using one of those ‘receive SMS for free’ websites you can easily find through a Google search.

This is when we discovered the wonderful world of SMS pumping fraud.

Generic website which allows you to receive SMS messages for free on a temporary phone number
Generic website which allows you to receive SMS messages for free on a temporary phone number

You might think that these websites (and there’s a lot of them) might exist to make money from advertising, since they probably have a lot of traffic, but what they’re actually doing is mining for websites and services that have/require SMS authentication. Chances are, if a service comes online that requires SMS, somebody, somewhere will eventually try to get around it by using a ‘free’ SMS service like the one above, and it promptly gets added to their attack database.

Very shortly after, that website/service will welcome an army of bots registering accounts with phone numbers in Argentina, Ecuador, Burkina Faso, Bulgaria and others.

The Fraud

Thanks to a lot of corruption, what happens is that SMS providers in these countries make deals with, or directly finance attackers to route SMS messages to phone numbers which they control, so they can charge the sender (Twilio in our case), who in turn charges us a very high fee per message.

In fact, this is apparently so profitable that Twitter reportedly lost $60M a year to this specific type of fraud/attack.

Now, Twilio gives you the impression that their ‘Fraud Guard’, at its most aggressive setting, is a set-and-forget type of situation, which very much isn’t the case. Our $5 was drained in seconds, and Twilio had let through all but one of the requests. However, we needed to understand how this works and how to fight it. So, we added a Cloudflare Turnstile to our registration flow, and topped-up our account with another $5.

For the first few hours, the bots seemed to be failing. Still making requests, but nothing coming through. I should add that the requests were coming from several hundred unique IP’s from all over the world.

Somebody must have checked in on them, because suddenly the account was drained again. The bots were providing valid, Cloudflare Turnstile tokens, and after a quick online search:

Price list of a popular CAPTCHA solving service
Price list of a popular CAPTCHA solving service

There is apparently an entire industry which revolves around solving CAPTCHA’s at scale, and at a very cheap price. You make an API request with the page you want to solve, and either a machine or a poor worker on the other side solves it and returns the token within seconds.

The Fight

Twilio’s support will tell you that the best way to fight against this is to block all numbers that aren’t in countries you expect business from. However, if you do business in at least one country that has a corrupt SMS provider, you aren’t safe. In reality, there isn’t a solution to this problem, and the only thing you can do is to make it so unprofitable that they stop bothering to try.

The first thing we implemented was a rate-limited registration intent, so that each user (per solved Turnstile), could only attempt to register two numbers (in case a legitimate user mistyped their number the first time). Next, the IP address would be logged and rate-limited as well - if that IP had successfully completed a registration after the intent (SMS fraud doesn’t ever actually verify the numbers), then that IP is rewarded with an additional registration intent, a failure triggers a rate-limit, and a total of 3 intents can exist simultaneously per IP that are in neither state.

This somewhat solves the problem of multiple users behind a NAT trying to register accounts simultaneously. We don’t actually have enough users for this to be an issue, but it was a fun engineering exercise to implement.

We did however, limit web-based registrations to first-world countries. Since the iOS app is by far much more popular than the web app, we figured we could keep registration open to riskier countries on iOS by using Apple’s App Attest service. This at least ensures that requests are from genuine Apple devices, coupled with a rate limit per-device of 3 accounts, this should make it sufficiently more expensive to attempt to run a phone farm, that it dissuades from future attacks.

The attacks persisted and failed for a few days after that, then suddenly disappeared. We’ve been live for several months, and haven’t see this type of attack since.