从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本

admin 2021年12月12日08:20:59评论207 views字数 3782阅读12分36秒阅读模式
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
看雪论坛作者ID:Avacci

在看雪高研班课时⑦中进行SSL库的内存漫游的时候,发现疑似可以dump所有证书的点,也就是org.conscrypt.ActiveSession的实例域peerCertificates

可以以soul为例,尝试开发dump其客户端证书的通杀脚本。
 
http://aosp.opersys.com/xref/android-8.1.0_r1/xref/external/conscrypt/common/src/main/java/org/conscrypt/ActiveSession.java#50
 
跟着课程中SSL相关的内存漫游的关键步骤走一遍。
 
先是搜索ConscryptFileDescriptorSocket类对象,找到ActiveSession类对象。
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
ActiveSession类对象中找到peerCertificates变量。
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本

这里的peerCertificates以数组形式存放了多个证书。之前课程中对soul进行过分析,这里直接取出asset中的p12证书文件,放入KeyStore Explorer中查看基本信息来作为参照。

从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本

观察多个不同session中peerCertificates的值,发现没有符合的证书。

然后注意到ActiveSession类对象中除了peerCertificates还有一个localCertificates。peerCertificates应该是服务器端的证书,localCertificates是本地app的证书。
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
用Frida写了一个脚本:
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
就可以hook到目标证书了。
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
然后再把得到证书写入文件中:
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
导出的证书已经可以被KeyStore Explorer正确识别了,但是无法导入到Charles中。
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
原因在于这个导出的证书中不包含私钥信息,所以还需要找到证书对应的私钥内容或者找到包含私钥的完整证书。
 
Android中的Https通信开发中基本上都会需要定义一个SSLContext类对象来配置SSL的一些关键参数。配置时需要调用其init初始化方法。
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
需要传入一个KeyManager数组,和一个TrustManager数组。
TrustManager是用来验证服务器端证书的,比如经典的checkServerTrusted。
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
KeyManager数组是包含了客户端(app)本地的证书(包括私钥),用来传给服务器端来对客户端进行验证的。那么我们当前的目标涉及的就是找到KeyManager对象中的本地证书(私钥)。
 

回到前面包含ActiveSession类对象的ConscryptFileDescriptorSocket实例,看看Socket对象中是否包含其中包含相关信息。找到一个SSLParametersImpl类对象。
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本

这个sslParameters中包含了一个X509KeyManager类对象和一个X509TrustManager类对象,似乎就是我们需要的东西。

从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本

另外,从源码中SSLContext.init方法追溯KeyManager传递过程,可以发现其传给了一个contextSpi对象。
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
然后在该对象的engineInit方法中会创建一个SSLParametersImpl类对象,并用KeyManager和TrustManager等内容将其初始化。
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
这样就可以和刚才的发现连起来了。说明理论上来说,SSLParametersImpl确实有可能存有我关心的本地证书相关信息。
 
用Wallbreaker可以看出这个KeyManager对象的具体实现类是KeyManagerImpl。这个类的实例对象可以调用getPrivateKey获取到证书私钥。
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
getPrivateKey需要指定别名:
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
而别名可以通过KeyManagerImpl对象的chooseXXAlias系列方法获取。这里要获取客户端上的证书,应该调用chooseClientAlias方法。这个方法需要传入三个参数,第一个是加密算法名称的列表,第二个是证书发行方的列表,第三个是所属的socket(可以为null)。
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
获取到alias再去调用getPrivateKey方法应该就可以获取到对应的私钥了。
 
ConscryptFileDescriptorSocket类中的getSSLParameter方法返回的是一个SSLParameters类对象,而不是我需要的SSLParametersImpl类对象。
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
有了以上理论指导,可以开始着手hook了。
 
在前面获取证书的脚本中添加额外代码。先获取SSLParametersImpl类对象:
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
这里有个坑是不要用类提供的getSSLParameters方法,返回的内容和想要的不是同一个东西。源码中查看这个getSSLParameters方法,返回了一个SSLParameters类对象。
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
这个类也不能强制转化成我想要的SSLParametersImpl类,不知道是个什么东西。
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
然后按着之前看的流程实现一遍,一直到拿到KeyManagerImpl类对象。这里也是只有包含了localCertificates的socket我们才感兴趣。
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
这里打印了KeyManagerImpl的hash变量值,因为Wallbreaker中看到这个值就是获取所要信息的关键。
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
Hook完运行后,和预计的一样得到了hash的值。
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
可以发现,这里不仅包含一个Private key entry,也包含了一个证书链。这个证书链中只有一项,就是那份本地证书。
 
