httptoolkit / frida-interception-and-unpinning

Frida scripts to directly MitM all HTTPS traffic from a target mobile application
https://httptoolkit.com/android/
GNU Affero General Public License v3.0
1.06k stars 198 forks source link

Not working with com.bumble.app #98

Open dkbarn opened 3 months ago

dkbarn commented 3 months ago

I am using HTTP Toolkit with a rooted Pixel 5 device running Android 14. It works like a charm for most apps. Now I am trying to inspect an app that uses certificate pinning, specifically com.bumble.app.

This app communicates with host bma.bumble.com over a raw SSL/TLS socket (not HTTP) using a proprietary variant of the gRPC / Protobuf protocol. I don't expect HTTP Toolkit to have a way of parsing this data, but I do want to inspect the unencrypted raw binary data.

I have followed all instructions at https://httptoolkit.com/blog/frida-certificate-pinning/

My device contains frida-server-16.3.3-android-arm64 and it is actively running. My computer has frida-tools 12.4.3 and I've confirmed everything is working by running frida-ps -U. I've added my certificate into config.js and also enabled debug mode to get more logging output. Here is the output:

(frida-tools) PS C:\Dev\venv\frida-tools> frida -U -l .\config.js -l .\native-tls-hook.js -l .\android-certificate-unpinning.js -l .\android-certificate-unpinning-fallback.js -f com.bumble.app
     ____
    / _  |   Frida 16.3.3 - 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/
   . . . .
   . . . .   Connected to Pixel 5 (id=***)
Spawning `com.bumble.app`...

*** Starting scripts ***
[+] Patched 2 libssl.so verification methods
== Hooked native TLS lib libssl.so ==
Spawned `com.bumble.app`. Resuming main thread!
[Pixel 5::com.bumble.app ]->
    === Disabling all recognized unpinning libraries ===
