背景
第三篇以获取客户端证书并修改客户端证书为切入点,探索该方式绕过SSL pinning的可能性
客户端证书获取
- Burp导出证书,然后转换
- 证书格式转换
- PEM到DER
openssl x509 -in cert.crt -outform der-out cert.der
- DER到PEM
openssl x509 -in cert.crt -inform der -outform pem -out cert.pem
- PEM到DER
绕过校验
import frida, sys, re
import codecs, time
'''
Running example:
python ./frida_spawn.py ./ca.crt
'''
APP_NAME = "com.xxx.android"
if(len(sys.argv)) < 2:
print("Usage: ./frida_spawn.py [plain text certificate in PEM format]")
quit()
def on_message(message, data):
if message['type'] == 'error':
print(message['stack'])
with codecs.open("./xxx_unpinning.js", 'r', encoding='utf8') as f:
jscode = f.read()
device = frida.get_usb_device(timeout=5)
pid = device.spawn([APP_NAME])
session = device.attach(pid)
print ("pid: {}".format(pid))
script = session.create_script(jscode)
print ("[*] Intercepting ...")
script.on('message', on_message)
script.load()
with open(sys.argv[1]) as file:
script.post({'type': 'input', 'payload': file.read()})
script.exports.mybypass()
device.resume(APP_NAME)
sys.stdin.read()
function bypass() {
//Java.perform(function () {
console.log('[*] Script started');
const certificateArray = Java.use('[Ljava.lang.String;');
const JavaString = Java.use('java.lang.String');
var myCertificate = null;
recv('input', function(value) {
myCertificate = JavaString.$new(value.payload);
});
var HookedClass = Java.use('java.security.cert.CertificateFactory');
const InputStream = Java.use('java.io.ByteArrayInputStream');
var inStreamCertificate = InputStream.$new(myCertificate.getBytes());
var done = false;
HookedClass.generateCertificate.implementation = function (inStream) {
if(!done) { // we will change only the first certificate to ours
console.log("[*] Successfully changed the certificate");
//done = true;
return this.generateCertificate(inStreamCertificate);
}
return this.generateCertificate(inStream);
};
//});
}
rpc.exports = {
mybypass : bypass,
}
底层逻辑
通过底层PEM_read_bio_X509证书时,直接替换证书,感觉是比较通用的做法