Android Mobile Application Security Testing Write-Up

Introduction
Continuing from Part 1, where we explored fundamental weaknesses in the WaTF Bank application — including root detection bypass, excessive permissions, and exposed components — this part dives deeper into the analysis by examining more advanced vulnerabilities affecting data access, communication, and server-side logic.
In this part, we will cover:
- Content provider misconfigurations and SQL injection
- Account enumeration techniques
- Insecure SSL implementation
- Authorization flaws leading to unauthorized data access
- Business logic vulnerabilities in money transfers
- Server-side input validation issues
- Exposure of sensitive resources
Let’s continue with the analysis.
Content Provider Flaw
As seen previously, there is an exported content provider. To gather more information, the following command can be used with drozer:
run app.broadcast.info -a com.WaTF.WaTFBank -i

Again, using drozer the URIs of the app can be enumerated:
run scanner.provider.finduris -a com.WaTF.WaTFBank

The content provider here is database-backed, which means it works as an interface to a database, so by accessing it, database operations can be used e.g.: functions query, insert, update, and delete. This can be identified from the source code:

In this case, I added some test favorite accounts manually.
Knowing the URI, it can be used to query the database that contains the Favorite Accounts:
run app.provider.query content://com.WaTF.WaTFBank.FavoriteAccountProvider

An account can also be inserted or deleted. For example, inserting one:
run app.provider.insert content://com.WaTF.WaTFBank.FavoriteAccountProvider --string name Provider --string accountNo 000

Negative accountNo is also accepted as the value is not validated.
Content Provider SQL Injection
The content provider’s SQLite database is vulnerable injection in both selection and projection.
Projection operation defines which columns will be returned in a query, while Selection defines which rows.
To identify that, drozer offers a module that scans the provider for injection vulnerabilities. However, it can also be identified manually by trying to make a query that will cause an error:
run app.provider.query content://com.WaTF.WaTFBank.FavoriteAccountProvider --selection "'"
The query using a single quote successfully caused an error, confirming the vulnerability (same happens with projection query too).

The error gives information about what database is used (SQLite), the query running in the background.
Now it is possible to extract the database schema by manipulating the query. More specifically, the query that returns database schema will be crafted using the projection operation.
run app.provider.query content://com.WaTF.WaTFBank.FavoriteAccountProvider --projection "* FROM SQLITE_MASTER WHERE type='table';--"

The query executed was the following:
SELECT * FROM SQLITE_MASTER WHERE type='table'; -- FROM favorite_accounts
To explain it a bit, in practice, the “FROM favorite_accounts” part is commented out with the “ — ”, so it is not executed at all, resulting in a query that selects all the database tables.
Account Enumeration
Accounts for testing are already provided in the project as I mentioned previously, however it is important to show how it would be possible to discover accounts based on information given by the app from failed login attempts.
Using Burp Suite’s Interception Proxy, I will inspect the server’s responses to login attempts.
This is done by using Action -> Do intercept -> Response to this request in BurpSuite when intercepting the request that sends the credentials.
These response messages appear on the app as Toast messages as well.

A toast provides simple feedback about an operation in a small popup.
After trying to log in with the invalid username “example”, the response of the server was “Invalid Username”.



The next thing I tried, was using a valid username, but with wrong password. The server’s response was “Invalid Password”, this information ensures us that the username was valid, and only the password was wrong.


Knowing that, BurpSuite’s Intruder can be used to perform an account enumeration.
First, the captured login request is sent to Burp Suite’s Intruder and the username field is highlighted.

Then, we can supply different names or a wordlist containing them to find the existence of users in the Intruder’s payload options.

After conducting the attack, the responses that have the message “Invalid Password”, reveal that the username supplied exists. Then when valid usernames are found, their passwords can be brute forced the same way, until a successful login.

In this example, it is verified that a user called emma exists.
Insecure SSL Verification
In the OkHttpHelper class the following code can be found:

