Charles在Windows上抓包https请求及弱网测试

背景

拦截http proxy的软件很多,如 FiddlerCharles等,能够实现对http通信的拦截,可以查验Request和Response参数,特别是移动设备快速普及,此类软件逐渐被用于移动设备APP的网络请求拦截。

Charles的使用

链接: https://pan.baidu.com/s/14ljJGK0r1UzN0hywbTWRXQ

提取码: 6xjn

PC端安装证书

(1) 安装证书

Help–>SSL Proxying–>Install Charles Root Certificate安装即可

(2) 配置需要证书的域名

Proxy–>SSL Proxying Settings–>SSL Proxying

中添加域名 比如

  • Host:*.baidu.com
  • Port:443

(3) 配置证书信任

此时证书还是不被信任的,让不信任变成信任:

导出证书

image-20221117003846457

输入密码

image-20221117003919348

选择保存位置

image-20221117004005887

注意文件名不能少。

打开IE浏览器—>工具—>Internet选项—>内容—>证书

Win + R 快捷键调出运行对话框,输入inetcpl.cpl,确定,即可打开Internet选项窗口。

image-20221117003629868

导入刚才导出的证书即可。

img

证书到期

删除过期的SSL安全证书:打开Charles软件,依次选择Help->SSL Proxying->Reset Charles Root Certificate

然后再按照上面的经行证书导出和导入。

如果这时还是不能监控到https请求,可以依次选择Proxy->SSL Proxying Settings,在这个里面添加一个:即可。

注意

Android端也要记得重新安装新证书。

Android安装证书

Help–>SSL Proxying–>Install Charles Root Certificate on a Mobile Device or Remote Browser

设置手机代理 比如我的是192.168.2.1:8888

在浏览器中打开 http://chls.pro/ssl 或者扫描如下二维码

1554271067

Android 手机可以在“设置–>安全–>从SD卡安装证书”中安装刚才下载的证书。

不用的Android位置不一样,我们可以搜索从SD卡安装找到对应的配置,选择下载的证书安装即可。

下载的位置默认在Downloads文件夹中。

APP无法抓包的原因

抓不到包,很可能目标APP使用了其它HTTP Client,比如自带一个libcurl的so,那样最终调用的是系统的Socket API,WLAN上设置的HTTP/HTTPS代理对它无效,但其实这种情况很少,市面上绝大多数的应用,都是使用URLConnection和OkHttp,尤其是近些年的应用,几乎都是清一色的OkHttp,所以绝大多数情况下都能抓到包,如果抓不到,很可能是应用自己进行了额外的SSL证书校验工作,根据情况再特殊分析特殊处理。

注意

Android7.0以后抓包失败:App自己不信任用户证书,只信任系统证书

简单来说,抓不到有几个可能:

  1. App自己不走代理,哪怕你设了代理。这种就只能强制走代理。
  2. App自己不信任用户证书,只信任系统证书
  3. App自己连系统证书也不信任,只信任特定证书。SSLPinning的问题。

像支付宝那样的变态,自己带了一个基于so的HTTP Client库,对于关键数据,都不走URLConnection和OkHttp,而是走自己的HTTP Client库,甚至一些WebView页面的渲染,都是先用自带的HTTP Client请求得到json数据,然后填到HTML模板里面,再在WebView里渲染出来。

还有一种情况

请求包虽然能抓到,但是内容加密了,这种只能逆向查看解密方法进行解密了。

APP抓包

Https请求

这种添加CA证书即可。

但是

Android从7.0开始系统不再信任用户CA证书(应用targetSdkVersion >= 24时生效,如果targetSdkVersion < 24即使系统是7.0+依然会信任)。

也就是说即使安装了用户CA证书,在Android 7.0+的机器上,targetSdkVersion >= 24的应用的HTTPS包就抓不到了。

比如上面的例子,抓包工具用内置的CA证书,创建了www.baidu.com域名的公钥证书发给Client,

系统校验此证书时发现是用户CA证书签发的,sorry。。。那么,我们如果绕过这种限制呢?

已知有以下5种方式(低于7.0的系统请忽略)。

模拟器抓包(推荐)

这是最推荐的方式,使用简单。

模拟器中设置代理即可不用安装证书,因为网络走的本机,只要本机安装证书即可。

安装系统版本是Android6的模拟器

推荐模拟器

http://mumu.163.com/

一定要选择Android6版本的。

链接:https://pan.baidu.com/s/1LwABhHS9OHLABvrHANA9lw
提取码:psvm

配置networkSecurityConfig

只能是自己的项目,自己的项目也不推荐,不安全。

配置networkSecurityConfig

如果我们想抓自己的App,只需要在AndroidManifest中配置networkSecurityConfig即可:

1
2
3
4
5
<?xml version="1.0" encoding="utf-8"?>
<manifest>
<application android:networkSecurityConfig="@xml/network_security_config">
</application>
</manifest>

network_security_config

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="system" />
<certificates src="user" />
</trust-anchors>
</base-config>
</network-security-config>

这样即表示,App信任用户CA证书,让系统对用户CA证书的校验给予通过。更多相关信息,详见

