How did I bypass a Custom Brute Force protection and why that solution is not a good idea?

May 25 · 8 min read

A bug hunter history …


In this article I am going to talk about how I bypass a brute force protection of the ACME corporation (a hypothetically name to maintain the non disclosure agreement) with a custom implementation in native code for token generation. Later I will mention why this is not the best solution and I will recommend a better one.


Brute force is one of the simple (also noisy) way to guess a password or something you want to know. Basically in a brute force attack an attacker try a tons of combination of passwords, strings, hex values, stack cookies, what you wants to find.

In this case the ACME company implemented a custom solution to “stop” brute force attacks based in tokens using native code (.so library ) in a Android application.

My client said:

No one can read the library to generate a token because is compiled and is not readable.

I say to myself :

That’s not true, some one can decompile the source code of the library and read the assembler code to understand what the library does.

So let’s get started..

About the app

The application is built for Android and it use its own token implementation to prevent brute force attacks.

Figure 1. Token validation process

In the Figure 1. We can see how the server handle the token, if the token is valid, the server return 200, but if the token is invalid, the server return 401.

This token is putted in the header and is validate per request.

Figure 2. Request example

In the Figure 2 we can see an example of request. In the X-ACME-Token header the application place the generated token. This token is used during the login process.

The research

Due to the kind of the test, I perform this research without access to the source code or any information about the application, this is what we call “black-box testing”.

I downloaded the APK of the application and opened it with JADX , after a lot of source code review I found the SEC class. This class define a static segment to load the library with native code. Also is important to note that the application doesn't obfuscate the code so was easy to JADX decompile the source code and show me in a readable format.

Figure 3. Sec class ACME example

Second ... At this point I know what is the name of the library so I extract the .so file using the ADB command from the Android emulated device.

adb pull /data/data/ .

In this link I was talk about Genymotion and how prepare an Android lab if you are interested.

This is the fun part. I need to do binary research if I want to understand what the file does because I don’t have the source code of the library.

Lets begin with the basic, I used xxd and file command to know more about the file.

Figure 4. Basic research in binary file

At this point I know what the file is, the ELF header and the output of the file command confirm that the file is a shared library. The next thing I always do is open the file using the string command.

Figure 5. Strings output command.

…. very interesting method I found here.


Lets open the library in IDA and examine that method.

Figure 6. Library opened with IDA

After a couple of hours reading assembler code to try understand what the library does I decide to move forward with another option (more simplistic and cheaper for my client) maybe if I find some vulnerability in the Login process I can generate my own token… But wait …. something comes to my mind and it was like a..

WOW!! … yes, it could works !!

Me after a revelation of God

FRIDA to the rescue

This is an awesome tool, according to the website is:

it’s a dynamic code instrumentation toolkit. It lets you inject snippets of JavaScript or your own library into native apps on Windows, macOS, GNU/Linux, iOS, Android, and QNX. Frida also provides you with some simple tools built on top of the Frida API. These can be used as-is, tweaked to your needs, or serve as examples of how to use the API.

What is my plan from now ?

In theory according to the definition, I could inject snippets of JavaScript into the native apps in this case Java. So I need to find in the code where the SEC class is used and try to understand how the token is generated (reading Java code not assembler) and maybe generate my own token.

My steps:

Give me six hours to chop down a tree and I will spend the first four sharpening the ax. Abraham Lincoln

Before diving into the code I spent a couple of hours understanding the FRIDA API. This is a very important step because it allows to me get a better idea of how FRIDA works and limitations it has.

After a while, I felt confident. I opened the APK file again, read some classes and found what I was looking for … YES !!

Figure 7. createClient example class

Again, the lack of code obfuscation makes me the work easy.

In the newBuilder.addHeader() instruction we can see how the X-ACME-Token Header is added and how Sec.access is called. According to the code three parameters is needed, the first is a Context object, the second is a unique ID, and the last one is an URL.

At this point we can use FRIDA..


FRIDA use python code to enable frida-tools, in this article I explain how is the installation of frida-tools. So I create a basic skeleton of code in python.

Figure 8. Python wrapper code

The next step is create a JavaScript snippet.

Figure 9. Example of JavaScript snippet

There are a lot of more code in Figure 9 to show, however I am interesting in to show you the function used to generate the token.

In this code we hook to Environment class and create a new instance of it, call the setter method and define a new value using random string. The next part is the getValidToken function.

Figure 10. getValidToken() method

In this code we overload the token function of com.acme.account.Sec. With this function overloaded we can create our acmeID and pass like an argument to the function which generates the token.

Figure 11. Token generation

Yeahh it worked … in Figure 11 you can see a list of token generated with FRIDA.

I configure Burpsuite Intruder with my list of tokens and then I tried to brute force a valid user of ACME…

Figure 12. Burpsuite intruder

Oh noooo!!!!! After 54 request the server return code 500 (which means server error) the status code 400 is for invalid password but after a series of request the server detect my brute force attack… Nooooo!!! :(

The exploit

I never give up, so, after resting, I came to the battle again and found this…

Figure 13. Context information

The Context … if I remember one of the parameter of the token.access function is a Context object, so what happens if I overload the token function again and define it with 3 strings parameters ?

Figure 14. Token method overload

I overload the function and configure my payload with my list of token.

…come on this has to work !!

Figure 15. Payload configuration

And DAWN men it worked…. Yeahhhh !!!

Figure 16. Brute force attack success using Intruder

After 303 request the server still returns 400 code indicating that the password is invalid… Yeahh !!!!

What happened here ?

With FRIDA, we overload the function of Token.access so at run-time when I executed my python script which inside use my JavaScript snippets and lunch an instance of in my emulated android device, the method definition is overloaded, so when I called the method getValidToken(), I am not calling the default method (token), I am calling the overloaded method passing 3 strings as arguments, so I don’t need to pass a context object. I have control of the three arguments and can pass random values to the token function.

I use this valid tokens to launch the attack…basically in the backend each request appears valid and the server doesn't detect my brute force attack.

Yeahhh !!!!

…But how we can fix this ?

The “solution”

I found a better way around token based implementation to prevent brute force attack using SafetyNET reCAPTCHA API. In Figure 17 is detailed the definition.

Figure 17. SafetyNET definition

This is a basic diagram of how SafetyNET reCAPTCHA does work. In Figure 18 you can see 3 actors (Android app, SafetyNET and Android Server). The Android app has a Site Key (something like a Public key) which is used to communicate with the SafetyNET server. Then SafetyNET server return the captcha challenge to the user and then send the token to the server for validation. The server has the secret key and validate the token against SafetyNET, then SafetyNET server validate this token using own analyst engine. The response is sent to the server and the server handle the token depending if it is valid or invalid.

Figure 18. SafetyNET basic architecture

What about ACME ?

At the end of this journey I made my report including a detailed explanation about the vulnerability and how to fix it.

Of course adding SafetyNET to an application in a production is not a trivial step, requires planning and in some case it need to validate against product team because adding a CAPTCHA affect the user experience using the application.

I didn’t exploit any vulnerability like Buffer Overflow, CSRF, SSRF or something similar, in this case the vulnerability is the token implementation by itself. Some times you need to spend time in order to understand the application to find this kind of bugs.

Please let know how if you implement SafetyNET reCAPTCHA API and how was the experience.

Bye bye …


Written by


Application Security Engineer and part-time bug hunter