It can be identified that no SSL verification is performed, in fact the SSL certificate verification is disabled by trusting all certificates without performing any validation checks. This leads to insecure communication between the two endpoints.
Specifically, the code creates an SSLSocketFactory that trusts all certificates using the empty TrustManager implementation that accepts all certificates. Also, the HostnameVerifier is set to always return true (hostname validation is disabled), this means that any certificate with a valid chain of trust will be accepted, even if it's not issued for the domain being accessed.
If SSL pinning was implemented, tools like Frida, Objection, Android-SSL-TrustKiller etc., would help disabling it.
Accessing Another User’s Information
Let’s login as a legitimate user (from the ones that are provided). When selecting Account Summary, the intercepted request shows what is sent to the backend server, a “token” and the “account number”. The same applies for Transaction History too.



In the Transaction History other account numbers can be seen. That way just by modifying the accountNo in the request any user can see the Account Summary or Transaction History of other accounts.
Being logged in as the user “Jacob — 4444444444” here when selecting Account Summary and Transaction History, I intercept the request and change the accountNo to “2222222222”. This results in showing another user’s information (William’s).

Exploiting Money Transfer
Money transfer can also be exploited the same way. In this example I make a money transfer from Jacob’s account to himself. Having seen the balance of William’s account I use the same amount.

The next step is to modify “accountNo” value to William’s and forward the request, which results in emptying his account.

Logging in without Username or Password
By inspecting the server’s response in a successful login, it can be observed that message, accountNo and token are returned.

All that is needed to know here is the “accountNo” of another account. In this example I attempt to login with user William, intercept the response and modify the number to “3333333333”. This results in accessing Emma’s account.

By observing the token generation pattern after some successful logins, it can also be inferred that it increments by one. So, it is possible to login in any account just by crafting the response accordingly to the corresponding account number and a token number higher than the last used. Even if the login attempt was unsuccessful.
For example pasting the following text in an intercepted login response results in a successful login to Emma’s account.

In this case, the pattern is too obvious. However, if you want to analyze token randomness a useful tool is Burp Suite’s sequencer.
Server-Side Input Validation
When transferring money to another account it is not possible to add a negative number in the field. However, it is possible to intercept the request and change the value of the money to negative number.
Here I am logged in as michael with the balance shown.

Then I attempt to make the following transfer.

Next I intercept the transfer request and change “amount” from 1000 to -1000.

This results to a successful transfer. This transfer however takes the money from the account “2222222222” and deposits them to Michael’s.

Exposed Resource
Generally speaking, another useful resource to inspect is the “strings.xml” of the package, because sometimes useful information can be found there.
This file is used to store user-visible strings such as UI labels, menu items, and messages. It allows for easy localization and translation of the app’s text strings. By separating the strings from the code, it enables developers to manage and modify the text without touching the code, which makes it easier to make changes and keep the code clean.
In this case the following values are found in the file (using jadx):

These are used for the requests to the server. All of them, were previously seen in the intercepted requests and refer to the transactions that are offered by the app. However, there is one extra url, “/UsersLoginLog”, that is not used by the app in any way.
To access it and see the contents, a browser can be simply used (or any tool that could make a GET request to the server). The request must be https.

So, the accessed resource gives a Login Log Table, that shows the logins of the users’ and containing Usernames, Account Numbers and DateTime.
Conclusion
In this part, we explored a range of vulnerabilities affecting data access, communication, and server-side logic, including content provider misconfigurations, SQL injection, account enumeration, and insecure SSL implementation.
In the next part, we will shift our focus to client-side weaknesses, including insecure data storage, sensitive information leakage, and techniques for bypassing local security controls.
Thanks for reading, see you in Part 3!😊
WaTF Bank Walkthrough (Part 2): Exploiting Android App Security Flaws was originally published in InfoSec Write-ups on Medium, where people are continuing the conversation by highlighting and responding to this story.
SOCIAL SHARE CARD GENERATOR