Pulling Back the Veil with Nerdwell
Finding Sensitive Data in Android Apps
Information Protection in Android Apps
There are a lot of benefits to the Android ecosystem for mobile app development but some of those most relevant to bug bounty hunters are the information security protections that Android provides. Developers and hardware manufacturers leverage these platform-level capabilities to provide the security features that users have come to expect, without having to reinvent the wheel in the process. A few of the key Android platform security features are:
|Data At Rest||Data In Transit|
Common Developer Assumptions
While one advantage of leveraging the Android platform-level security features is that developers don’t have to dig into the nitty-gritty details of implementing these features, this can be a double-edged sword. As with many things in the security field, a lack of familiarity can quickly open the door to implementation mistakes and, subsequently, vulnerabilities.
At a high level, most vulnerabilities can be distilled down to:
- One or more assumptions are made; and
- Some set of conditions undermines the assumption(s), leading to a security impact.
So, as bug bounty hunters, our goal is to identify the assumptions being made by application and system creators and then craft conditions that undermine these assumptions to achieve a security impact. With that in mind, it’s helpful to start by considering how developers’ use of Android platform-level security features can lead to assumptions that we might be able to undermine. A few examples that we’ll look at today include:
- The attacker does not have access to application source code.
- The attacker cannot access “private” application data.
- SSL/TLS and certificate pinning prevent a would-be attacker from intercepting and evaluating backend API calls.
Invalidating Developer Assumptions
Let’s take a quick look at how we can invalidate some of these common developer assumptions.
The attacker does not have access to application source code.
- With freely-available tools (e.g. Jadx GUI), it’s a breeze to decompile APKs to human-readable Java (or Kotlin) source code.
The attacker cannot access “private” application data.
- We can set “debuggable=true” in the AndroidManifest.xml to access the /data/data/com.my.app.name “private” data folder.
SSL/TLS and certificate pinning prevent a would-be attacker from intercepting and evaluating backend API calls.
- New tools make it even easier to strip cert pinning and intercept network traffic for Android mobile apps.
Tools – Hardware Setup
|In order to implement the techniques to invalidate these common developer assumptions, we’ll first need to set up our hacking environment with specific tools, both in terms of hardware and software. The hardware tools are simple enough, consisting primarily of:
Tools – Software Setup
|The software tools that we’ll need include:|
Tools and techniques for stripping certificate pinning from Android mobile apps have been around for quite some time. However, the process has historically been manual, cumbersome, and error prone. Typically, this involved unpacking the APK, searching the smali code for hooks that perform certificate pinning, manually editing the smali code to bypass these code paths, and the repackage the APK to side-load on the mobile device.
Now-a-days, thanks to a significant contribution to the community by shroudedcode, we have a new tool to add to our Android hacking toolbox that greatly simplifies the process of stripping certificate pinning from Android apps. In fact, with the apk-mitm NodeJS package, this process is now reduced to a one-liner. The apk-mitm GitHub page details the perquisites necessary to get the tool setup, which essentially just consists of installing Node and then running:
- npm install -g apk-mitm
Once it’s installed, we can strip certificate pinning from any APK using the one-liner depicted below. Once completed, we can then sideload the patch APK by running:
- adb install <app-patched.apk>
Accessing Private App Data
While the Android platform-level per-app isolations security features are effective at preventing one malicious app from accessing the private data of other apps on a user’s mobile device in the field, as bug bounty hunters we can still bypass these features to gain insight into a target app’s internal workings and potential use and/or disclosure of sensitive information. In many cases, bug bounty hunters are challenged with testing black boxes, where limited information about the target’s internal operations are known to the hacker. In these instances, we can apply deductive reasoning to glean information about what the device might be doing internally, but such hunches are still mostly guess work.
Wouldn’t it be nice if we had a way to peek behind the veil and see how the app is actually working behind the scenes? That’s exactly what we’ll achieve in the steps below. Let’s presume we have downloaded and installed a release build mobile app from the Google Play store and we’re tasked with performing a mobile app penetration test against the app.
We’ll start by listing the packages installed on the mobile device using the command
adb shell pm list packages -f | grep -i app-name
And here we can see I’ve installed a demo app called nerdwell.levelupx.demo
Next, we copy the target app’s APK from the mobile device using the command
adb pull /data/app/path-from-pm-list-packages-output
Next, we uninstall the release build of the target app from our mobile device because in the end, we’re going to side load a debuggable version and we’ll encounter namespace problems if we don’t first uninstall the existing version.
adb uninstall nerdwell.levelupx.demo
We then unpackage the APK copied from the mobile device using the below command, which extracts the contents of the base.apk file into a new folder named “extracted_apk.”
java -jar ./apktool.jar d -o extracted_apk ./base.apk
Now we edit the AndroidManifest.xml file in the extracted_apk folder and set the android:debuggable=”true” flag.
NOTE: In most release build apps, the AndroidManifest.xml will not include android:debuggable=”false” as is depicted below. If this flag is present, we can just change false to true; otherwise, we must add the entire android:debuggable=”true” flag.
Next, we will repackage the APK for deployment to our test mobile device, which requires us to generate a Java keystore using the command: keytool -genkey -v -keystore resign.keystore -alias alias_name -keyalg RSA -keysize 2048 -validity 10000
We then use the apktool.jar tool to rebuild our debuggable APK using the command, which creates a new APK called nerdwell.levelupx.demo–debuggable.apk from the contents of the “extracted_apk” folder.
java -jar apktool.jar b -o nerdwell.levelupx.demo–debuggable.apk ./extracted_apk/
Next, we sign the new APK and prepare it for deployment to our test mobile device using the command, which produces an APK named nerdwell.levelupx.demo–debuggable-aligned-signed.apk.
java -jar ./uber-apk-signer.jar -a ./nerdwell.levelupx.demo–debuggable.apk -ks resign.keystore -ksAlias alias_name
Lastly, we’re now ready to side load our debuggable version of the target APK to our test mobile device using the command: adb install ./nerdwell.levelupx.demo—debuggable-aligned-signed.apk
Once this has been completed, we can access the app’s private data from “adb shell” by using the “runas nerdwell.levelupx.demo” command.
As demonstrated in the below screenshot, this can help us to identify everything from hardcoded API keys to localStorage of sensitive session tokens.
Extracting Private App Data
Picking up where the prior demo leaves off, we might find that it would be helpful to pull the target app’s private data folder over to our Mac or Linux PC to take advantage of our full suite of hacking tools. However, in attempting to do so, you will find that once you switch contexts to the mobile app user (via the “runas” command), you’re unable to write to the external storage (/sdcard/), even if the app has the WRITE_EXTERNAL_STORAGE permission.
Fortunately, we can use tar and a feature of the xxd tool to extract the mobile app’s private data folder as a .tar file onto our Mac or Linux PC. The command to do so is adb shell “run-as nerdwell.levelupx.demo xxd /data/user/0/nerdwell.levelupx.demo/private_data.tar” | xxd -r >private_data.tar
About the Author
Nerdwell is a systems and security engineer with a passion for bug bounty and vulnerability research. He currently works in critical infrastructure protection and has experience supporting technology in a variety of industries, ranging from manufacturing to healthcare. With over 20 years’ experiences, Nerdwell understands firsthand the challenges of building and supporting complex technology solutions securely. In addition to finding bugs and performing security research, Nerdwell enjoys networking and sharing knowledge with fellow hackers.
Get Started with Bugcrowd
Every minute that goes by, your unknown vulnerabilities leave you more exposed to cyber attacks.