[+] javax.net.ssl.HttpsURLConnection setDefaultHostnameVerifier
[+] javax.net.ssl.HttpsURLConnection setSSLSocketFactory
[+] javax.net.ssl.HttpsURLConnection setHostnameVerifier
[+] javax.net.ssl.SSLContext init(KeyManager;[], TrustManager;[], SecureRandom)
[ ] com.android.org.conscrypt.CertPinManager isChainValid
[+] com.android.org.conscrypt.CertPinManager checkChainPinning
[+] android.security.net.config.NetworkSecurityConfig $init(*) (0)
[+] android.security.net.config.NetworkSecurityConfig $init(*) (1)
[+] com.android.okhttp.internal.tls.OkHostnameVerifier verify(String, SSLSession)
[+] com.android.okhttp.Address $init(String, int, Dns, SocketFactory, SSLSocketFactory, HostnameVerifier, CertificatePinner, Authenticator, Proxy, List, List, ProxySelector)
[ ] com.android.okhttp.Address $init(String, int, SocketFactory, SSLSocketFactory, HostnameVerifier, CertificatePinner, Authenticator, Proxy, List, List, ProxySelector)
[ ] okhttp3.CertificatePinner *
[ ] com.squareup.okhttp.CertificatePinner *
[ ] com.datatheorem.android.trustkit.pinning.PinningTrustManager *
[ ] appcelerator.https.PinningTrustManager *
[ ] nl.xservices.plugins.sslCertificateChecker *
[ ] com.worklight.wlclient.api.WLClient *
[ ] com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning *
[ ] com.worklight.androidgap.plugin.WLCertificatePinningPlugin *
[ ] com.commonsware.cwac.netsecurity.conscrypt.CertPinManager *
[ ] io.netty.handler.ssl.util.FingerprintTrustManagerFactory *
[ ] com.silkimen.cordovahttp.CordovaServerTrust *
[ ] com.appmattus.certificatetransparency.internal.verifier.CertificateTransparencyHostnameVerifier *
[ ] com.appmattus.certificatetransparency.internal.verifier.CertificateTransparencyInterceptor *
[ ] com.appmattus.certificatetransparency.internal.verifier.CertificateTransparencyTrustManager *
== Certificate unpinning completed ==
== Unpinning fallback auto-patcher installed ==
*** Scripts completed ***

 => android.security.net.config.NetworkSecurityConfig $init(*) (0)
 => android.security.net.config.NetworkSecurityConfig $init(*) (0)
 => com.android.okhttp.Address $init(String, int, Dns, SocketFactory, SSLSocketFactory, HostnameVerifier, CertificatePinner, Authenticator, Proxy, List, List, ProxySelector)
 => com.android.okhttp.Address $init(String, int, Dns, SocketFactory, SSLSocketFactory, HostnameVerifier, CertificatePinner, Authenticator, Proxy, List, List, ProxySelector)
 => com.android.okhttp.Address $init(String, int, Dns, SocketFactory, SSLSocketFactory, HostnameVerifier, CertificatePinner, Authenticator, Proxy, List, List, ProxySelector)
 => com.android.okhttp.Address $init(String, int, Dns, SocketFactory, SSLSocketFactory, HostnameVerifier, CertificatePinner, Authenticator, Proxy, List, List, ProxySelector)
 => com.android.okhttp.internal.tls.OkHostnameVerifier verify(String, SSLSession)
 => com.android.okhttp.internal.tls.OkHostnameVerifier verify(String, SSLSession)
 => com.android.okhttp.internal.tls.OkHostnameVerifier verify(String, SSLSession)
 => javax.net.ssl.SSLContext init(KeyManager;[], TrustManager;[], SecureRandom)
 => com.android.okhttp.internal.tls.OkHostnameVerifier verify(String, SSLSession)
 => com.android.okhttp.internal.tls.OkHostnameVerifier verify(String, SSLSession)
 => com.android.okhttp.Address $init(String, int, Dns, SocketFactory, SSLSocketFactory, HostnameVerifier, CertificatePinner, Authenticator, Proxy, List, List, ProxySelector)
 => javax.net.ssl.SSLContext init(KeyManager;[], TrustManager;[], SecureRandom)
 => com.android.okhttp.Address $init(String, int, Dns, SocketFactory, SSLSocketFactory, HostnameVerifier, CertificatePinner, Authenticator, Proxy, List, List, ProxySelector)
 => com.android.okhttp.internal.tls.OkHostnameVerifier verify(String, SSLSession)
 => javax.net.ssl.SSLContext init(KeyManager;[], TrustManager;[], SecureRandom)
 => com.android.okhttp.internal.tls.OkHostnameVerifier verify(String, SSLSession)
 => javax.net.ssl.SSLContext init(KeyManager;[], TrustManager;[], SecureRandom)
 => com.android.okhttp.internal.tls.OkHostnameVerifier verify(String, SSLSession)
 => javax.net.ssl.SSLContext init(KeyManager;[], TrustManager;[], SecureRandom)
 => com.android.okhttp.internal.tls.OkHostnameVerifier verify(String, SSLSession)
 => com.android.okhttp.Address $init(String, int, Dns, SocketFactory, SSLSocketFactory, HostnameVerifier, CertificatePinner, Authenticator, Proxy, List, List, ProxySelector)
 => com.android.okhttp.internal.tls.OkHostnameVerifier verify(String, SSLSession)
 => com.android.okhttp.Address $init(String, int, Dns, SocketFactory, SSLSocketFactory, HostnameVerifier, CertificatePinner, Authenticator, Proxy, List, List, ProxySelector)
 => com.android.okhttp.Address $init(String, int, Dns, SocketFactory, SSLSocketFactory, HostnameVerifier, CertificatePinner, Authenticator, Proxy, List, List, ProxySelector)
 => com.android.okhttp.Address $init(String, int, Dns, SocketFactory, SSLSocketFactory, HostnameVerifier, CertificatePinner, Authenticator, Proxy, List, List, ProxySelector)
 => com.android.okhttp.Address $init(String, int, Dns, SocketFactory, SSLSocketFactory, HostnameVerifier, CertificatePinner, Authenticator, Proxy, List, List, ProxySelector)
 => com.android.okhttp.Address $init(String, int, Dns, SocketFactory, SSLSocketFactory, HostnameVerifier, CertificatePinner, Authenticator, Proxy, List, List, ProxySelector)
 => com.android.okhttp.internal.tls.OkHostnameVerifier verify(String, SSLSession)
...

Over in HTTP Toolkit, I can see that it is intercepting something, but it's not able to recognize it and it just shows up as garbage that can't be processed. Furthermore, the app itself fails to populate. I can click around on various views, but none of the communication with its backend server is actually working. image

Memexurer commented 3 months ago

even after you manage to bypass bumble ssl pins, then you will still get blocked by their backend - maybe they have some JA3 checks for checking if you are mitming requests?

anyways; maybe it will help you: here's my frida script for capturing some of data sent by that custom protocol (also no clue if it will work on newer versions, because the class names could be different)

Java.perform(() => {

let yb7 = Java.use("b.yb7");
yb7["i"].implementation = function (c26527sn) {
    //send message; if you view this method in jadx then you'll find all the classes responsible for receiving/sending messages
    let gson = Java.use("b.jng").$new();

    console.log(gson.h(c26527sn));
    this["i"](c26527sn);
};

let mzu = Java.use("b.mzu");
mzu["invoke"].overload().implementation = function () {
    //IP pin bypass; you have to use this with  --codeshare 007panda/unpinning
    return null;
};

})

also: use mitmproxy instead of http toolkit, because, as you said, it doesnt support this custom message protocol and it could mess with the data

dkbarn commented 3 months ago

Thanks for this @Memexurer. Which version of the app is the script confirmed working with?

Memexurer commented 2 months ago

also, you can use this for these ja3 checks: https://github.com/fedosgad/mirror_proxy

vikasg603 commented 3 weeks ago

Hey anyone got success with it? badoo also has an same issue it seems.