eWallets, or digital wallets are becoming evermore popular. Most Android eWallets are apps that allow a user to make electronic transactions, including purchasing items online or in-person. Some services even allow an individual’s bank account to be linked to the service. Naturally, breaking the security of such a system is not only interesting, but potentially, profitable for an attacker. In this post, I’ll be going over how, I discovered a payment tampering vulnerability in a popular Android eWallet (the vulnerability has been fixed).
In addition to purchasing goods, most digital wallets, allow users to transfer funds between one wallet and another. In order to do so, this particular application requires the user to provide a mobile number of the other party using the same service.
That’s useful; but what if an attacker could abuse the transfer of funds functionality to extract funds from a victim’s account without their permission, or worst still, extract an amount from a victim’s account where the amount is greater than the amount residing in the victim’s account? Not so useful!
This attack a Negative Amount Transfer, and involves a vulnerability wherein the digital wallet application does not properly validate the amount being transferred, and allows negative amounts to be transferred.
A while back, I was given the task of performing a penetration test on a popular eWallet Android application. The scope of the exercise was of 5 days, so there was plenty of time for me to sufficiently test the application and go after high-prized payment tampering vulnerabilities. In order to do so, I would have needed to test the SOAP or RESTful web service driving the Android application.
I started off using OWASP’s Top-10 list as my check-list. Sure enough, within two days I was able to find the usual high-severity vulnerabilities such as SQL injection and authentication bypasses, but while those bugs were bad, I was still concerned about payment tampering flaws.
I dedicated the third day to hunt down any logical flaws, with the hope of finding a payment tampering bug, however, my efforts were futile. HTTP request data was encrypted (beyond simple TLS), so I could not see what was going on, nor modify any HTTP requests.
Since the encryption issue would not get me very far, I thought I could see what happens if the payment is tampered with before it gets encrypted. To do that, I would need to perform runtime analysis and debugging on the Android application, which means that I had to decompile the Android application (.apk file) and extract the source code in order to find the function that was responsible for the encryption on the client-side.
Decompiling involved the following steps.
- Converting the
.apkfile to a
.zipfile by renaming its extension
- Unzipping the
- Converting the extracted the application’s
classes.dexfile into a
.jarfile using the
dex2jarutility. This step converts the Dalvik bytecode (
.dex) used by Android’s Dalvik VM into
.classfiles (contained within a
.jarfile) which can in-turn be used by our decompiler in the following step.
- Opening the converted
.jarfile in JD-GUI. JD-GUI is a graphical utility that displays Java source code of
.classfiles. It allows you to easily browse the reconstructed source code.
After reviewing the code for a while, I managed to find the function responsible for the aforementioned encryption. With the difficult part over, all I had to do was debug the application.
I created the following setup.
– Logs into the attacker account, checks balance ($650)
– Logs into the victim account, checks balance ($473)
– Mobile number – 7830XXXXX
It’s now time to use the Android Debug Bridge (
adb) and the Java Debugger (
jdb) to inspect the Android application during execution. To insect the function, I also set a break-point on the
security.encryption() function (discovered through the decompilation process) responsible for encrypting the contents of the HTTP request.
Once the breakpoint was hit for the transfer functionality, I tampered the value of the
str parameter to make that a negative amount, and allowed the function to proceed with its execution.
Once that happened, the application sent a request to the server with a negative amount in the request to transfer funds from the attacker account to the victim account. The web service was indeed vulnerable to a logical payment tampering vulnerability.