Network security configuration:

https://developer.android.com/training/articles/security-config

调低targetSdkVersion < 24

如果想抓一个App的包,可以找个历史版本,只需要其targetSdkVersion < 24即可。

然而,随着GooglePlay开始限制targetSdkVersion,现在要求其必须>=26,2019年8月1日后必须>=28,国内应用市场也开始逐步响应这种限制。

绝大多数App的targetSdkVersion都将大于24了,也就意味着抓HTTPS的包越来越难操作了。

平行空间抓包

平行空间兼容性差,如不支持64位,需要插件。

http://www.parallel-app.com/index_cn.php

https://www.52pojie.cn/thread-1315784-1-1.html

如果我们希望抓 targetSdkVersion >= 24 的应用的包,那又该怎么办呢?

我们可以使用平行空间或者 VirtualApp 来曲线救国。

平行空间和 VirtualApp 这种多开应用可以作为宿主系统来运行其它应用,如果平行空间和 VirtualApp 的 targetSdkVersion < 24,那么问题也就解决了。

在此,我推荐使用平行空间,相比部分开源的 VirtualApp,平行空间运行得更加稳定。

但必须注意

平行空间的版本 4.0.8625 以下才是 targetSdkVersion < 24,别安装错了。

安装到系统 CA 证书目录

需要手机Root

对于 Root 的机器,这是最完美最佳的解决方案。如果把 CA 证书安装到系统 CA 证书目录中,那这个假 CA 证书就是真正洗白了,不是真的也是真的了。

由于系统 CA 证书格式都是特殊的 .0 格式,我们必须将抓包工具内置的 CA 证书以这种格式导出,HttpCanary 直接提供了这种导出选项。

操作路径:设置 → SSL 证书设置 → 导出 HttpCanary 根证书 → System Trusted(.0)

PS. 很不幸的 HttpCanary v2.8.0 前导出的证书名称可能不正确,建议升级到 v2.8.0 以上版本操作。

导出 .0 格式的证书后,

可以使用 MT 管理器将 .0 文件复制到 /etc/security/cacerts/ 目录下,

或者通过 adb remount 然后 push 也可

(这里稍微提一下,别在 sdcard 里找这个目录)。

重新打包

重新打包目标APK,修改AndroidManifest.xml

我们可以使用Apktool等工具对目标APK进行解包,添加 net_security_config.xml]并修改 AndroidManifest.xml]然后重新打包。

但是现在很多应用都做了防打包处理,要么利用Apktool弱点,制造错误让Apktool抛异常,要么重新打包后程序校验自身证书,校验失败无法启动,罢工。

公钥证书固定

Root手机,安装Xposed框架,使用JustTrustMe模块干它

Xposed的JustTrustMe模块Hook了Android SDK的HTTP库,强制跳过SSL证书验证,不管是真证书还是假证书,一律验证通过,于是Fiddler作为中间人攻击制造的假证书也被通过了。

证书固定(Certificate Pinning)是指 Client 端内置 Server 端真正的公钥证书。

在 HTTPS 请求时,Server 端发给客户端的公钥证书必须与 Client 端内置的公钥证书一致,请求才会成功。

在这种情况下,由于 MITM Server 创建的公钥证书和 Client 端内置的公钥证书不一致,MITM Server 就无法伪装成真正的 Server 了。

这时,抓包就表现为 App 网络错误。已知的知名应用,比如饿了么,就采用了证书固定。

另外,有些服务器采用的自签证书(证书不是由真正 CA 发行商签发的),这种情况 App 请求时必须使用证书固定。

证书固定的一般做法是,将公钥证书(.crt 或者 .cer 等格式)内置到 App 中,然后创建 TrustManager 时将公钥证书加进去。很多应用还会将内置的公钥证书伪装起来或者加密,防止逆向提取,比如饿了么就伪装成了 png,当然对公钥证书伪装或者加密没什么太大必要,纯粹自欺欺人罢了。

证书固定对抓包是个非常麻烦的阻碍,不过我们总是有办法绕过的,就是麻烦了点。

5.1 JustTrustMe 破解证书固定
Xposed 和 Magisk 都有相应的模块,用来破解证书固定,实现正常抓包。

eg. JustTrustMe: https://github.com/Fuzion24/JustTrustMe
破解的原理大致是,Hook 创建 SSLContext 等涉及 TrustManager 相关的方法,将固定的证书移除。

5.2 基于 VirtualApp 的 Hook 机制破解证书固定
Xposed 和 Magisk 需要刷机等特殊处理,但是如果不想刷机折腾,我们还可以在 VirtualApp 中加入 Hook 代码,然后利用 VirtualApp 打开目标应用进行抓包。

当然,有开发者已经实现了相关的功能。详见:

VirtualHook:https://github.com/rk700/VirtualHook
CertUnpinning:https://github.com/rk700/CertUnpinning
不过,这里 CertUnpinning 插件的代码有点问题,要改改。

