Android Application’s Client Side Encryption Bypass Leads to Account Takeover
During android application penetration testing, I found an interesting scenario where the android application built on top of React Native and source code was obfuscated. During the login process, the application asks for userid and token, the token is of 4 digits. The token value is encrypted at client end and there is no brute-force protection implemented at server side.
The challenge was to identify the encryption mechanism used for token encryption.
During the android application penetration testing, to identify the client-side encryption mechanism, I have used various tools like apktool, dex2jar, jd-gui to understand the encryption process.
As the application built on top of react native which results to single source file while reversing the application. It’s too hard to identify the logic by simply reversing the APK and then analyze the source code that we usually do for any java based android application as the source-code is not usually obfuscated.
During the login process, I observed that when we provide userid and token (4 digit) in the application, the application sent only “/user/authenticate” HTTP request which contained encrypted token information and userId.
Based on that I drew my conclusion that the encryption process might be at the client-end
So i went ahead and extracted the APK file from android device and used apktool to decompile/reverse engineer extracted APK. Following which I searched for “/user/authentication” request in the source code and found it in “index.android.bundle” file.
After detailed analysis of the “index.android.bundle” file, I discovered that the application built on top of “React Native” framework and “index.android.bundle” is the only source file which is responsible for all the API calls made from the android application.
Then i have followed this blog and found that, the following command is used to display the react-native framework specific logs in logcat console,
Command: adb logcat *:S ReactNative:V ReactNativeJS:V
To inject log statement in android application, Generally, we used smali code. But this application build on top of react native framework, Based on the blog, the following command is used to inject the log statement in the android application.
Now we are able to modify react native based android application. In order to make this modification additional work is required. In my case any modification in “index.android.bundle” requires the following steps:
- Modify the source file
- Compile the source using apktool to generate the APK
- Sign the generated APK file (Note: As android device not allowed to install unsigned APK files)
- Uninstall the existing Android app from the device
- Reinstall the newly generated singed APK file
For such sequential steps, I have used “android application analyzer” tool, where the “Reinstall” feature allow us to do all the above steps while single button click
It’s too hard to identify the function which was responsible for token encryption process. So i have used “trial and error” approach and after performing more than 35+ attempt and hook logging statement each time to identify the function which might be called during login process as the source code is obfuscated.
Finally, I found that the “pinEntrySucceeded” function was called when token value passed from the Android Application, and “pinEntrySucceeded” function has 4 arguments and we are interested in “C” argument, because that is responsible to generate the encrypted token value passed in “/user/authenticate” HTTP Request.
Then i have tried to back reference the “pinEntrySucceeded” function’s parameter “C” and identified that “C” parameter is nothing but the call to “B(n,t)”.
Finally i found the function definition of function “B(t,n)” which contains for loop to perform some operation on the parameter value “t” and “n” and returns the parameter “u” which is nothing but the encrypted token value passed in “/user/authenticate” HTTP request.
B(t, n) => where “n” is userId and “t” is the plaintext token value
As the token value if the 4 digit number, so the possible value for this is “0000” to “9999”. For POC i have used token value from “2500” to “2800”.
I went ahead and modified the function and put another “for loop” (Brute-force for loop) on top of actual “for loop” (token encryption for loop).
So instead of taking “t” parameter passed from the “pinEntrySucceeded” function, it will brute-force the token using for loop variable “lol” and for every “lol” variable it will generate the “token” value and inject the log statement which will print in logcat when the user performed signin process.
So we have run the logcat to capture the react native specific logs, so when the user performs login process and clicks on login button the application logs all the token values generated based on PIN (2500 to 2800) and stores all the data in “output.txt” as shown in the figure:
In order to perform our final attack, it is required to extract only tokens from the above file:
I captured invalid login attempt requests and passed this request to intruder:
Load the tokens file into Burp intruder:
The attack succeeded and I was able to identify the valid encryption token as the server sent response with “200 OK” for a valid encryption token as shown below:
Result: As a result based on the knowledge of “userId” parameter, I was able to login to any user account using the brute-force approach by reverse engineering the app to understand the logic of encrypted pin generation as shown above.
- Whenever you see the encrypted or cryptographic value in android application API request, Always check for client side encryptions
- Always play with trial and error and never give up. Personally to be able to do this attack it took me 2 days to finally crack it.