Android抓包总结

前言

这篇文章算是总结一下我之前抓包遇到的一些问题, 个人属性里带bug, 所以遇到的问题会比较多, 算是给大家提供一个抓包抓不到应该如何解决的思路。

工具介绍

Android中可用的抓包软件有fiddler、burpsuite、Charls、HttpCanary、Packet Capture、tcpdump、wireshark等等。tcpdump和wireshark可以解决部分不是使用HTTP/HTTPS协议传输数据的app, 用tcpdump抓包, 用wireshark分析数据包。

如果想抓取三大运营商传输的数据包并分析, 因其路由规则的限制, 可能还是需要在android系统中利用iptables设置反向代理, 用Fiddler解密数据包之后分析, 不过好像Fiddler好像有自己的反向代理设置方法, 这部分了解不多。

Charls是Mac上常见的抓包工具, 我没用过, 不过网上蛮多教程的。HttpCanary和Packet Capture这两个工具与常规的电脑上的代理抓包不同的是, 能保证一定能抓取到数据包, 我一般都用Packet Capture来验证应用是否发送请求。HttpCanary被称为移动端的Fiddler, 能够改包和劫持双向认证的应用传输的数据包, 感觉还是蛮强大的。

Fiddler抓取Android数据包

基础设置

  1. 下载好Fiddler之后, 打开该软件, 生成证书。

设置连接

设置HTTPS

用ipconfig查看当前主机的ip

手机和电脑在同一局域网中即可, 手机端设置WLAN种给网络设置代理, 选择对应的WLAN, 选中修改网络, 手动设置代理, 主机名填上面电脑ip地址, 端口写fiddler默认端口8888。

手机端用浏览器访问http://电脑IP:8888, 观察网络是否访问成功, 成功之后, 点击”FiddlerRoot.certificate”下载Fiddler的证书并安装。

如果上述步骤都原原本本做完了, 还是不能出现上图的效果, 可以换个路由或者直接手机开热点。我当时遇到不能访问的问题, ping了一下, 一直显示destination unreachable, 应该是路由器安全规则的限制, 换成了手机开热点就ok了。

继续进行测试的时候, 发现不管是修改密码还是用验证码进行登录, 我都抓不到那些包。想不出是哪里出了问题…..大概找了一下, 发现是SSL Pinning的机制阻止了我抓包。使用了Xposed+JustTrustMe, 就抓取到数据包了, 数据包如下:

如果知道Fiddler怎么抓包了, 不知道怎么改包, 可以用Fiddler左下角的黑框框中断请求, 修改之后再发出, 比如输入bpu baidu.com就可以中断所有发向baidu.com的请求。

之后查看中断的数据包会出现如下效果, 修改完点击Run to Completion就可以把请求发出去了。

Fiddler设置之后手机无法连接上代理

  1. 关闭电脑防火墙

  2. 打开注册表(cmd-regedit), 在HKEY_CURRENT_USER\Software\Microsoft\Fiddler2下创建一个DWORD, 值置为80(十进制)[在空白处右键即可创建]。

  1. 编写fiddlerScript rule:在Fiddler上点击Rules->Customize Rules, 用Ctrl+F查找OnBeforeRequest方法添加一行代码。
1
2
3
4
5

if (oSession.host.toLowerCase() == "webserver:8888") 
{
        oSession.host = "webserver:80"; 
}

Burpsuite抓取Android数据包

基础设置

Burpsuite改包的步骤就不在这里赘述了, 网上有很多教程, 接下来我们要设置burpsuite, 以求抓取到数据包, 设置如下:

提示, 监听的端口号、电脑内网ip要和手机上的代理设置一致, 电脑内网ip可以用ipconfig查看。用burpsuite一直抓取不到https的证书, 怀疑是我burpsuite证书没有安装到手机上, 所以我现在先将它装到系统证书中, 再看看能不能先抓取到https的证书。

安装证书至系统中

1、下载.der格式的证书, 将下载的cacert.der转换格式, 并获取证书hash值, 生成<证书hash>.0文件, 例如:7bf17d07.0

2、把<证书hash>.0证书push到/data/local/tmp目录下后移动至/system/etc/security/cacerts/
(mv操作出错之后, 先试一下“mount -o rw,remount /system”如果出现了报错“mount: ‘/system’ not in /proc/mounts”, 再尝试“mount -o rw,remount /”, 就可以操作system目录了)

3、重启手机

