Bypassing SSL pinning on Android in 2021
mobile-dev
hacking
This article is a braindump of how I was successful in bypassing SSL pinning on Android 11 in 2021. Please see the acknowledgments at the end for the various guides that helped me get there!
The goal of this article was to understand the August Lock private API. If that’s what you’re interesting in learning more about too, this is the guide to follow. `
Prereqs
- A rooted Android phone (see my old guide on rooting pixel 1). Note for this article i’m using a rooted Pixel 4a.
- Install some proxy/HTTP introspection application on your computer. I’m using a Mac with Proxyman installed for this tutorial.
- Download the Android Debug Bridge (
adb
) binary, bundled as a part of Android platform tools - Install python3 and frida
Setup
Install Frida on your rooted device
You’ll want to start the frida-server
on your android phone.
I did this by installing the frida-server package in magisk
itself (just open the app and search Frida
in the packages panel). You may also start frida-server
manually.
Starting frida on your android device sets
ADB & Frida
In Developer settings, turn on USB debugging
. Plugging your device into your computer, you should be able to issue the following commands.
$ ~/platform-tools/adb devices -l
List of devices attached
XXXXXXXXXXXXXX device usb:XXXXXXX product:sunfish model:Pixel_4a device:sunfish transport_id:1
$ frida-ps -U
PID Name
---- -----------------------------------------------------------------------------------------------------
6598 Android Auto
8348 August
6954 Calendar
7456 Chrome
956 android.hardware.camera.provider@2.6-service-google
957 android.hardware.cas@1.2-service
624 android.hardware.configstore@1.1-service
958 android.hardware.confirmationui@1.0-service-google
1540 logcat
572 logd
...
1284 lowi-server
900 magiskd
1184 media.codec
1173 media.extractor
990 media.hwcodec
1174 media.metrics
1201 media.swcodec
1177 mediaserver
996 modem_svc
997 msm_irqbalance
925 netd
1187 netmgrd
2463 org.codeaurora.ims
...
Set up MITM proxy
Set up a local proxy, sending your Android phone’s connection through something like Proxyman with a trusted SSL cert. You’ll want to be able to see your Android app’s traffic in the proxyman UI, even if you aren’t able to view the actual HTTP bodies.
For more info for MITM’ing your device, see Proxyman’s guide on:
You’ll also want to save the .crt
file to your Android phone’s Downloads - we’ll need this certificate in the next step.
Copy ssl cert to data directory
Here we’ll copy the SSL cert to place the frida script will be able to read it.
$ adb shell cp /storage/self/primary/Download/proxyman-ca.pem.crt /data/local/tmp/cert-der.crt
$ adb shell ls /data/local/tmp
cert-der.crt
re.frida.server
Running a frida script
Frida is an instrumentation platform that allows us to dynamically no-op or reimplement specified system functions.
A couple ssl-pinning scripts i’ve found online are by @pcipolloni and httptoolkit. Choose one of these scripts, or write your own, and push that script to your device.
EDIT (Dec 12, 2021): I’ve have recent success with this script
$ adb push ~/frida_scripts/frida_ssl_pinning /data/local/tmp
/home/josh/frida_scripts/frida_ssl_pinni...1 file pushed, 0 skipped. 0.3 MB/s (2972 bytes in 0.011s)
$ adb shell ls /data/local/tmp
cert-der.crt
frida_ssl_pinning
re.frida.server
Runing the script looks like so:
[~/frida_ssl_pinning]$ frida -U -f com.august.luna -l script.js --no-pause
____
/ _ | Frida 15.0.13 - A world-class dynamic instrumentation toolkit
| (_| |
> _ | Commands:
/_/ |_| help -> Displays the help system
. . . . object? -> Display information about 'object'
. . . . exit/quit -> Exit
. . . .
. . . . More info at https://frida.re/docs/home/
Spawned `com.august.luna`. Resuming main thread!
[Pixel 4a::com.august.luna]->
[.] Cert Pinning Bypass/Re-Pinning
[+] Loading our CA...
[o] Our CA Info: OU=https://proxyman.io, CN="Proxyman CA (7 Feb 2021, harper.local)", O=Proxyman Inc, L=Singapore, C=SG
[+] Creating a KeyStore for our CA...
[+] Creating a TrustManager that trusts the CA in our KeyStore...
[+] Our TrustManager is ready...
[+] Hijacking SSLContext methods now...
[-] Waiting for the app to invoke SSLContext.init()...
[o] App invoked javax.net.ssl.SSLContext.init...
[+] SSLContext initialized with our custom TrustManager!
[o] App invoked javax.net.ssl.SSLContext.init...
[+] SSLContext initialized with our custom TrustManager!
Moving back to Proxyman, you can validate that the SSL unpinning scripts were either successful or unsuccessful.
In the case of the August app, the scripts above did not allow 100% of requests to get through, but regardless may have ended up getting me the information I was looking for. This technique could be combined with other techniques, such as downgrading to an older app version or trying to get the app into an uncommon error state.
Previous work/references
Have a comment? Let me know
This post helpful? Buy me a coffee!