发布于2022年11月4日2年前 利用Frida手动绕过Android APP证书校验 HTTPS证书校验绕过有很多成熟的方法,比如SSL Unpinning,JustTrustMe等,但是遇到混淆过或写在so里的校验的时候是无效的。 本文写的可能会有些啰嗦,记录了我整个尝试的思路。没有直接写绕过方法,是想给其他和我一样的萌新提供一些思路,如有不妥之处大佬们轻喷。最近买了一个TP-Link的摄像头,顺便下载的它配套的安卓应用,想看看这个应用在与服务器交互的时候都发了些啥,因此准备抓包。当我把姿势都摆好了之后,却发现它的流量在Burpsuite里完全没出现。掏出祖传的XPosed插件SSL Unpinning,竟然没用。emmmm,那可能是进行了混淆,XPosed在Hook的时候需要特定的包名,如果包名被混淆了自然是Hook不到的嘛。代理流量在系统里配置了代理却抓不到包,很有可能是因为APP有限制,禁止流量走代理。因为我是在模拟器上安装了这个APP,因此想到了强行代理这个模拟器的流量,看看会怎样。测试中用的是雷电模拟器,流量转发用的是Proxifier。因此在Proxifier中配置需要拦截流量的进程名为LdBoxHeadless.exe的进程,来强行转发流量到我们的Burp上:转发成功,现在尝试一下请求,比如找回密码功能,点击“完成”后,返回的提示竟然是“网络连接失败”???同时,Burp收到警告,提示Failed to negotiate a TLS connect to xxx,表示HTTPS握手过程失败。好吧,果然是限制了流量同时也校验了证书。查看日志既然发生了错误,那应该会有相应的报错日志,看看能不能从日志里看出点端倪。进入adb shell,先输入ps命令查看对应进程的pid,比如这里是 2035 ,在用logcat | grep 2035来过滤出该进程的日志即可。此时再点击完成按钮,提示“网络连接失败”,查看logcat打出来的日志,发现了证书错误的信息:反编译dex看到相关的报错日志,如果有反编译出来的伪代码,看看能不能搜到相关报错的日志的语句来定位到相关代码段,顺藤摸瓜找到校验的函数,再去Hook岂不美滋滋~先尝试一下反编译,来看看是不是被混淆过。解压apk,使用dex2jar将classes.dex转换成.jar格式,再用Java Decompiler查看。看到包名的时候,发现它确实进行了混淆。但是并没有看到和常见的 HTTP 相关的组件(比如OKHttp3)相关的包。将报错日志的部分拆成关键词来搜索也完全搜不到相关的地方,非常让人怀疑实际上这部分逻辑就没写在Java层,很有可能在so里。分析so既然如此,进入apk包中的lib文件夹,看看它加载的so里有没有什么特别之处。从so文件的大小和名称中,第一眼就识别到了libIPCAppContextJNI.so文件。果断拖到ida中看看里面有什么。在ida中加载完之后,果断的打开Strings Window来暴搜字符串。输入verify error:num,看看我发现了什么!跟进这个字符串的调用,F5,顺利找到打出这句日志的代码:但是,这个函数是一个回调函数,函数名为TPSSLManager::SSLCtxVerifyCallback,追踪它的调用也没有找到有验证证书相关的操作,似乎又陷入僵局……因为对证书校验的实现不是很熟悉,打破僵局的方法只能求助于度娘。看到那句日志打印的上一行X509_verify_cert_error_string函数,抱着死马当活马医的心态,扔进搜索引擎,竟然搜到了一堆OPENSSL的证书校验的示例代码!通过示例代码的注释,发现OPENSSL校验证书的函数名为X509_verify_cert,回到ida里搜了一下,Bingo!跟进这个函数被调用的地方看了下,和示例代码一样,都是在用if语句在判断这个函数的返回值是1还是0,那初步确认证书校验的点就在此处。Frida Hook由于测试是在雷电模拟器里做的,因此需要下载并运行x86版本的Frida-server。给萌新的一个小提示:Frida运行需要关闭SELinux,可以在adb shell中输入setenforce 0来关闭它。确认函数地址在写JS脚本之前,先使用Frida的命令行来确认一下要Hook的模块和函数是否可用(个人觉得这样便于调试)。在PC端的命令行输入frida -U com.tplink.ipc连接.进入后输入Module.findExportByName("libIPCAppContextJNI.so", "X509_verify_cert")应该能打印出X509_verify_cert函数的入口地址,但是竟然返回的是null。此时有点慌了,难道我的判断出错了吗?果断使用Process.enumerateModules()命令,会在命令行中打印出所有的模块(即加载的so),找了一下发现也没有libIPCAppContextJNI.so,甚至路径几乎都是/system/lib这样系统路径下的文件。在这里我卡了很久,搜了很多文章,都没有发现问题出在哪了,简直一度就要放弃了,直到我想要不要换真机试一下……简直峰回路转!全都成功了,顺利打印出地址:如果在模拟器环境里找不到so,搜不到函数,一定要赶快换真机试一下,一定要啊!血的教训!!!脚本编写 & Hook接下来就可以编写JS代码来进行Hook了,代码内容也很简单,就是修改这个函数的返回值,让它永远等于1即可:Java.perform(function(){ var nativePointer = Module.findExportByName("libIPCAppContextJNI.so", "X509_verify_cert"); console.log("-------------Start-------------"); Interceptor.attach(nativePointer, { onEnter: function(args){ // 此处是修改入参要做的逻辑,在这里不需要修改,留空即可 }, onLeave: function(retval){ console.log("----------leaving-------------") // 打印原始的返回值 console.log(retval); // replace修改返回值 retval.replace(0x1) // 再次打印出来验证一下修改是否成功 console.log(retval); } }); });把这个文件保存,我命名为hook.js。开启Frida,在忘记密码那里点几下:(frida) pentest@DESKTOP-2AE07FJ:~/frida$ frida -U com.tplink.ipc -l hook.js ____ / _ | Frida 12.8.17 - A world-class dynamic instrumentation toolkit | (_| | > _ | Commands: /_/ |_| help -> Displays the help system . . . . object? -> Display information about 'object' . . . . exit/quit -> Exit . . . . . . . . More info at https://www.frida.re/docs/home/ Attaching... -------------Start------------- [MI 5s::com.tplink.ipc]-> ----------leaving------------- 0x1 0x1Nice!成功Hook到并打印了返回值。配置代理到这一步,已经接近成功了,但是在系统里设置代理之后它并不会走,判断应该是做了代理上的限制,导致APP的流量不跟随代理。那这一步的目标,就是让APP的流量顺利走到PC的Burpsuite上,来帮助我们进行分析。第一种思路自然是找出限制代理的部分,一并Hook掉,但是我实在是不想再去找了,于是果断放弃;第二种思路是通过无线网卡共享一个热点,再配置转发达到抓包的目的。这种方法在Windows系统下配置很麻烦,放弃;第三种思路是PC端配置反向代理,手机端通过修改hosts文件强行转流量,因为之前的测试中配置过(详细的原理和配置可参见《泄露的网站证书和私钥?来做些有趣的事吧!》),且配置也简单(就是操作步骤有点复杂,好在环境都在),就果断用了。反向代理是要配置证书的,但是因为Hook掉了校验,所以配置什么证书也无所谓了~配置Hosts配置hosts文件需要知道域名,在分析校验的部分看到了对于*.tplinkcloud.com.cn域名的校验。因此再次用Strings暴搜:因为考虑到可能不同的功能会访问不同的域名,为了方便起见,一次性把这些域名都添加到hosts文件里。在修改hosts文件的时候,需要注意编写的格式。可以先通过adb pull /etc/hosts将原始的hosts文件下载到PC,再在这个基础上修改。在“回车”符号上一定要注意,Android只识别\n而无法识别\r\n,因此在编辑的时候一定要注意回车符。我使用的是Notepad++来进行编辑,注意右下角:如果不是LF的话,可以双击这个位置选择“转换为Unix格式”即可。编辑完后再adb push回原位并重启即可生效。开始抓包!终于在经过无数失败之后,可以开始抓包了。如果以上步骤都配置正确的话,此时打开APP,在PC上输入命令frida -U com.tplink.ipc -l hook.js后,点击相应的按钮,在命令行里会出现一串这样的输出:每一个输出都代表一个请求的证书校验被绕过了。打开Burpsuite,终于能看到熟悉的请求了:接下来就可以尽情的发挥脑洞开始测试了!总结整个思路其实非常简单,顺利转到包还是因为这个APP没有进行过加固,so里的函数名都很全,所以在分析这一步中并没有太大难度。总体思路总结如下:通过反编译等方式确定证书绑定的核心函数的位置;使用Frida对该核心函数进行Hook;如果遇到无法代理的情况,嫌麻烦可以用反向代理的方式抓包。
创建帐户或登录后发表意见