How did I bypass a Custom Brute Force protection and why that solution is not a good idea?
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.
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.
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.
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.
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/com.acme.app/lib/libacme-lib.so .
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.
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.
…. very interesting method I found here.
Lets open the library in IDA and examine that method.
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 !!
FRIDA to the rescue
This is an awesome tool, according to the website is:
What is my plan from now ?
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 !!
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.
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.
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.
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…
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!!! :(
I never give up, so, after resting, I came to the battle again and found this…
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 ?
I overload the function and configure my payload with my list of token.
…come on this has to work !!
And DAWN men it worked…. Yeahhhh !!!
After 303 request the server still returns 400 code indicating that the password is invalid… Yeahh !!!!
What happened here ?
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.
…But how we can fix this ?
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.
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.
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 …