Android 7: Intercepting App Traffic

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:

  1. Install the proxy tool’s certificate authority (CA) certificate in Android’s trust store.
  2. Configure the wireless connection to proxy traffic through your chosen proxy utility.
  3. 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 pre-existing Android application packages or APKs (Android Package Kit).

When attempting to submit a search query in the official Wikipedia Android app while proxying traffic, the connection fails because the app doesn’t trust user installed CAs.

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:

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>

Next, modify AndroidManifest.xml by adding the following attribute to the application tag:

android:networkSecurityConfig="@xml/network_security_config"

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

The 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 validity flag.

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

Installation

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.

Attempting the same search as before now succeeds because our modified Wikipedia APK trusts user installed CAs.

Burp Suite successfully intercepting app traffic from the Wikipedia app.

Footnotes

  1. 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.
  2. 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.