TAG: SSL Pinning Bypass
背景
-
随着App安全技术快速发展,越来越多的App使用SSL Pinning(证书绑定),因此需要有方案来绕过该防御措施。
-
网上有很多脚本,适用于大部分情况,但是一遇到脚本无法使用的时候,我们便需要有逆向分析的思路。
-
本文将从两方面入手,一方面是分析公开脚本的原理,一方面是当脚本失效时的逆向思路分享。
---- 授人以鱼不如授人以渔
逆向思路(一)
- 思路: 当证书校验失败时,应该会调用系统close关闭连接,因此可以trace close入手,定位校验证书的SO位置。
frida-trace -U -f com.xxx.android -i close
- 找到
__handlers/libc.so/close.js
修改为:
/*
* Auto-generated by Frida. Please modify to match the signature of close.
* This stub is currently auto-generated from manpages when available.
*
* For full API reference, see: https://frida.re/docs/javascript-api/
*/
{
/**
* Called synchronously when about to call close.
*
* @this {object} - Object allowing you to store state for use in onLeave.
* @param {function} log - Call this function with a string to be presented to the user.
* @param {array} args - Function arguments represented as an array of NativePointer objects.
* For example use args[0].readUtf8String() if the first argument is a pointer to a C string encoded as UTF-8.
* It is also possible to modify arguments by assigning a NativePointer object to an element of this array.
* @param {object} state - Object allowing you to keep state across function calls.
* Only one JavaScript function will execute at a time, so do not worry about race-conditions.
* However, do not use this to store function arguments across onEnter/onLeave, but instead
* use "this" which is an object for keeping state local to an invocation.
*/
onEnter(log, args, state) {
const sockfd = args[0].toInt32();
const socktype = Socket.type(sockfd);
if (!socktype || socktype !== "tcp") return;
const sockLocal = Socket.localAddress(sockfd)
const tcpEpLocal = sockLocal && sockLocal.ip ? sockLocal : null
const sockRemote = Socket.peerAddress(sockfd)
const tcpEpRemote = sockRemote && sockRemote.ip ? sockRemote : null
if (tcpEpLocal !== null) {
log("[*] TcpEpLocal addr: " + tcpEpLocal.ip + " ,port: " + tcpEpLocal.port + " ,lr: " + this.context.lr + " ,path: " + new ModuleMap().find(ptr(this.context.lr)).path);
}
if (tcpEpRemote != null) {
log("[*] TcpEpRemote addr: " + tcpEpRemote.ip + " ,port: " + tcpEpRemote.port + " ,lr: " + this.context.lr + " ,path: " + new ModuleMap().find(ptr(this.context.lr)).path);
}
},
/**
* Called synchronously when about to return from close.
*
* See onEnter for details.
*
* @this {object} - Object allowing you to access state stored in onEnter.
* @param {function} log - Call this function with a string to be presented to the user.
* @param {NativePointer} retval - Return value represented as a NativePointer object.
* @param {object} state - Object allowing you to keep state across function calls.
*/
onLeave(log, retval, state) {}
}
- 定位到SSL验证的SO位置后进行静态分析
- 静态分析关键词: verify、SSL、x509_store_st,log信息
- 一般分析返回值为bool、int的函数,修改其返回值即可
示例
绕过ssl pinning
var acallBackfn = {
onEnter: function(args){
},
onLeave: function(retval){
console.log("ori retval: " + retval.toInt32());
retval.replace(0x1);
console.log("changed retval: " + retval.toInt32());
}
};
hook_native("libliger.so","_ZN8proxygen15SSLVerification17verifyWithMetricsEbP17x509_store_ctx_stRKNSt6__ndk112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEPNS0_31SSLFailureVerificationCallbacksEPNS0_31SSLSuccessVerificationCallbacksERKNS_15TimeUtilGenericINS3_6chrono12steady_clockEEERNS_10TraceEventE",2,acallBackfn);
逆向思路(二)
定位思路: 采用grep定位字符串位置
grep -rins "verify error" .
关键词:
- OpenSSL
- verify error
- signed certificate
- and verifier failure