按正常获取PrivateKey的步骤,应该根据密钥加密算法列表和证书发布者列表去获取目标对象的alias(hash值)。
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
但是尝试后得到的alias始终为null,暂时未找到原因。考虑到大部分情况下本地存放的用于传给服务器校验的证书应该只有一份(不一定准确),暂且用遍历的方式取出hashTable中的所有内容。
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
这里打印出了hashTable值所属的实际类为PrivateKeyEntry:
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
调用其getPrivateKey方法就可以得到与私钥相关的对象:
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
调用getCertificate方法可以获取证书链最末端的一份证书。这里研究的目标只有一份证书,所以返回的就是目标证书。
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
这里的getPrivateKey方法返回的是一个PrivateKey接口类型,需要定位其具体的实现类并用Java.cast转一下后才能调用类的getEncoded方法输出私钥内容。
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
这里我没找到什么好办法,最后是直接通过Wallbreaker查看的具体实现类。
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
但不同的app可能会用不同的类来实现这个PrivateKey接口,所以是个有待优化的点。
 
最后这部分实现大概是这样,将证书和私钥同时写入文件:
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
把两个生成的文件pull到本地,放入KeyStore Explorer中分别查看,可以识别。
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
为了导入Charles,需要看下Charles支持的证书导入格式。有两种支持的格式,PEM格式和P12格式。
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
一般P12格式的证书文件中包含了证书和公私钥密钥对,文件内容是二进制编码的。而PEM格式的证书文件可能不包含私钥,如果需要的话私钥可以单独存放在一个文件中,文件内容是base64编码的。
 
可以看到Charles中导入PEM证书时,需要分别选择填入PEM编码的私钥和PEM编码的证书。
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
而刚才在KeyStore Explorer中,可以将hook出来的文件分别转成PEM编码格式。

从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本

把两份PEM内容分别贴入Charles中:

从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本

证书就添加成功了。
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
再抓包就可以抓到登录包了:
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
虽然初步完成了任务,但每次需要把证书和私钥分开导出来并分别转成PEM格式,再放入Charles显然很麻烦。既然现在可以同时hook到证书和其对应的私钥,理论上应该可以直接导出一个同时包含证书和私钥的P12格式文件,然后直接导入Charles使用。
 
这里搜索到了一篇相关的博客介绍如何以开发视角完成这个操作:
https://blog.csdn.net/u011077027/article/details/100847057
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
这里用到的参数都是刚才hook出来的内容,那直接依样画葫芦就可以了。
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
这里证书密码自定义为hello。
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
把导出的文件直接导入Charles(P12格式):
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
输入密码hello并确认,就添加成功了。
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
再次抓包,没有问题。
从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本

至此,感觉过程中还是略过了不少细节。
这些细节的忽略可能让这次的脚本遇到其他app时达不到效果。不过有了这个基本的框架,自认为对大部分应用来说,遇到后都可以见招拆招了。


从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本 


看雪ID:Avacci

https://bbs.pediy.com/user-home-879855.htm

*本文由看雪论坛 Avacci 原创,转载请注明来自看雪社区



从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本

从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本


# 往期推荐

1. CVE-2021-21224分析笔记

2. 浅见:将JS代码注入到第三方CEF应用程序

3. JSONP和CORS跨域漏洞学习笔记

4. 记一次MEMZ样本分析

5. GlobeImposter家族的病毒样本分析

6. CVE-2010-2553 堆溢出漏洞分析



从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本
公众号ID:ikanxue
官方微博:看雪安全
商务合作:[email protected]



从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本

球分享

从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本

球点赞

从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本

球在看



从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本

点击“阅读原文”,了解更多!

本文始发于微信公众号(看雪学院):从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2021年12月12日08:20:59
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   从SSL库的内存漫游开发dump自定义客户端证书的通杀脚本https://cn-sec.com/archives/459427.html

发表评论

匿名网友 填写信息