只有root环境才能将proxy证书安装至android系统证书中, 这种方法好像能绕过应用本地证书校验, 其实burp和Fiddler还有其他的代理证书的安装方法都差不多, 最后将<hash证书>.0的文件mv至/system/etc/security/cacerts/目录下即可, 不建议直接将用户证书直接mv, 可能会导致环境出错也不好排查证书错误, 甚至可能导致android网络环境出错。

下面是具体步骤, 先在设置本地代理, 将burpsuite证书下载下来

打开浏览器输入本地地址, 下载.der格式的证书

此处参照文章BrupSuit证书导入Android7.0以上手机, 因为我windows本地安装了ubuntu的子系统, 所以直接用ubuntu1604子系统对证书进行操作。

1
2
3
4
// 转换证书的格式
$ openssl x509 -in cacert.der -inform DER -out cacert.pem -outform PEM
// 提取证书的hash
$ openssl x509 -inform PEM -subject_hash -in cacert.pem

上图中的7bf17d07就为证书的hash值, 将该目录下生成的7bf17d07.0文件push到手机中, 最后移动到/system/etc/security/cacerts/目录下

1
2
3
4
5
$ adb push 7bf17d07.0 /data/local/tmp
$ adb shell
sailfish:/ $ su
sailfish:/ # mount -o rw,remount / # 拥有操作/目录的权限, 本意是要操作/system目录
sailfish:/ # mv /data/local/tmp/7bf17d07.0 /system/etc/security/cacerts/7bf17d07.0

按照原本的文章应该给7bf17d07.0文件添加644权限, 但是我具体操作的时候没有添加权限也成功了, 如果按照我上面的步骤出错了, 可以尝试给文件添加权限。重启之后可以看到证书安装成功。

第一次安装证书的时候出现了不能访问使用https协议的网站, 应该是我测试的手机环境出现了问题, 我重新刷机再按照上面的步骤走一遍就成功了, 如果你们也遇到访问https网站失败的问题, 可以尝试一下使用这个方法。

Android抓包介绍

抓包最重要的是看能不能抓取到数据包, 想要抓到包就要看app使用什么传输协议了, 一般情况下使用HTTP都是能抓到包的, 这也就不难理解, 为什么google坚持推广HTTPS了。为什么说使用HTTPS会抓不到包?现在的HTTPS都是基于TLS协议的, 它的特点就是需要确认传输双方的身份。确认了身份之后再传输数据, 这样就能避免中间人攻击了。下面来看看HTTPS, 是怎么进行数据传输的, 发现HTTPS需要先建立连接才能传输数据。

讲到要认证对方的身份, 我就想起了之前翻译的一篇HTTP安全), 里面就有提及到在使用HTTPS协议的过程中, 客户端和服务器通过证书来判断对方的身份。之前没有怎么理解, 现在才对证书的作用有比较深刻的理解。

文章中举了个例子, Chrome浏览器通过判断是否有证书来判断你访问的网站是否安全的, 并不是你访问的网站真的是安全的。提及这个是因为app使用HTTPS传输也是看证书的, 只不过有的app限制的比较严格只信任自带的证书, 有的app安全要求没那么高, 直接信任系统证书。

抓包出错排查思路

上面是大概的排查思路, 具体的细节可能有些差异。如果proxy带有证书校验, 且JustTrustMe绕不过去, 可能要自己重新根据该应用定制hook模块, 去绕过其本地证书校验, 但是大部分应用都能通过将证书安装为系统证书绕过, 如果无法在root环境下运行, 文章《Intercepting traffic from Android Flutter applications》和JustTrustMe的源码应该能给你提供一点hook模块绕过证书校验的思路, 《Intercepting traffic from Android Flutter applications》讲的是如何绕过google开源框架Flutter中的证书校验进行抓包。

最后说抓不到包还有一种可能性, 就是要求一定要用SIM卡发出传输请求的数据包….不过这个应该应该只有使用了三大运营商的SDK或他们的应用才会出现这种情况, 这部分应该只能用反向代理才有可能抓取到传输的数据包了, 具体情况就要具体分析了。

当时尝试tcpdump+wireshark效果不怎么样, 因为所有的数据都经过了加密, 而wireshark不能解密, 所以对于加密传输的数据包这种方法可能有点鸡肋, 听说有mitmdump抓包工具专门处理linux环境下http/https的数据包, 不过我自己没用过, 之后要是接触了会进一步补充。

SSL pinning和双向认证的区别

SSL pinning实际上是客户端锁定服务器端的证书, 在要与服务器进行交互的时候, 服务器端会将CA证书发送给客户端, 客户端会调用函数对服务器端的证书进行校验, 与本地的服务器端证书(存放在\<app>\asset目录或\res\raw下)进行比对。

