Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,79 @@ Notes
- Extend for OkHttp: hook okhttp3.CertificatePinner and HostnameVerifier as needed, or use a universal unpinning script from CodeShare.
- Run example: `frida -U -f com.target.app -l ssl-bypass.js --no-pause`

### mTLS interception: bypass server pinning without breaking client auth

For **mTLS** apps, `SSLContext.init(KeyManager[], TrustManager[], SecureRandom)` controls **two different trust decisions**:
- **`TrustManager[]`** validates the **server** certificate.
- **`KeyManager[]`** presents the **client** certificate/private key.

If you replace **both** arrays with a generic “trust all” hook, the app may accept Burp's certificate but **stop sending its client certificate**, so the handshake still fails. In mTLS scenarios, keep the original `KeyManager[]` and replace **only** `TrustManager[]`.

```js
Java.perform(function () {
var X509TrustManager = Java.use('javax.net.ssl.X509TrustManager');
var SSLContext = Java.use('javax.net.ssl.SSLContext');
var TrustAll = Java.registerClass({
name: 'com.ht.TrustAll', implements: [X509TrustManager], methods: {
checkClientTrusted: function () {}, checkServerTrusted: function () {},
getAcceptedIssuers: function () { return []; }
}
});
var init = SSLContext.init.overload('[Ljavax.net.ssl.KeyManager;','[Ljavax.net.ssl.TrustManager;','java.security.SecureRandom');
init.implementation = function (km, tm, sr) {
return init.call(this, km, Java.array('javax.net.ssl.TrustManager', [TrustAll.$new()]), sr);
};
});
```

### mTLS client certificate extraction from live keystore reloads

A common Android mTLS pattern is:
1. generate an app keypair,
2. store the private key + issued client cert in **PKCS12** (`.p12`), often with a runtime-derived password,
3. reload that keystore on every request to build a `KeyManager`.

That password can be strong at rest and still be useless during runtime: the app must eventually call `KeyStore.load(...)`, `getCertificate(...)`, and `getKey(alias, password)` in-process. Hook the method/constructor that receives the **decrypted `KeyStore`**, alias, and password (often a custom `KeyManager` wrapper) and dump the live material instead of brute-forcing the `.p12` offline.

Quick triage:
- `privateKey.getEncoded()` returns **bytes** → software/JCE key, usually exportable.
- `privateKey.getEncoded()` returns **`null`** → likely `AndroidKeyStore`/TEE-backed, so direct key export is blocked and you need a different approach.

<details>
<summary>Frida example: dump client cert/private key from a decrypted PKCS12-backed KeyStore</summary>

```js
Java.perform(function () {
var CKM = Java.use('com.example.app.ClientKeyManager');
var Base64 = Java.use('android.util.Base64');
var X509Certificate = Java.use('java.security.cert.X509Certificate');

CKM.$init.implementation = function (ks, alias, password) {
this.$init(ks, alias, password);
var cert = Java.cast(ks.getCertificate(alias), X509Certificate);
var certPem = Base64.encodeToString(cert.getEncoded(), 0);
var key = ks.getKey(alias, password);
var raw = key.getEncoded();
console.log('alias=' + alias + ' password=' + password);
console.log('CERT=' + certPem);
console.log('KEY=' + (raw ? Base64.encodeToString(raw, 0) : 'null'));
};
});
```

</details>

If the key is exportable, convert the dumped PEM key + certificate into a Burp-compatible client bundle:

```bash
openssl pkcs12 -export -out client-cert.pfx -inkey privateKey.key -in cert.pem
```

Useful extra hook points when Frida is attached **before enrollment**:
- `KeyPairGenerator.generateKeyPair()`
- `KeyStore.setKeyEntry()`
- custom registration code that signs a nonce before the server issues the client certificate

### OkHttp4 / gRPC / Cronet pinning (2024+)

Modern stacks pin inside newer APIs (OkHttp4+, gRPC over Cronet/BoringSSL). Add these hooks when the basic SSLContext hook hangs:
Expand Down Expand Up @@ -482,4 +555,6 @@ Notes
- [Frida OkHttp4 SSL pinning bypass script](https://github.com/Zero3141/Frida-OkHttp-Bypass)
- [XDA guide to strong Play Integrity bypass (2025)](https://xdaforums.com/t/updated-11-17-2025-guide-get-strong-integrity-fix-banking-apps-revolut-google-wallet-android-16-working.4753805/)
- [Weaponizing LSPosed: Remote SMS Injection and Identity Spoofing in Modern Payment Ecosystems](https://www.cloudsek.com/blog/weaponizing-lsposed-remote-sms-injection-and-identity-spoofing-in-modern-payment-ecosystems-2)
- [How to Bypass mTLS on Android with Frida](https://kiratliygt.medium.com/how-to-bypass-mtls-on-android-with-frida-45c5e71373e8)
- [Demo-mTLS- lab app/server](https://github.com/YigitK-1/Demo-mTLS-)
{{#include ../../banners/hacktricks-training.md}}