在Android上抓HTTPS包,我们会通常使用不限于charles, fiddler等工具作为中间人:在上面这些抓包工具的实现原理中,伪造证书这一点就是他们毕生无法绕过的坎,基于这个破绽就可以有下面的检测方式:判断在请求的时候获取到的服务端证书链中的leaf证书公钥指纹 和 真实的服务端leaf证书的公钥指纹(发版时候硬编码到app) 是否吻合来确定是不是伪造来判断是否有中间人,这种方式就是我们所说的ssl pinning。而mtls则是更严格的校验,服务端也要验客户端的证书(硬编码在app),就意味着你必须要用拥有服务端自签发的信任证书的客户端发起的访问,服务端才受理。既然这样,在中间人伪造了证书在没有配置信任客户端证书的情况下,请求会被拦在跟服务端握手时候的证书校验上。对于常规的java层证书校验方式,如TrustKit-Android依赖的是Android框架层的Java TLS API(HttpsURLConnection、SSLSocket、X509TrustManager等),所以针对于这些证书校验,一些工具譬如JustTrustMe和objection,就是hook掉所有涉及到的常规证书校验的java层校验类来强制验证通过。即便这些工具在java层已经hook了这么多方法,但是依然存在着会使用native层来进行证书校验的方式,存在魔改的http或者自定义协议的通信的方式,这些对于http协议的抓包工具来说都是束手无策的。当然,其实前面说这么多,并不是为了贬低中间人代理类抓包工具,也不是为了争个高低对错,我只是想表达的是中间人代理这类抓包软件作为首选永远不会错,但是当你感到迷茫的时候,请不要忘记还有wireshark站在你的背后。好了,屁话有点多了。进入正题,下面我会基于从目标出发,来说明如何在不使用中间人代理的方式让wireshark实时抓包并且自动解密tls。文章会分为上下两篇:wireshark是支持对用户提供的sslkey.log来解密对应匹配的tls流量,持续的写入sslkey.log,wireshark会使用类似于tail的方式读取新sslkey.wireshark需要的sslkey.log包含的信息会是类似于下面这样:每一行可以分成三段:label: 通常会有CLIENT_RANDOM, CLIENT_HANDSHAKE_TRAFFIC_SECRET, EXPORTER_SECRET等label,其中最关键的是 CLIENT_RANDOM。Client Random: 32字节(64个hex字符),握手阶段(Cient Hello)客户端发起Hello时候的随机数,这个值也是wireshark用来定位要解密tls报文的IDMaster Secret: 48字节(96个hex字符),TLS 握手计算出来的主密钥。简单的可以理解成这是用于生成后续客户端和服务端通信的加密数据的密钥的重要参数。( 可以理解成gen_data_secret(master_secret) ) 图1 图2有了前面这些认识,再次确认我们需要完成的目标:通过任何可行的方式,让要抓包的app上tls流量的sslkey实时写出到pc日志文件上,以让wireshark能够读取解密tls流量。在Android 7之后,aosp的ssl就从openssl换到了boringssl,所以这里我们只会从boringssl项目来研究(虽然我们需要关注的地方大概率并没有区别)。boringssl项目: e59K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6Y4L8$3!0Y4L8r3g2Q4x3V1k6T1L8%4u0A6L8X3N6K6M7$3H3`.在aosp中boringssl会生成libssl.so,是java层SSLSocket / SSLContext等的native支持。这是一句没有提供任何依据的结论描述。对于没有了解过java层是怎么和native关联起来的人来说,这其实很依赖死记硬背,虽然了解这些并这不是必要的,但如果感兴趣的可以看:下面我会以一个不知道这个事实的角度来,从一个简单的例子中跟踪为什么java层定位到libssl.so。(如果已经了解或并不在意,可省略该部分跳转)为什么是这个方法?下面的代码段来自 boringssl项目的src/ssl/ssl_lib.cc文件确定要hook的函数的时候,最先想到的可能会是:为什么呢?最快速确定就是通过readelf来确定符号名称是否存在,或者使用hex编辑器来搜索字符串来确定存在并且在.symtab段(事实上如果是使用ida pro的话,他能显示并不能反映符号的存在,因为他会依赖其他的信息手段来确定函数符号名);elf是否能够保留STB_LOCAL函数符号究其根本在编译的时候就确定了,通过external/boringssl/Android.bp的配置也能确定这些事实。SSL_CTX_set_keylog_callback作为导出符号,自然获取其符号地址起来也是非常的简单,在这之前,我们需要拿到要注册回调函数的SSL_CTX *ctx才能够继续,这个要怎么办呢?前面我们在跟踪java层到native层中,可以看到建立连接,首先需要的是 SSL_new。所以我们的策略是,通过attach符号SSL_new,使用参数SSL_CTX* ctx来使用符号SSL_CTX_set_keylog_callback进行注册回调函数。到这里我们完成了对libssl.so中tls的密钥打印。但这就是所有了吗?不,还没有,wireshark还拿不到这些数据,我们还需要使用rpc来接管所有的sslkey。frida提供了一套rpc的通信实现:允许脚本中使用rpc.exports来注册导出函数定义,并且使用send和recv来通信:(frida-analykit实现了这一套,按照文档配置使用即可)frida-analykit的导出函数注册位于 frida-analykit/script/rpc.tsfrida-analykit的python的rpc接受的数据代理实现位于 frida-analykit/agent/rpc/resolver.py这一部分我只列举了实现原理依据,其余都是代码开发、项目组织层面的,这些我就不过多说了(真想理解看代码自己消化更高效)。实现细节可以跳转阅读frida-analykit光是第一眼看到有这么多文字,耐心就足以被削去一半。说到这些,其实我是更倾向于直接把演示测试这一段放到前头(先通过图片看看怎么个事,再决定要不要细看,毕竟大家时间都很宝贵),但是想了想这会使得文章的行文组织过于跳脱、突兀,所以作罢,仅留下一把跳伞用于定位。下面的资源都可以跳转工具下载,其中下面的测试资源都是相对于该目录下的图3图3可以看到app的大概情况,接下来我们会演示验证下面两点:验证frida-analykit + wireshark是否能规避类似于ssl pinning的证书校验。(虽然从原理上是显而易见的,但是没有比能看到事实更让人感到安心的)wire
...(已截断)
---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-286510.htm
frida-analykit wireshark 流量抓包(上)- 初探libssl体验wireshark无视证书校验的实时https抓包
378 浏览
16 回复
github第一个给你点赞
tql
tql
tql
没看懂和ssl_log_secret有啥关系 最终是hook SSL_new 调用SSL_CTX_set_keylog_callback 注册回调函数来输出keylog 知不知道ssl_log_secret地址好像完全不影响
厉害啊
自己能
没看懂和ssl_log_secret有啥关系 最终是hook SSL_new 调用SSL_CTX_set_keylog_callback 注册回调函数来输出keylog 知不知道ssl_log_ ...
在上篇中提到的ssl_log_secret并不是为了hook它,它是sslkey.log日志生成的代码实现,当要通过SSL_CTX_set_keylog_callback设置回调的时候就是为了在这里面生效,所以需要贴出来这些代码和概念来理清这些思路。至于ssl_log_secret的地址定位是下篇的内容,这里面也是提前给下篇埋个点
没看懂和ssl_log_secret有啥关系 最终是hook SSL_new 调用SSL_CTX_set_keylog_callback 注册回调函数来输出keylog 知不知道ssl_log_ ...
在上篇中提到的ssl_log_secret并不是为了hook它,它是sslkey.log日志生成的代码实现,当要通过SSL_CTX_set_keylog_callback设置回调的时候就是为了在这里面生效,所以需要贴出来这些代码和概念来理清这些思路。至于ssl_log_secret的地址定位是下篇的内容,这里面也是提前给下篇埋个点
zsa233
在上篇中提到的ssl_log_secret并不是为了hook它,它是sslkey.log日志生成的代码实现,当要通过SSL_CTX_set_keylog_callback设置回调的时候就是为了在这里面 ...
上篇和下篇还是有点割裂的 看完完全不知道 定位ssl_log_secret有啥作用 看源码才知道 后面实际上是hook ssl_log_secret 然后自己实现了根据入参生成out的代码.
也就是说 SSL_CTX_set_keylog_callback来获取信息的话和ssl_log_secret 完全没关系.
hook ssl_log_secret 来获取信息的话也和SSL_CTX_set_keylog_callback完全没关系
是这样的吗?
在上篇中提到的ssl_log_secret并不是为了hook它,它是sslkey.log日志生成的代码实现,当要通过SSL_CTX_set_keylog_callback设置回调的时候就是为了在这里面 ...
上篇和下篇还是有点割裂的 看完完全不知道 定位ssl_log_secret有啥作用 看源码才知道 后面实际上是hook ssl_log_secret 然后自己实现了根据入参生成out的代码.
也就是说 SSL_CTX_set_keylog_callback来获取信息的话和ssl_log_secret 完全没关系.
hook ssl_log_secret 来获取信息的话也和SSL_CTX_set_keylog_callback完全没关系
是这样的吗?
自己能
上篇和下篇还是有点割裂的 看完完全不知道 定位ssl_log_secret有啥作用 看源码才知道 后面实际上是hook ssl_log_secret 然后自己实现了根据入参生成out的代码.
也 ...
1. 先回答你的问题:
- SSL_CTX_set_keylog_callback来获取信息的话和ssl_log_secret 完全没关系了吗?hook ssl_log_secret 来获取信息的话也和SSL_CTX_set_keylog_callback完全没关系吗?
--- 如果但就从结果上来看,是的。因为最后的目标都是要获取到sslkey。但是如果从处理方式上来看的话,用`SSL_CTX_set_keylog_callback`来达到的话类似于是“原生实现”的方式获取信息;而用ssl_log_secret达到的话就是侵入式的获取信息,而所说的侵入式的意思就是你这里面提到的:通过解析ssl_log_secret的SSL结果参数来 “自己实现了根据入参生成out的代码“。
2. 在上下篇中确实没有提到是如何运用获取到的ssl_log_secret地址,缺少这一点确实会造成一定的困惑。主要的原因是我在写文章的时候是按照文章主讲思路,然后代码是作为补全的一环。而在这部分内容是希望实现在不长篇大论的情况下,内容更具有针对性的讨论hook的思路。不过但就现在的结果上来看有困惑的会自然而然的去看代码理解的,所以你也有了属于你自己的理解。同时我也认同直接看代码是更高效的。
上篇和下篇还是有点割裂的 看完完全不知道 定位ssl_log_secret有啥作用 看源码才知道 后面实际上是hook ssl_log_secret 然后自己实现了根据入参生成out的代码.
也 ...
1. 先回答你的问题:
- SSL_CTX_set_keylog_callback来获取信息的话和ssl_log_secret 完全没关系了吗?hook ssl_log_secret 来获取信息的话也和SSL_CTX_set_keylog_callback完全没关系吗?
--- 如果但就从结果上来看,是的。因为最后的目标都是要获取到sslkey。但是如果从处理方式上来看的话,用`SSL_CTX_set_keylog_callback`来达到的话类似于是“原生实现”的方式获取信息;而用ssl_log_secret达到的话就是侵入式的获取信息,而所说的侵入式的意思就是你这里面提到的:通过解析ssl_log_secret的SSL结果参数来 “自己实现了根据入参生成out的代码“。
2. 在上下篇中确实没有提到是如何运用获取到的ssl_log_secret地址,缺少这一点确实会造成一定的困惑。主要的原因是我在写文章的时候是按照文章主讲思路,然后代码是作为补全的一环。而在这部分内容是希望实现在不长篇大论的情况下,内容更具有针对性的讨论hook的思路。不过但就现在的结果上来看有困惑的会自然而然的去看代码理解的,所以你也有了属于你自己的理解。同时我也认同直接看代码是更高效的。
6.66.6666
mark
6666感谢
厉害
看看
感谢分享