而双向认证是添加了客户端向服务器发送CA证书, 服务器端对客户端的证书进行校验的部分, 具体详情可看文章扯一扯HTTPS单向认证、双向认证、抓包原理、反抓包策略的单向认证、双向认证部分的内容。

抓取HTTPS的数据包

Frida绕过SSL单向校验

昨天刚好遇到JustTrustMe无法绕过SSL单向校验的情况, 这几天接触了Frida, 就尝试用DBI的方法绕过SSL的单向校验, 参考文章Universal Android SSL Pinning bypass with Frida这里就不详细地说明Frida的安装方法及使用方法了。

设置Fiddler代理, 在本地下载Fiddler的证书, 将证书直接重命名为cert-der.crt。之后将证书push到/data/local/tmp目录下, 在adb shell里输入./frida-server &再在PC端进行操作。

新建一个frida-android-repinning.js文件, 详细代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
setTimeout(function(){
Java.perform(function (){
console.log("");
console.log("[.] Cert Pinning Bypass/Re-Pinning");

var CertificateFactory = Java.use("java.security.cert.CertificateFactory");
var FileInputStream = Java.use("java.io.FileInputStream");
var BufferedInputStream = Java.use("java.io.BufferedInputStream");
var X509Certificate = Java.use("java.security.cert.X509Certificate");
var KeyStore = Java.use("java.security.KeyStore");
var TrustManagerFactory = Java.use("javax.net.ssl.TrustManagerFactory");
var SSLContext = Java.use("javax.net.ssl.SSLContext");

// Load CAs from an InputStream
console.log("[+] Loading our CA...")
var cf = CertificateFactory.getInstance("X.509");

try {
var fileInputStream = FileInputStream.$new("/data/local/tmp/cert-der.crt");
}
catch(err) {
console.log("[o] " + err);
}

var bufferedInputStream = BufferedInputStream.$new(fileInputStream);
var ca = cf.generateCertificate(bufferedInputStream);
bufferedInputStream.close();

var certInfo = Java.cast(ca, X509Certificate);
console.log("[o] Our CA Info: " + certInfo.getSubjectDN());

// Create a KeyStore containing our trusted CAs
console.log("[+] Creating a KeyStore for our CA...");
var keyStoreType = KeyStore.getDefaultType();
var keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);

// Create a TrustManager that trusts the CAs in our KeyStore
console.log("[+] Creating a TrustManager that trusts the CA in our KeyStore...");
var tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
var tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
console.log("[+] Our TrustManager is ready...");

console.log("[+] Hijacking SSLContext methods now...")
console.log("[-] Waiting for the app to invoke SSLContext.init()...")

SSLContext.init.overload("[Ljavax.net.ssl.KeyManager;", "[Ljavax.net.ssl.TrustManager;", "java.security.SecureRandom").implementation = function(a,b,c) {
console.log("[o] App invoked javax.net.ssl.SSLContext.init...");
SSLContext.init.overload("[Ljavax.net.ssl.KeyManager;", "[Ljavax.net.ssl.TrustManager;", "java.security.SecureRandom").call(this, a, tmf.getTrustManagers(), c);
console.log("[+] SSLContext initialized with our custom TrustManager!");
}
});
},0);

在cmd, 输入如下命令:

1
2
$ adb push burpca-cert-der.crt /data/local/tmp/cert-der.crt
$ frida -U -f it.app.mobile -l frida-android-repinning.js --no-pause

在关闭应用的情况下(避免Magisk Hide处于开启状态), 可得到回显并绕过SSL pinning。

绕过SSL双向校验

其实SSL双向校验是在SSL单向校验的基础上, 在说明这部分内容的时候同时也会有绕过SSL单向校验详细的步骤。参考文章Android平台HTTPS抓包解决方案及问题分析, 我们可以先用sxxl.app来练练手。

在手机上设置完代理之后, 点击完确认, 发现app出现如下弹窗:

在这个时候查看Fiddler会发现应用没有发出任何请求, 这是因为app会对服务器端的证书进行校验, 这时候我们前面安装的Fiddler证书就不起作用了, 应用在发现证书是伪造的情况下拒绝发送请求。根据这个报错+抓不到包, 我们可以确定应用是存在单向校验的, 也就是SSL pinning, 让我们先来解决SSL pinning的问题。使用JustTrustMe可以绕过客户端的证书校验, 下面勾选上JustTrustMe, 在Xposed框架下使用JustTrustMe绕过SSL pinning。