5.3 导入真正的公钥证书和私钥
如果 Client 固定了公钥证书,那么 MITM Server 必须持有真正的公钥证书和匹配的私钥。如果开发者具有真正服务端的公钥证书和私钥,(比如百度的公钥证书和私钥百度的后端开发肯定有),如果真有的话,可以将其导入 HttpCanary 中,也可以完成正常抓包。

在设置 → SSL 证书设置 → 管理 SSL 导入证书 中,切换到服务端,然后导入公钥证书 + 私钥,支持 .p12 和 .bks 格式文件。

双向认证

SSL/TLS 协议提供了双向认证的功能,即除了 Client 需要校验 Server 的真实性,Server 也需要校验 Client 的真实性。

这种情况,一般比较少,但是还是有部分应用是开启了双向认证的。比如匿名社交应用 Soul 部分接口就使用了双向认证。使用了双向认证的 HTTPS 请求,同样无法直接抓包。

关于双向认证的原理。

首先,双向认证需要 Server 支持,Client 必须内置一套公钥证书 + 私钥。在 SSL/TLS 握手过程中,Server 端会向 Client 端请求证书,Client 端必须将内置的公钥证书发给 Server,Server 验证公钥证书的真实性。

注意,这里的内置的公钥证书有区别于前面第 5 点的公钥证书固定,双向认证内置的公钥证书 + 私钥是额外的一套,不同于证书固定内置的公钥证书。

如果一个 Client 既使用证书固定,又使用双向认证,那么 Client 端应该内置一套公钥证书 + 一套公钥证书和私钥。

第一套与 Server 端的公钥证书相同,用于 Client 端系统校验与 Server 发来的证书是否相同,即证书固定;第二套 SSL/TLS 握手时公钥证书发给 Server 端,Server 端进行签名校验,即双向认证。

用于双向认证的公钥证书和私钥代表了 Client 端身份,所以其是隐秘的,一般都是用 .p12 或者 .bks 文件 + 密钥进行存放。由于是内置在 Client 中,存储的密钥一般也是写死在 Client 代码中,有些 App 为了防反编译会将密钥写到 so 库中,比如 S 匿名社交 App,但是只要存在于 Client 端中都是有办法提取出来的。

6.1 双向认证抓包
这里以 S 匿名社交 App 为例,讲解下如何抓取使用了双向认证的 App 的 HTTPS 包。

如果服务器使用了 Nginx 且开启了双向认证,抓包时会出现 400 Bad Request 的错误,如下:

有些服务器可能不会返回 404,直接请求失败。

接下来看,如何使用 HttpCanary 配置双向认证抓包。

首先,解压 APK,提取出 .p12 或者 .bks 文件,二进制的文件一般存放都在 raw 或者 assets 目录。

将 client.p12 文件导入手机,然后在 HttpCanary 的设置 → SSL 证书设置 → 管理 SSL 导入证书中,切换到客户端(因为需要配给 MITM Client),然后导入. p12 文件。

由于双向认证的公钥证书和私钥是受密钥保护的,所以需要输入密码:

一般通过逆向可以从 APK 中提取出密钥,具体操作这里略过。输入密钥后,需要输入映射域名,这里使用通配符 * 映射所有相关域名:

导入完成后如下:

可以点进证书详情查看细节,这个 client.p12 文件包含公钥证书和私钥,是用于双向认证的。

配置完成后,重新进行抓包,看看效果。

可以看到,之前 400 Bad Request 的两个要求双向认证的请求成功了!

SSL 重协商

有些服务器可能会开启 SSL 重协商,即 SSL/TLS 握手成功后发送请求时服务器会要求重新握手。这种情况一般比较少,但是也不排除,已知的应用比如 10000 社区 就使用了 SSL 重协商。

由于 Android 系统对 SSL 重协商是有限支持,所以部分系统版本抓包会失败,表现为网络异常。在 Android 8.1 以下,SslSocket 是完全支持 SSL 重协商的,但是 SSLEngine 却是不支持 SSL 重协商的,而 HttpCanary 解析 SSL/TLS 使用的是 SSLEngine。在 Android 8.1 及以上,SSLEngine 和 SslSocket 统一了实现,故是支持 SSL 重协商的。

所以,如果确认服务器使用了 SSL 重协商,请使用 8.1 及以上版本系统进行抓包。

弱网测试

1、点击Proxy->Throttling Settings

2、勾选[Enable Throttling]使的限制网速可用,相当于开启了限制网速的功能

image-20221118020813056

其中

Bandwidth:带宽 这个限制网速。

Utilistation:利用百分比宽带的利用比保持100%就行。

Round-trip:往返延迟测量客户端和远程服务器之间的第一次往返通信的毫秒延迟。它用于客户端向服务器和服务器向客户端的每次请求。

MTU:最大传输单元

Reliability (%):可靠率(是否丢包)。

Stability (%):稳定率 如果连接不稳定,则连接的质量会在不稳定的质量范围内随机下降。

Unstable quality range (%):不稳定的质量范围。

以下配置用于模拟不太好的2G蜂窝网络:

  • 带宽256 kbps(上传和下载)
  • 利用100%
  • 延迟40 ms
  • MTU为1500字节
  • 可靠性90%
  • 稳定90%
  • 不稳定的质量范围为0%至10%