A standard aspect of any mobile application security (MAS) assessment is intercepting and analyzing network traffic generated by the application under test. For the majority of applications, this traffic is HTTP or HTTPS so tools like Burp Suite, Zed Attack Proxy (ZAP), or mitmproxy are invaluable for identifying vulnerabilities and security issues related to the app’s interaction with web services. Obviously, in order to intercept HTTPS traffic in cleartext, it is necessary to perform a man-in-the-middle attack. In versions of Android prior to Nougat (7.0), this was a straightforward affair:
- Install the proxy tool’s certificate authority (CA) certificate in Android’s trust store.
- Configure the wireless connection to proxy traffic through your chosen proxy utility.
- Go about your application assessment.
However, starting with Nougat, Google introduced an array of new security measures. As a result, apps no longer trust user installed certificate authorities and thus refuse to connect via intercepting proxy tools. There are also no configuration options to modify this behavior either per app or system wide. If you happen to be the developer of the app you are testing, there is extensive documentation on how to modify this behavior in your own app using a file named
network_security_config.xml. But, these instructions require the ability to compile the application from source and, as a consulting firm, we usually don’t have that luxury. So, we need to modify preexisting Android application packages or APKs (Android Package Kit).
Modifying Application APKs
For the purposes of demonstration, let’s modify the official Wikipedia application. The first step is obtaining an official APK. Depending on the specific engagement, the client may give us an unreleased version of the application, but often times, we evaluate an application that has already been published in the Play Store. There are a couple options for getting an official APK:
- Download the APK from a mirror such as APKMirror or APKPure, or
- Install the app on a device via the Play Store and use the Android Debugging Bridge to pull the APK off the device:
adb pull /data/app/org.wikipedia-1/base.apk wikipedia.apk
The second positional parameter is the location of the APK on the device while the third is the location to transfer the APK to on your local filesystem.
Extracting an Android Application Package
From here, we need to unpack the APK in order to modify it. An APK is nothing more than a ZIP file1 containing an app’s compiled object code2 and any additional resources (e.g., graphics or textures) it needs to run, but we cannot simply unzip an APK as the compilation process has translated all the files within, even XML files, into a binary format. To properly uncompress and then, later, recompress the app, we need to use
apktool decode wikipedia.apk
This will create a folder with the same name as the APK but without the extension:
wikipedia/ ├── AndroidManifest.xml ├── apktool.yml ├── assets/ ├── lib/ ├── original/ ├── res/ ├── smali/ └── unknown/
Extending an Application’s Trust
Android apps can be configured to trust user installed CAs using the
network_security_config.xml file which goes in the
res/xml/ directory of the extracted APK. It should contain the following:
<?xml version="1.0"?> <network-security-config> <base-config> <trust-anchors> <!-- Trust preinstalled CAs --> <certificates src="system"/> <!-- Additionally trust user added CAs --> <certificates src="user"/> </trust-anchors> </base-config> </network-security-config>
AndroidManifest.xml by adding the following attribute to the
Update (October 2018): If you extract the APK and find the app already has a
network_security_config.xml file, pay careful attention to its contents. There are an assortment of ways the developer can use this file to configure the final application package. It is possible to use this file to only configure debug builds to trust user installed certificate authorities while release builds published via the Play Store will only trust CAs who’s certificates are packaged with Android itself. If the preexisting file uses the
debug-overrides tag instead of
base-config, you will need to modify
network_security_config.xml and continue rebuilding the application package.
Rebuilding an Application Package
Now we can recompress the application into an APK using
apktool. From within the folder where we previously extracted the official APK:
apktool build -o wikipedia_unsafe.apk
This creates an unsigned and unaligned1 APK which Android will refuse to install even if you attempt to do so over the debugging bridge. (Note that I’ve labeled the resulting APK “unsafe” since it enables eavesdropping.) Fortunately, self-signed certificates meet the signing requirement for our purposes since we’re not trying to publish our modified APK. To sign the new, extra trusting APK, we first need to setup a keystore using Java’s
keytool utility provided as part of the Java Development Kit (JDK):
keytool -keystore wikipedia.jks -genkey -keyalg RSA -keysize 2048 -validity 30 -alias wikipedia
keystore flag specifies the filename of the keystore to create and we specify the RSA algorithm using the
keyalg flag because
keytool defaults to DSA otherwise. Since we have no need to retain the key pair after we’re done assessing the app, we specify a very short lifespan, 30 days, for the self-signed certificate using the
Preparing the APK for Installation
With our keystore in hand, we can now sign and align our modified APK. There are two different tools we can use to sign our APK;
jarsigner is provided as part of the JDK, and
apksigner is provided as part of the official Android SDK, specifically the build tools. Which tool you use dictates the order of the next couple of steps. To align our APK, we’ll need
zipalign which also comes with the Android SDK’s build tools.
If you use
jarsigner to sign the new APK, sign the APK and then align it. The ‘
wikipedia‘ at the end of the
jarsigner command is the alias we gave to the key pair when we created it, and the ‘
4‘ in the
zipalign command aligns the APK along 4 byte boundaries.
jarsigner -keystore wikipedia.jks wikipedia_unsafe.apk wikipedia zipalign -f -v 4 wikipedia_unsafe.apk wikipedia_unsafe-signed.apk
If you use
apksigner to sign the new APK, the order is reversed:
zipalign -f -v 4 wikipedia_unsafe.apk wikipedia_unsafe-signed.apk apksigner sign --ks wikipedia.jks wikipedia_unsafe-signed.apk
Finally, we can install our modified application via the Android debugging bridge:
adb install wikipedia_unsafe-signed.apk
If you obtained the official APK by installing the app on the device from the Play Store, be sure to uninstall it before you install the modified version, otherwise Android will refuse to install the modified version because the signing keys don’t match. From here, you configure Android the same as previous versions: ensure the CA is installed via the Android settings app, and the wireless connection is configured to proxy traffic.
- APKs are actually ZIP files which have been optimized to allow for easy and efficient access to different segments of the archive. APKs are optimized by aligning these segments along 4 byte boundaries to make them easy for various Android components to find without having to parse the entire file.
- In versions of Android prior to 5.0 (Lollipop), applications where compiled to Java bytecode and then run on the Dalvik virtual machine. However, Lollipop introduced the Android Run Time (ART) which requires applications be fully compiled to object code for the instruction sets supported by Android.
Originally authored by Travis S.