Android reverse engineering

Hello everybody. In this tutorial we’re going to reverse engineer a vulnerable android app, find all vulnerabilities and create a report. 

Tools

We will use the following tools:

I won’t cover installation of all of the tools, only tricky ones.

Creating a virtual device

We should create an android virtual device without google play and google services in order to be able to get access to all file system folders of the device.

Run android studio (v2020.3.1 in my case) and open AVD manager. Click on Create Virtual Device, then select a device without Google Play, for example Nexus S:

Hit Next. Now select x86 images tab and select android version without Google APIs:

Hit Next. Set AVD Name, in my case it is gonna be Rooted and hit Finish.

Installing drozer

Drozer consists of 2 parts: console app and android app. To install the console app I had to run apt install drozer on my linux machine. 

Open https://labs.f-secure.com/tools/drozer/ and download the drozer agent apk file on your local computer. Run your newly created android emulator. Create an empty android app in android studio. In android studio open Device File Explorer and upload drozer agent apk to Download folder, in my case the path was /storage/emulated/0/Download:

In the android emulator open Files => Downloads and install drozer agent. Run the drozer agent apk. Now you should forward ports so that you could connect to the drozer app from your local machine. Run adb forward tcp:31415 tcp:31415. In the android drozer app click the ON button at the bottom of the screen. Now open the console on your local computer and run drozer console connect. You should be connected to the drozer app:

Installing insecurebankv2

In this section we will install a vulnerable android app from this repo: https://github.com/dineshshetty/Android-InsecureBankv2 . Run git clone https://github.com/dineshshetty/Android-InsecureBankv2. Now go to the AndroLabServer folder which has a server side code and install all of the requirements via pip install -r requirements.txt. Run python app.py to run the server. Server backend was written with python 2 so I actually had to run python2 app.py.

Now in the project directory find the file InsecureBankv2.apk. This is our vulnerable android app. Using device file explorer in android studio upload this file to the Download folder and install the app the same way you earlier installed the drozer app.

Now open the insecure bank app. In the preferences screen set the server ip to 10.0.2.2 (android proxies request from this ip to your local machine) and server port to 8888:

The insecure bank app has the following presaved user credentials:

  • dinesh/Dinesh@123$
  • jack/Jack@123$

Now try to login with the credentials above. You should be able to login and see server request in the console:

Setting up burp suite

In this section we will set up a burp suite to intercept requests from the android app to the server. Open burp suite, in my case I’m using Burp Suite Community Edition v2021.8.2, select Proxy tab, hit Intercept button to disable request interception, then select Options and add a new proxy for all interfaces on port 8081:

Now in the burp suite in the Proxy tab hit the Intercept tab. Then click on the Open browser button. Built-in burp browser should be opened. In the web address input type burp and hit enter. You should see the following screen:

Click on the CA Certificate button on the top right corner and download burp certificate. Rename the downloaded certificate from cacert.der to cacert.cer as android does not understand the der extension. Upload certificate to the device using device file explorer in android studio. Now in android emulator open Settings => Network & internet => Wi-Fi => Wi-Fi preferences => Advanced => Install certificates, select burp’s certificate from the Download folder => set any name and VPN and apps for credential use => OK. You should see your certificate in Settings => Security => Encryption & credentials => Trusted credentials => User tab:

Now get your local ip address. Run ifconfig:

In my case it is 192.168.0.105.

In android emulator open Settings => Network & internet => Wi-Fi => Cogs icon => Edit icon => Advanced options => set your ip address in proxy hostname and port 8081(the one from burp) and click Save:

Now you should be able to intercept requests from insecure bank app to the server. In burp enable the Intercept toggler in the Proxy tab. Open insecure bank app, in the preferences screen set server ip to your local ip and server port to 8888(the one where python server is running). Try to login. Request should be intercepted in burp:

API issues

In this section we will go through all API requests made by the insecure bank app to check for available issues. Login to the app using any of the presaved accounts and check all the screens and app features.

User enumeration

Try to login with a non existing user:

You will get the following server response:

Server tells us that the user does not exist. It means that we can try to brute force all available logins. Server should respond with a more general error like Invalid credentials.

Transfer issue

Login with a dinesh account and try to make a funds transfer. You will see the following request:

Now login with a jack account and try to make a funds transfer. You will see the following request:

So dinesh has account number 888888888 and jack has account number 999999999. If you login from jack account and set dinesh account number in From Account field in transfer screen then jack will transfer funds from dinesh account instead of his own:

Server response:

Password issue

Login with the dinesh account and try to update a password. You will see the following request:

If you intercept the request and change the username to jack then you will be able to update password of the jack account:

Server response:

Decompiling using dex2jar

