>samit_hota
Back to research
MOBILE & DEVICE SECURITY

Android Pentesting Lab Setup: System CAs, Writable Storage, and Frida

Samit Hota·
#android#mobile-security#burp-suite#frida

Most Android lab setup guides fail because they ignore the architectural shifts between Android 7.0 (API 24) and Android 10 (API 29). They instruct you to drag-and-drop a user certificate into security settings, then leave you wondering why Burp Suite shows zero HTTP traffic or why your filesystem refuses to mount read-write.

If you want to inspect mobile app traffic reliably today, you must push your interception CA directly into the system certificate store and run an environment capable of bypass-hooking runtime controls. Here is how to build a robust, reproducible lab from scratch that handles modern Android restrictions without falling apart.

Selecting the Target Image: Avoid the Google Play Trap

The biggest mistake researchers make when creating an Android Virtual Device (AVD) in Android Studio is choosing an image tagged with “Google Play”. Google Play system images are production-builds: adb root is permanently disabled in the build configuration, meaning you cannot elevate privileges to write to the system partition.

Instead, create an AVD using a Google APIs system image (not Google Play). For the smoothest balance between modern API behavior and writable partitions, select API 28 (Android 9.0) or API 29 (Android 10.0) x86_64 with Google APIs.

Once created, launch the emulator exclusively from the command line using the -writable-system flag. If you launch it from Android Studio’s UI, your filesystem modifications will be discarded or blocked.

# List available AVDs
emulator -list-avds

# Start the emulator with a writable system partition
emulator -avd Pixel_API_28 -writable-system -no-snapshot-load

Keep this terminal open. The -no-snapshot-load flag ensures you boot cleanly without restoring a state that might lock down the partition.

Converting and Hashing the Burp Certificate

Android’s system certificate store located at /system/etc/security/cacerts/ does not care about file extensions like .crt or .pem. It indexes certificates based on the subject name’s Old OpenSSL hash appended with .0.

First, export Burp Suite’s CA certificate in DER format from http://burp or directly from Burp’s GUI (Project options > Listeners > Export CA certificate). Save it as cacert.der.

Convert the DER file to PEM format, calculate its subject hash, and rename it:

# Convert DER to PEM
openssl x509 -inform DER -in cacert.der -out burp.pem

# Get the old subject hash (Android uses -subject_hash_old)
HASH=$(openssl x509 -inform PEM -subject_hash_old -in burp.pem | head -n 1)

# Rename the certificate using the hash output
cp burp.pem ${HASH}.0

For a standard PortSwigger CA, this hash is typically 9a53d944. Your final file must be named 9a53d944.0.

Mounting /system as Writable and Installing the CA

Starting in Android 7.0 (API 24), applications ignore user-installed certificates by default unless the developer explicitly opts in via network_security_config.xml. To bypass this globally without decompiling and patching every APK, your certificate must live in the system store.

On API 29+, simple adb remount commands often fail due to dynamic partitions and dm-verity protection. Execute this exact sequence to disable verity and push the certificate:

# Elevate ADB permissions
adb root

# Disable dm-verity checking (requires reboot)
adb disable-verity
adb reboot

# Wait for boot, then elevate again and remount
adb wait-for-device
adb root
adb remount

# Push the certificate to temporary storage first
adb push 9a53d944.0 /sdcard/

# Move certificate into the system cert store via adb shell
adb shell "su 0 mv /sdcard/9a53d944.0 /system/etc/security/cacerts/"

# Fix permissions: root ownership, readable by all (644)
adb shell "su 0 chmod 644 /system/etc/security/cacerts/9a53d944.0"
adb shell "su 0 chown root:root /system/etc/security/cacerts/9a53d944.0"

Verify installation by navigating inside the emulator to Settings > Security > Encryption & credentials > Trusted credentials. Under the System tab, look for PortSwigger CA.

Bypassing Custom Pinning with Frida

Moving your CA into the system store solves the default API 24+ restriction, but modern apps frequently implement explicit Certificate Pinning (using OkHttp CertificatePinner, TrustKit, or custom native C++ hooks) or declare a restrictive networkSecurityConfig that rejects custom CAs entirely.

To bypass these active runtime checks, set up Frida on the host and emulator.

First, check your target architecture and match it to the correct frida-server binary release from GitHub:

adb shell getprop ro.product.cpu.abi
# Returns x86_64 (for emulators) or arm64-v8a (for physical devices)

Download the corresponding frida-server-X.X.X-android-x86_64.xz, extract it, push it to /data/local/tmp/, and set execution permissions:

# Push frida-server to the device
adb push frida-server-16.x.x-android-x86_64 /data/local/tmp/frida-server

# Grant root permissions and run in the background
adb shell "chmod 755 /data/local/tmp/frida-server"
adb shell "/data/local/tmp/frida-server &"

Confirm Frida is communicating with your host by listing running processes:

frida-ps -U

To break active pinning, inject a universal pin-bypassing script against your target application package (com.example.targetapp):

frida -U -f com.example.targetapp -l universal-ssl-check-bypass.js

By placing your CA in the system store, you bypass default framework restrictions globally. By running Frida alongside it, you handle application-level override attempts. Set your Android Wi-Fi proxy settings to route through your host machine running Burp Suite, and you will capture cleartext HTTPS traffic across virtually any application.

Want a second set of eyes on your security posture?

Let's talk about where your real exposure is.

Book an advisory call