Android

Things to look @ during Android app review

  • basic services

  • content provider

  • broadcast receiver

  • webview

  • Intent filters

  • repacking a android app

  • ssl pinning

  • Android manifest

    • check permissions app needed

    • check if any component is debuggable cat manifest | grep debuggable

    • find exported components and , those are potential inputs to application

      • find "exported:true".

        content provider, broadcast receiver are example of exported

    • Unprotected activities

      • cat manifest | grep exported="true"

Emulator setup

  • install android studio

  • `/Users/$USER/Library/Android/sdk/emulator/emulator -list-avds` will list all the available devices (we can install more from android studio)

  • ` sudo /Users/$USER/Library/Android/sdk/emulator/emulator -writable-system -avd Nexus_6_API_25 -netdelay none -netspeed full -http-proxy 127.0.0.1:8081` to run AVD

[READ MORE https://developer.android.com/studio/run/emulator-commandline]

Install burp certificate to emulator

1. Download cacert.der file from burp
2. openssl x509 -inform DER -in cacert.der -out cacert.pem
3. filename=`openssl x509 -inform PEM -subject_hash_old -in cacert.pem | head -1`.0
4. mv cacert.pem $filename
5. adb root
6. adb remount
7. adb push $filename /system/etc/security/cacerts/
8. adb shell chmod 644 /system/etc/security/cacerts/$filename
9. adb shell reboot

validate by checking for portswigger cred in Settings -> Security -> Trusted Credentials.

Resetting Android device

$ cd /Users/username/.android/avd/<device>.avd/
$ rm userdata.img # this is block with user info.

Decompiling

  • use jadx

Start Point of application

In the AndroidManifest.xml

<activity android:name="com.employroll.www.employroll.login.Luncher" android:windowSoftInputMode="adjustResize">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
</activity>

Activity with intent-filter name android.intent.action.MAIN are the First one to launched. in this case Launcher.java file will be called when app is run.

Proxy Requests

Proxy requests : Android App -> My Computer -> Internet And Then we can use Burp in our computer to change/edit/repeat do whatever with requests.

In Computer

* Start burp * Proxy -> Options * Edit -> Allow All Interfaces and bind to port say 8080. * Ifconfig and get IP Addr(say 192.168.1.8)

In Android

* Connect to router(ABC) * Setting->Wifi->ABC Setting * Advanced Options -> proxy -> * IP = 192.168.1.8 * Port = 8080

Done

Files to investigate

Dynamic analysis

$ ls /data/data/[com.file]/
 app_textures
 app_webview
 cache
 databases
 lib -> /data/app/jakhar.aseem.diva-1/lib/x86
 shared_prefs

Here imp. files are * shared_prefs : contains shared stored files * databases : sqlite database info

Static analysis

* strings.xml * AndroidManifest.xml

adb commands

  1. list connected devices adb devices

  2. get shell adb shell

  3. install apk to device adb install file.apk

  4. transfer file from PC to android adb push /source /tmp/destination

  5. See logs adb logcat

  6. get root adb root

  7. remote adb


On mobile
$ adb push $NDK_ROOT/prebuilt/android-x86_64/gdbserver/gdbserver /data/local/tmp/
$ adb forward tcp:1234 tcp:1234
$ adb shell
$ /data/local/tmp/gdbsever :1234 --attach `pidof com.google.ctf.pwn.tridroid`

On Desktop
(gdb) target remote localhost:1234
(gdb) c

Sources & Sinks

Sources

  • registerReceiver

---- ANDROID CODE TO REGISTER -----
this.broadcastReceiver = new BroadcastReceiver() {

    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals("com.google.ctf.pwn.tridroid.SET_NAME")) {
            MainActivity.this.editText.setText(new String(Base64.getDecoder().decode(intent.getStringExtra("data")), StandardCharsets.UTF_8));
        } else if (intent.getAction().equals("com.google.ctf.pwn.tridroid.SET_FLAG")) {
            MainActivity.this.flag = new String(Base64.getDecoder().decode(intent.getStringExtra("data").trim()), StandardCharsets.UTF_8).trim();
        }
    }
};

IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.google.ctf.pwn.tridroid.SET_NAME");
intentFilter.addAction("com.google.ctf.pwn.tridroid.SET_FLAG");
registerReceiver(this.broadcastReceiver, intentFilter);

---- Invoking EVENT -----
$ adb shell
adb $ am broadcast -a com.google.ctf.pwn.tridoid.SET_NAME -e data "hello world"
  • Intents

Sinks

  1. webView.loadUrl

this.webView.getSettings().setJavaScriptEnabled(true); // means we can execute JS
this.webView.getSettings().setAllowFileAccess(true); // means we can access file system
this.webView.getSettings().setAllowFileAccessFromFileURLs(true); // means we can access file:// url
this.webView.setWebViewClient(new WebViewClient()); 
this.webView.setWebChromeClient(new WebChromeClient());
this.webView.addJavascriptInterface(this, "bridge"); // add external interface (x86)
this.webView.loadUrl("file:///android_asset/index.html"); // URL to load

frida

## Step 1

  • step 1 is to load frida server script to device and connect to it### ON Mobile* adb push /source /tmp/frida-server-x86

  • adb shell

  • cd /tmp

  • bash frida-server-x86 &

## ON Laptop

  • frida -U -f com.hackerone.thermostat --no-pause

## dynamic link custom scriptfile.js

setImmediate(function(){
    Java.perform(function() {
        var currentApplication = Java.use("android.app.ActivityThread").currentApplication();
        var context = currentApplication.getApplicationContext();        // Extra Code Goes Here
    });
});

> Usage :

$ frida -U -f com.employroll.www.employroll -l ./file.js --no-pause

## Hooking onto function

* package : jakhar.aseem.diva * class : InsecureDataStorage1Activity * Func to override : saveCredentials with 1 argument($init for consrtructor)

so Java.use('jakhar.aseem.diva.InsecureDataStorage1Activity');

file.js below

setImmediate(function(){
    Java.perform(function() {
        var currentApplication = Java.use("android.app.ActivityThread").currentApplication();
        var context = currentApplication.getApplicationContext();   
        var p1 = Java.use('jakhar.aseem.diva.InsecureDataStorage1Activity');
        p1.saveCredentials.implementation =function(x){
             console.log("Hook stop : "+JSON.stringify(Object.getOwnPropertyNames(this)));
             var ret_value = this.saveCredentials(x);
             return ret_value;
        };
    });
});

## Changing variable values

* package : jakhar.aseem.diva * class : InsecureDataStorage1Activity * varibale Name : gps_latitude_valfile.js

setImmediate(function(){
    Java.perform(function() {
        var currentApplication = Java.use("android.app.ActivityThread").currentApplication();
        var context = currentApplication.getApplicationContext();
        var p1 = Java.use('jakhar.aseem.diva.InsecureDataStorage1Activity');
        console.log("GPS Value : ",p1.gps_latitude_val.value) // changing value
        p1.gps_latitude_val.value = "14.231";
    });
});

Common bugs:

  • SQLi

  • IDOR

  • authentication issue

  • insecure uploads

  • broadcast reciever

  • content provider

    • insecure store of secure info/ secrets System API's should be used to store sensitive info. Keyschains in IOS and smartLock in android is correct way of storing sensitive info

  • Check for screenshot

    • when a app goes to background , OS takes screenshot to show in app switcher which is publicly availble. check if any private info can be leaked using this

  • Sensitive data leak

    • Look at local app data if anything useful

  • weak crypto / Hardcoded crypto

  • Folder structure

| AndroidManifest.xml | - resouces/ | /Layouts : check if there is admin layouts, debug layouts | /images : nothing here

  • Cross app scripting https://hackerone.com/reports/401793 loadUrl + evaluateJS

  • Intent-redirection https://hackerone.com/reports/951691 fix: check both activity class and package name of intent before redirecting

  • Intent Broadcasting broadcasting intent is IPC mechanism to communicate with other app. If there is some sensitive data send that can be intercepted by other apps, its a problem * chck jazzy wu Fix: if you know who this broadcast is for, use setClass, setComponent, setName to make sure it only goes to target

  • Path traversal durin file saving, and attacker can control path, we can override other files

    • zip file can have relative paths and unzipping this will again PT

  • OAuth response_type=token is bad. Use response_type=code

Last updated