Create a new folder wip, inside the wip folder create a new folder source and put the InsecureBankv2.apk file there. From a wip folder, using your own paths to dex2jar tool, run sh /home/vladimir/Public/program_files/dex2jar-2.0/d2j-dex2jar.sh -f source/InsecureBankv2.apk. You should see the InsecureBankv2-dex2jar.jar file appear in the wip folder.

Now open jadx-gui and select InsecureBankv2-dex2jar.jar. You should the source java code of the app:

Decompiling using apktool

Now run apktool d source/InsecureBankv2.apk. You should see the InsecureBankv2 folder with all app resource files and smali code:

Source code issues

Admin backdoor

Take a look at the com.android.insecurebankv2.DoLogin at the following code in postData() method:

You can see that if the username equals devadmin then the request goes to some other API method. Try to login with devadmin username and empty password. You should be able to successfully login.

Hidden content

Take a look at the com.android.insecurebankv2.LoginActivity at the following code in onCreate() method:

You can see that there is some button that is hidden when the resource string is_admin equals no. Open the decompiled InsecureBankv2 folder, the open res/values/strings.xml file. Find the is_admin string and change it to yes. Now build the app via apktool b InsecureBankv2 and sign it via the sign tool, in my case the command is java -jar /home/vladimir/Public/program_files/sign-1.0.jar InsecureBankv2/dist/InsecureBankv2.apk. You should see a new signed apk InsecureBankv2.s.apk in the InsecureBankv2/dist folder. Install this signed apk via adb install InsecureBankv2/dist/InsecureBankv2.s.apk. Open the app, you should see that hidden button Create User is visible now:

Modifying smali code

Basically it is not an issue, I will just show that you can modify smali code to edit app’s source code. When you login you see a screen with a label Device not rooted:

Let’s modify the source code so that the label is Rooted device. Take a look at the com.android.insecurebankv2.PostLogin class at the following method:

You can see in the 1st condition that if Superuser.apk exists then the label is set to the Rooted device. Open smali code of the above class in InsecureBankv2/smali/com/android/insecurebankv2/PostLogin.smali and find the showRootStatus() method:

You can see that the v2 register holds the result of the check that the file Superuser.apk exists. Then if the v2 register is not empty then proceed to condition cond_0. We don’t have the file Superuser.apk anywhere so the v2 register will always hold an empty result. All we have to do is modify the condition from “if file Superuser.apk exists”(if-nez v2, :cond_0) to “if the Superuser.apk file is empty”(if-eqz v2, :cond_0). So the modified code is:

Now build the app using the apk tool and sign it(as in the previous step). Install the app and open it. You should see the label Rooted device:

Insecure cryptography

Take a look at the com.android.insecurebankv2.DoLogin class. On user login the credentials are saved via the saveCreds() method:

You can see that login and password are encrypted via the CryptoClass and stored to shared preferences. If you take a look at the com.android.insecurebankv2.CryptoClass you can see that the private key is hard coded directly in the source code. You can get this private key and decrypt login and password as shared preferences are accessible by other apps.

Storage

It is always a good idea to check the data folder of the target app:

Database

Download mydb SQLite db file to your local machine and open via any database editor. I’m using Valentina Studio. Sadly there is a single table names but sometimes you may find a useful information:

Shared preferences

There are also 2 xml files of the shared preferences. 

The 1st one mySharedPreferences.xml is for storing server connection settings:

The 2nd one com.android.insecurebankv2_preferences.xml stores encrypted login and password:

But we have already discussed that those credentials can be decrypted as private key is hardcoded in the source code.

Log

You can also check the adb logcat output for some information disclosure. On user login you can see the following line in the adb logcat:

2021-08-31 23:34:36.343 7504-7547/com.android.insecurebankv2 D/Successful Login:: , account=dinesh:Dinesh@123$

Login and password are logged as plain text. Some other apps may read the adb output logs and find out your login and password.

Drozer

General app info

First of all let’s get some more information about the app. Run the drozer console app via drozer console connect(don’t forget that drozer android client should be up and running on your emulator with forwarded ports as we already discussed in the Installing drozer section).

Run run app.package.info -a com.android.insecurebankv2 to get some basic info about the app:

Now run run app.package.attacksurface com.android.insecurebankv2 to get a list of exported activities, services, broadcast receivers and content providers:

Activities

To get a list of all activities run run app.activity.info -a com.android.insecurebankv2:

You can see that we can open PostLogin activity bypassing the login screen. Run run app.activity.start --component com.android.insecurebankv2 com.android.insecurebankv2.PostLogin. Insecure bank app should be opened and you should see the PostLogin screen. Notice that at the time of executing the command the android drozer client must be opened in the foreground. 

Broadcast receivers

To get a list of exported broadcast receivers run run app.broadcast.info -a com.android.insecurebankv2 -i:

Now check the source code of com.android.insecurebankv2.MyBroadcastReceiver:

You can see that it receives 2 strings: phonenumber and newpass. Then it sends a local sms message that the user password was updated. Any other app can call this broadcast receiver and trick the user to open an external url or whatever.

