Collection of notes regarding Android application analysis and testing.
Testing Guides and Frameworks
MobSF practically covers everything outlined in the Static Analysis section below, however it is good to understand what’s going on under the hood and how to manually verify the issues MobSF identifies.
APK File Format
APK stands for Android Package File and is saved in ZIP format:
# file googleplaystore.apk googleplaystore.apk: Zip archive data, at least v0.0 to extract
You can simply extract the file using the unzip command:
# unzip googleplaystore.apk Archive: googleplaystore.apk inflating: AndroidManifest.xml inflating: META-INF/services/com.google.protobuf.GeneratedExtensionRegistryLoader inflating: META-INF/services/kotlinx.coroutines.CoroutineExceptionHandler inflating: META-INF/services/kotlinx.coroutines.internal.MainDispatcherFactory extracting: android-support-multidex.version.txt extracting: assets/_kotlin inflating: assets/apploading/generic_category.json inflating: assets/dev_triggered_update_progress_animation.json extracting: assets/dexopt/baseline.prof extracting: assets/empty_asset_generated_by_bazel~ inflating: assets/gameloading/warmcold_stitched.json inflating: assets/gameloading/warmcold_stitched_v2.json inflating: assets/keys/dfe-response-auth/1 inflating: assets/keys/dfe-response-auth/meta ...
Running ls in the directory you’ll see the following:
# ls AndroidManifest.xml assets classes3.dex classes5.dex com lib org resources.arsc android-support-multidex.version.txt classes2.dex classes4.dex classes.dex googleplaystore.apk META-INF res stamp-cert-sha256
You’ll notice if you try to view some files that they’re not exactly plaintext, you’ll need to use an Android binary XML decoder, a tool like axmldec can decode individual files like so:
# axmldec -o output.xml AndroidManifest.xml # axmldec -o output.xml network_security_config.xml
This is a bit tedious and there are other alternatives we can use that take care of extraction and decoding.
apktool allows you to extract and decode all files within the APK with a single command, installing from debian-based systems:
# apt install apktool
You can then run the following to disassemble the APK:
# apktool d googleplaystore.apk Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true I: Using Apktool 2.5.0-dirty on googleplaystore.apk I: Loading resource table... I: Decoding AndroidManifest.xml with resources... I: Loading resource table from file: /root/.local/share/apktool/framework/1.apk I: Regular manifest package... I: Decoding file-resources... I: Decoding values */* XMLs... I: Baksmaling classes.dex... I: Baksmaling classes2.dex... I: Baksmaling classes3.dex... I: Baksmaling classes4.dex... I: Baksmaling classes5.dex... I: Copying assets and libs... I: Copying unknown files... I: Copying original files... I: Copying META-INF/services directory
APKs usually contain the following files and directories:
assets - directory with application assets.
res - directory with all resources that are not compiled into resources.arsc. These are all resources except the files in res/values. All XML resources are converted to binary XML, and all .png files are optimized (crunched) to save space and improve runtime performance when inflating these files.
lib - directory with compiled native libraries used by your app. Contains multiple directories — one for each supported CPU architecture (ABI).
META-INF - directory with APK metadata, such as its signature.
AndroidManifest.xml - application manifest in the binary XML file format. This contains application metadata e.g. its name, version, permissions, etc.
classes.dex - file with app code in the Dex file format. There can be additional .dex files (named classes2.dex, etc.) when the application uses multidex.
resources.arsc - file with precompiled resources, such as strings, colours, or styles.
Every app project must have an AndroidManifest.xml file (with precisely that name) at the root of the project source set. The manifest file describes essential information about your app to the Android build tools, the Android operating system, and Google Play.
From an attackers standpoint the main areas of the AndroidManifest.xml file we’re concerned with are outlined below (part copied and modified from hacktricks):
First of all, check if the application is debuggeable. A production APK shouldn’t be (or others will be able to connect to it). You can check if an application is debbugeable looking in the manifest for the attribute debuggable=”true” inside the tag
<application Example: <application theme="@2131296387" debuggable="true"
- Backup: The android:allowBackup attribute defines whether application data can be backed up and restored by a user who has enabled usb debugging. If backup flag is set to true, it allows an attacker to take the backup of the application data via adb even if the device is not rooted. Therefore applications that handle and store sensitive information such as card details, passwords etc. should have this setting explicitly set to false because by default it is set to true to prevent such risks
- NetworkSecurity: The application network security can be overwritten the defaults values with
android:networkSecurityConfig="@xml/network_security_config". A file with that name may be put in
res/xml. This file will configure important security settings like certificate pins or if it allows HTTP traffic. You can read here more information about all the things that can be configure, but check this example about how to configure HTTP traffic for some domains:
<domain-config cleartextTrafficPermitted="true"> <domain includeSubdomains="true">formation-software.co.uk </domain></domain-config>
- Permissions: security permissions that can be used to permit/deny access to specific components or features of this or other applications, some examples are included below:
Exported activities: activity that can be accessed by external components or apps. Can be dangerous - https://blog.mzfr.me/posts/2020-11-07-exported-activities/
- Content Providers: Content Providers are the way apps share structured data, such as relational databases. If an exported provider is being exposed, you could be able to access/modify interesting information.
- Check for FileProviders configurations inside the attribute
FileProvider: a type of Content Provider that will share files from a folder.
Exposed Services: services run in the background without a UI. They are used to perform long-running processes, even if the user starts using a different application. A service can be exported which allows other processes on the device to start the service. Depending on what the service is doing internally vulnerabilities could be exploited.
Broadcast Receivers: Broadcasts can be thought of a messaging system and broadcast receivers are the listeners. - https://book.hacktricks.xyz/mobile-apps-pentesting/android-app-pentesting#exploiting-broadcast-receivers
URL scheme: An application can declare an URL schema inside and activity so every time the Android device try to access an address using that schema the applications activity will be called -
<data android:scheme="myapp"/>. Read the code of the activity managing the schema and look for vulnerabilities managing the input of the user.
- minSdkVersion, targetSDKVersion, maxSdkVersion: They indicate the versions of Android the app will run on. It’s important to keep them in mind because from a security perspective, supporting old version will allow known vulnerable versions of android to run it.
This file isn’t always present within an APK, the following best surmises the
The Network Security Configuration feature lets apps customize their network security settings in a safe, declarative configuration file without modifying app code. These settings can be configured for specific domains and for a specific app. The key capabilities of this feature are as follows:
Custom trust anchors: Customize which Certificate Authorities (CA) are trusted for an app’s secure connections. For example, trusting particular self-signed certificates or restricting the set of public CAs that the app trusts.
Debug-only overrides: Safely debug secure connections in an app without added risk to the installed base.
Cleartext traffic opt-out: Protect apps from accidental usage of cleartext traffic.
Certificate pinning: Restrict an app’s secure connection to particular certificates.
The file is commonly located at
res/xml/network_security_config.xml and a demo file is shown below:
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <base-config cleartextTrafficPermitted="true"> <trust-anchors> <certificates src="system"/> <certificates src="user"/> </trust-anchors> </base-config> </network-security-config>
This folder contains the manifest information and other metadata. It’ll be located at META-INF/ or original/META-INF if Apktool was used to unpack the APK:
# ls -la total 624 drwxr-xr-x 3 root root 4096 Sep 17 05:12 . drwxr-xr-x 3 root root 4096 Sep 17 05:12 .. -rw-r--r-- 1 root root 1588 Sep 17 05:12 BNDLTOOL.RSA -rw-r--r-- 1 root root 309018 Sep 17 05:12 BNDLTOOL.SF -rw-r--r-- 1 root root 308914 Sep 17 05:12 MANIFEST.MF drwxr-xr-x 2 root root 4096 Sep 17 05:12 services
The purpose of these files are outlined below:
MANIFEST.MF: It contains various information used by the java run-time environment when loading the jar file, such as which is the main class to be run from the jar file, version of package, build number, creator of the package, security policies/permissions of java applets and java webstart packages, the list of file names in the jar along with their SHA1 digests, etc.
<>.SF: This contains the list of all files along with their SHA-1 digest.
<>.RSA: This contains the signed contents of the CERT.SF file along with the certificate chain of the public key used for signing the contents.
# head MANIFEST.MF Manifest-Version: 1.0 Created-By: singlejar Name: AndroidManifest.xml SHA-256-Digest: RqiPLwTD6yEkC1NBk+e9GLdlFznH3Cm0gKqwGxhkfE8= Name: META-INF/services/com.google.protobuf.GeneratedExtensionRegistry Loader SHA-256-Digest: uNuVf59jJrgvEBrRFV3nrehS+5W2m79z1P7FwTbHVhY=
# head BNDLTOOL.SF Signature-Version: 1.0 Created-By: 1.0 (Android) SHA-256-Digest-Manifest: 7YTmpO0rBcy63HeLRcXarbbw4fn60o2K2bcbcLmVqBc= X-Android-APK-Signed: 2, 3 Name: AndroidManifest.xml SHA-256-Digest: JYk1A0P3/ZEMyNlw3pZw8mF+HAC96pL2kpI05V6nZLw= Name: META-INF/services/com.google.protobuf.GeneratedExtensionRegistry Loader
Java Code Extraction
A DEX file is an executable file saved in a format that contains compiled code written for Android, Google’s Linux-based mobile phone platform. It is technically referred to as a “Dalvik Executable,” and can be interpreted by the Dalvik virtual machine.
Developer file written in Smali, the assembly language used by the Android Dalvik Virtual Machine; usually created by decompiling .DEX (Dalvik Executable) files, which are the executables included in Android apps (.APK files); usually used for low-level inspection of an Android app’s contents, or for hacking Android apps.
You’ll notice the presence of either
.smali files after either unzipping or using apktool on the APK. We can use those files to create a JAR file which we can then load into JD-GUI and browse the classes for the APK application:
# apt install dex2jar # apt install jd-gui # d2j-dex2jar -f googleplaystore.apk Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true dex2jar googleplaystore.apk -> ./googleplaystore-dex2jar.jar
This spits out
googleplaystore-dex2jar.jar which we can open in
jd-gui and browse the code:
It should be noted that you can then unzip the jar file and browse/grep the code base instead of using
jd-gui. Java code within APKs is often obfuscated and shrunk (up to 90% smaller) using ProGaurd, this is done to improve speed and makes it slightly harder to reverse engineer. DexGaurd is another product used to secure Android apps and SDKs.
Grepping for Juicy Data
APKs usually contain string resources that provide text strings for the application, these can sometimes contain API keys and other sensitive data. These are often stored in a file located at
res/values/strings.xml, but this isn’t always the case.
Recursively grepping for keywords is the easiest (manual) way to find sensitive information, an example is shown below:
# grep -iR "api\|api_\|key\|token\|password\|http:" // can add more patterns ... AndroidManifest.xml: <meta-data android:name="com.google.android.safetynet.API_KEY" android:value="AIzaSyAbjymMFVpKzKIQNuebMSBu2mdHlasX3Xk"/> AndroidManifest.xml: <action android:name="com.google.android.play.core.testerapi.BIND_TESTER_API_SERVICE"/> res/allstrings.xml: <string name="google_api_key">AIzaSyApxIsGO9Yw4rxdXiVm5zMpPPLJ53kz_fA</string> res/values/public.xml: <public type="string" name="google_api_key" id="0x7f1403c3" /> res/values/strings.xml: <string name="google_api_key">AIzaSyApxIsGO9Yw4rxdXiVm5zMpPPLJ53kz_fA</string>
Worth noting some API keys are public like the ones shown above.
Grepping for interesting files types is also recommended,
.sqlite in particular:
# ls -laR | egrep '\.db$|\.sqlite'
apkleaks is a tool you can also use to scan APK files for URIs, endpoints & secrets:
# pip3 install apkleaks # apkleaks -f googleplaystore.apk _ ____ _ ___ _ / \ | _ \| |/ / | ___ __ _| | _____ / _ \ | |_) | ' /| | / _ \/ _` | |/ / __| / ___ \| __/| . \| |__| __/ (_| | <\__ \ /_/ \_\_| |_|\_\_____\___|\__,_|_|\_\___/ v2.6.1 -- Scanning APK file for URIs, endpoints & secrets (c) 2020-2021, dwisiswant0 Can't find jadx binary. Do you want to download jadx? (Y/n) y ** Downloading jadx... ** Decompiling APK... Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true INFO - loading ... INFO - processing ... Killed ** Scanning against 'com.android.vending' [Artifactory_Password] - APA9E4sItnoWEER1vvlO0jYJsH0ACLunNSG3onDooVs [Generic_API_Key] - API_KEY" android:value="AIzaSyAbjymMFVpKzKIQNuebMSBu2mdHlasX3Xk" [Google_API_Key] - AIzaSyAbjymMFVpKzKIQNuebMSBu2mdHlasX3Xk - AIzaSyApxIsGO9Yw4rxdXiVm5zMpPPLJ53kz_fA [IP_Address] - 126.96.36.199 - 188.8.131.52 - 184.108.40.206 - 220.127.116.11 - 18.104.22.168 - 22.214.171.124 - 126.96.36.199 - 188.8.131.52 ...
apkurlgrep is another tool you can use to extract all URLs and paths from the target APK (can have some false positives):
# apkurlgrep -a googleplaystore.apk Result of URLs: https://play.google.com/store http://schemas.android.com/apk/res-auto http://schemas.android.com/aapt https://support.google.com/googleplay/troubleshooter/7287311?p=invalid_code#ts=7286412\ https://g.co/AndroidCertifiedDevice ... Result of URLs Paths: /store /redeem /wishlist /apps/test/ /apps /protect/home content://com.google.android.finsky.securityhub.provider/getText content://com.google.android.finsky.securityhub.provider/getIcon /apps/launch s/media/bestanden shrink/expand /proc/self/cmdline
Notes from the Bugcrowd talk linked above:
Insecure Connections (CWE-319)
Use of insecure network protocols - loading data over insecure networks such as HTTP allows attackers that control the network to replace, remove, and inject code
Data transmission over insecure protocols - sending sensitive data over insecure networks such as HTTP allows attackers that control the network to intercept, modify, and steal the data
Authentication over insecure protocols - sending login information over insecure networks such as HTTP allows attackers that control the network to intercept, modify, and steal the data
→ Review app’s network security config (Android P feature) to understand whether the app is allowed to use insecure network protocols
→ Grep the app’s code for “http:”, “ftp:”, “smtp:”, and URLs that indicate the use of insecure network protocols
→ Understand common entry points into the network such as the URL class or the WebView class
⇒ check whether there are code flaws that lead to insecure connections being made
Cryptography and Authentication
Embedded third-party secrets (CWE-798) - apps that embed third-party secrets such as twitter API or AWS auth tokens can trivially have these secrets extracted and abused by attackers
Embedded cryptography secrets (CWE-321) - apps that use embedded crypto secrets are susceptible to simple data decryption attacks
Leaking OAuth tokens - OAuth implicit Grant and Authz (without PKCE) flows expose tokens that can be used to create fraudulent requests
→ Compile a list of interesting public APIs and create regular expressions to find keys/secrets through grep
→ Compile a list of interesting public APIs and look for their package names in apps
→ Grep for “key”, “password”, “login”, “secret”, and such
Private File Access
Private data sharing (CWE-359) - applications may leak private data to other apps or attackers in obvious and subtle ways
Private data overwrite due to path traversal (CWE category 21) - applications that don’t sanitize attacker-provided directory paths may be susceptible to overwrite their internal files with attacker-provided files
Private data overwrite due to ZIP file traversal - applications that unzip archive files without sanitizing the target file paths of files inside the archives are susceptible to overwriting their internal files with attacker-provided files
→ Find all users of APIs in the
java.util.zip.* package or third-party zipping libraries
→ Understand whether user-provided ZIP files are being unzipped by the code
Unprotected App Parts
Unprotected activities (CWE-926) - exported activities can be started by other apps on the device which may break user workflow assumptions, including ways that break security boundaries
Unprotected services (CWE-926) - apps that export services allow malicious apps on the device to start those services
Typos in custom permissions - when used custom permissions don’t match declared custom permissions, Android defaults to silently failing to enforce the permission
**Intent redirection (CWE-925) **- apps that accept and launch arbitrary intents from external sources may allow malware to start internal components indirectly or access protected content:// URIS.
Implicit broadcasts (sending) (CWE-927) - applications that send broadcasts without specifying the broadcast target may have these broadcasts intercepted by malicious apps on the same device
Implicit broadcasts (receiving) (CWE-927) - applications that accept broadcasts without checking the sender may accept maliciously crafted broadcasts sent from malicious apps on the same device
→ Find calls to startActivity and verify that intent components are constructed from trusted data
→ Find calls Intent::getExtras where returned values are cast to intent and verify that they are properly checked before being used
⇒ it isn’t enough to check the target class name. malware can reuse your class names and force your app that owns the target component
- Incorrect URL verification (CWE-939) - apps that rely on URL parsing to verify that a given URL is pointing to a trusted server may be susceptible to many different ways to get URL parsing and verification wrong.
- Find every instance of URLs being used in an app
- Narrow it down to those that work on user-controlled input
- Narrow it down to those that are used to branch between different code paths
- could be any part of the URL, not just the host name
- Incorrect sandboxing of scripting language (CWE-266) - embedding a scripting language or interpreter in an app can lead to exposure of app internals if the security boundaries of the interpreter are not well understood.
- Look for indicators of scripting languages
- common interpreters such as Python inside the app
- look for Android and Java sandboxing libraries
- check whether these interpreters allows untrusted input
- Look for indicators of scripting languages
- Unprotected data on server (CWE-306) - an app connects to a remote web server, database, or API that does not sufficiently protect sensitive user data. Any hacker can access this data.
Android Debug Bridge (adb)
Android Debug Bridge (adb) is a versatile command-line tool that lets you communicate with a device. The adb command facilitates a variety of device actions, such as installing and debugging apps, and it provides access to a Unix shell that you can use to run a variety of commands on a device. It is a client-server program that includes three components:
A client, which sends commands. The client runs on your development machine. You can invoke a client from a command-line terminal by issuing an adb command.
A daemon (adbd), which runs commands on a device. The daemon runs as a background process on each device.
A server, which manages communication between the client and the daemon. The server runs as a background process on your development machine.
In order to communicate with an Android device via adb you need to enable debugging, this is all outlined in the referenced documentation linked above.
A fairly recent HackTheBox machine called Explore is all based on Android and gives you the opportunity to play with adb.
Mobile Security Framework
Install the relevant requirements outlined in the installation documentation and then run the relevant install script.
Once setup has finished you can navigate to
https://0.0.0.0:8000/ and upload the APK. Running the
googleplayapk.apk through spits out a nice report, it highlights the areas previous mentioned throughout this static analysis section. Be sure to manually verify findings as false positives can occur.
If you look at the terminal after uploading a file to MobSF, it provides updates on actions it’s taking against the APK:
[INFO] 17/Sep/2021 12:58:43 - APK Extracted [INFO] 17/Sep/2021 12:58:43 - Getting Hardcoded Certificates/Keystores [INFO] 17/Sep/2021 12:58:43 - Getting AndroidManifest.xml from APK [INFO] 17/Sep/2021 12:58:43 - Converting AXML to XML Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true [INFO] 17/Sep/2021 12:58:49 - Parsing AndroidManifest.xml Requested API level 30 is larger than maximum we have, returning API level 28 instead. [INFO] 17/Sep/2021 12:58:54 - Fetching icon path Requested API level 30 is larger than maximum we have, returning API level 28 instead. [INFO] 17/Sep/2021 12:58:57 - Extracting Manifest Data [INFO] 17/Sep/2021 12:58:57 - Fetching Details from Play Store: com.android.vending [INFO] 17/Sep/2021 12:59:01 - Manifest Analysis Started [INFO] 17/Sep/2021 12:59:01 - Binary Analysis Started
.AAB to .APK
An Android App Bundle is a publishing format that includes all your app’s compiled code and resources, and defers APK generation and signing to Google Play.
bundletool-all-**.jar from bundletool and then run:
java -jar bundletool.jar build-apks --bundle=<aab file> --output=app.apks
You can then use 7zip etc. to extract the files. If you get a bunch of files, look for the highest file size or master - this should be an .apk file type which can be imported into MobSF, Genymotion, NoxPlayer, etc.
Repacking and Signing
# apktool b /path/to/folder -o app.apk # keytool -genkey -v -keystore my-release-key.keystore -alias alias_name -keyalg RSA -keysize 2048 -validity 10000 # jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore my-release-key.keystore app.apk alias_name
MobSF does support dynamic analysis but I’ve never personally used it yet, device emulation via Genymotion or NoxPlayer is how i’ve performed dynamic analysis in the past.