绕过SSL pinning之后, 就能使用Fiddler抓取到HTTPS的数据包了。

我随便输入了一个手机号码, 按下确定之后, 服务器回传了400的状态码过来, 说需要发送证书以确认客户端的身份。到这一步基本能确定是存在双向校验的了, 接下来的工作就是绕过SSL服务器端的校验了。

如果服务器端会对客户端证书进行校验, 证书应该就直接存放在apk里, 网上与SSL双向校验相关的文章都将证书放到<app>/asset目录下, 也就是app的资源目录下, 也有可能放在/res/raw目录下。直接将app解压之后, 发现证书的位置如下:

如果找半天没找到就用关键词.p12/.pfx搜索证书文件。

在我们要使用该证书的时候, 需要输入安装证书的密码。这时候就需要从源码中获取安装证书的密码了。可能是因为多个dex文件的原因, 直接用JEB反编译的时候出错了, 所以我用GDA反编译来分析应用的源代码

获取安装证书的密码

发现通过关键词”PKCS12”能够定位到加载证书的位置。

上图第二个红框中的load函数的第二个参数其实就是证书的密钥, 追根溯源, 我们可以知道v1参数是下图中调用的函数的返回值。

上图的函数的功能就是传递p0参数, 也就是说p0参数就是证书安装密码。想获取这个密码, 关键在于Auto_getValue函数。到这一步, 只要跟进Null_getStorePassword函数看看就好了。

跟进去发现调用了native层的函数, 查看init函数中具体加载的是哪个so文件:

用IDA反编译soul-netsdk之后, 搜索字符串”getStorePassword”, 就定位到函数getStorePassword上了, F5之后, 获得伪代码和密钥:

代理添加客户端证书

HttpCanary添加客户端证书进行抓包的过程可以参照文章Android平台HTTPS抓包解决方案及问题分析, 在自己头昏的时候也感谢这篇文章的作者MegatronKing点醒我。下面主要讲解Fiddler和burpsuite添加客户端证书的方法。

fiddler操作过程

尝试一下用Fiddler处理这部分的内容来安装客户端的证书, 用来绕过双向认证。

用Fiddler抓取该应用的数据包的时候, 发现Fiddler出现了上面的弹窗, 提示要添加ClientCertificate.cer, 才能抓取到传输的数据包, 不然只会出现400的状态码。而我们文件目录下只能找到client.p12client.crt两种格式的证书文件, 所以我们需要将已有的client证书转换成.cer格式的证书。

好像应用中只出现.p12格式的证书的情况比较常见, 所以下面只会提及如何使用openssl将.p12格式的证书转换成.cer/.der格式的证书。(.der和.cer格式的证书仅有文件头和文件尾不同)

下面的命令实现了证书的格式转换, .p12->.pem->.cer, 在生成.pem格式的证书之后, 需要输入证书的密码, 也就是我们上面逆向获取的证书密码。最后将ClientCertificate.cer移动到之前Fiddler弹窗出现的目录下, 也就是<Fiddler安装路径>\Fiddler2下。

1
2
3
4
5
# 将.p12证书转换成.pem格式
$ openssl pkcs12 -in client.p12 -out ClientCertificate.pem -nodes
Enter Import Password:
# 将.pem证书转换成.cer格式
$ x509 -outform der -in ClientCertificate.pem -out ClientCertificate.cer

现在打开Fiddler尝试抓包, 发现原本显示400的数据包现在能够正常抓取到了, 如果还是不能正常抓取到, 双击client.p12将证书安装到本地试试看。

burp操作过程

手机的burpsuite证书安装成功之后, 我们会发现只能抓取到400的状态码。

因为要绕过服务器端对证书的验证, 我们还需要在这里添加上面我们在asset目录下找到的证书。

安装完就能正常抓取数据包了。

抓取TCP的数据包

现在还不知道怎么能够获取TCP的数据包并对其中的内容进行解密, 不过之前在看雪上看到一篇分析使用TCP传输协议的文章某直播APP逆向TCP协议分析, 我大概看了一下, 文章是从逆向的角度分析的, 具体怎么从渗透的角度发现是TCP协议传输的数据包还没有分析过, 看作者使用了wireshark抓取应用的数据包并进行分析, 这个还是要重新分析一下的。

结语

文章最后, 还要感谢华华师傅, 其实实习的时候接触android的时间也不长, 但是之后真的让我接触到很多和学到很多, 也谢谢师傅能耐心地帮我解答问题, 感恩。