Run run app.broadcast.send --action theBroadcast --extra string phonenumber +123456 --extra string newpass YOUR_NEW_PASSWORD to send a local reset message sms. You should see a new sms message:

Content providers

To get a list of exported URIs run run app.provider.finduri com.android.insecurebankv2:

To get a list of vulnerable URIs for SQL injection run run scanner.provider.injection -a com.android.insecurebankv2:

You can see that we can inject SQL code in the projection section. Run run app.provider.query content://com.android.insecurebankv2.TrackUserContentProvider/trackerusers --projection "* FROM sqlite_master; --" to get a list of all available table names:

Services

Insecure bank app does not export any services but you can find a great “drozer services cheat sheet” here: https://book.hacktricks.xyz/mobile-apps-pentesting/android-app-pentesting/drozer-tutorial#services

CVSS

It is always a good practise to set a CVSS(Common Vulnerability Scoring System) score to any issue that you’ve found. You can open a CVSS calculator at https://www.first.org/cvss/calculator/3.0 and calculate a score.

Let’s take a vulnerable exported broadcast receiver where any app can send an action and the user will see an sms message “your password has been updated” although real password change is not performed.

  • – Attack Vector (AV): local (malicious app should be locally installed on user device)
  • – Attack Complexity (AC): Low (it is very simple send a malicious android intent)
  • – Privileges Required (PR): None
  • – User Interaction (UI): Required (user must open a malicious app)
  • – Scope (S): Changed (sms message can contain a link to some other service)
  • – Confidentiality (C):  Low (password is not really updated)
  • – Integrity (I): None (password is not really updated)
  • – Availability (A): Low (malicious app can spam sms messages)

So we get a medium score: 5.0

Report

When all assessments are done it is time to write a report with all the issues and remediations. You can see an example report here: https://tcm-sec.com/wp-content/uploads/2021/04/TCMS-Demo-Corp-Security-Assessment-Findings-Report.pdf

Summary

This summary is just a shorthand of all the steps and commands:

  1. 1. Create an android virtual device without Google Play and Google services
  2. 2. Setup burp
    – enable proxy in burp
    – in android device setup proxy in wifi settings
    – upload and install CA burp suite certificate on android device (open internal burp’s web browser and open burp address)
    – certificate should be visible in Settings => Trusted Credentials
  3. 3. Using burp suite analyze app’s server requests and responses to find potential flaws
  4. 4. Decompile apk using dex2jar and check decompiled java sources
    sh /home/vladimir/Public/program_files/dex2jar-2.0/d2j-dex2jar.sh -f source/source.com.apk => decompile via dex2jar
  5. 5. Decompile apk using apktool and check resources (AndroidManifest.xml, xml resources, other files if available)
    apktool d yourapp.apk => decompile using apktool
  6. 6. Check app storage: /data/data/com.android.yourapp folder, xml files of shared preferences, sqlite db, logcat output
  7. 7. Setup drozer
    – install drozer client app on android device
    adb forward tcp:31415 tcp:31415 => forward drozer ports
    drozer console connect => connect to drozer console
  8. 8. Drozer (general app info)
    run app.package.info -a com.android.yourapp => get general app info
    run app.package.attacksurface com.android.yourapp => get general attack surface
  9. 9. Drozer (activities)
    run app.activity.info -a com.android.yourapp => get list of activities
    run app.activity.start --component com.android.yourapp com.android.yourapp.SecureActivity => run activity
  10. 10. Drozer (broadcast receivers)
    run app.broadcast.info -a com.android.yourapp -i => get info about broadcast receivers
    run app.broadcast.send --action ACTION_NAME --extra string name value --extra string name2 value2 => send intent with params to broadcast receiver
  11. 11. Drozer (content providers)
    run app.provider.finduri com.android.yourapp => get a list of content providers uris
    run scanner.provider.injection -a com.android.yourapp => get a list of vulnerable uris
    run app.provider.query content://com.android.yourapp/users --projection "* FROM sqlite_master; --" => run SQL injection to list all available table names
  12. 12. Drozer (services)
    https://book.hacktricks.xyz/mobile-apps-pentesting/android-app-pentesting/drozer-tutorial#services
  13. 13. Report
    – CVSS score
    – High level description with issue and video with potentially great impact
    – Step by step guide with screenshots
    – Explanation how to remediate the issue

How to reinstall a modified app:

  1. 1. apktool d yourapp.apk
  2. 2. modify smali
  3. 3. apktool b yourapp --use-aapt2 (or omit “–use-aapt2”)
  4. 4. java -jar /home/vladimir/Public/program_files/sign-1.0.jar yourapp/dist/yourapp.apk
  5. 5. adb install yourapp/dist/yourapp.s.apk

Leave a Reply

Your email address will not be published. Required fields are marked *