前言
这篇文章算是总结一下我之前抓包遇到的一些问题,个人属性里带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,能够改包和劫持双向认证的应用传输的数据包,感觉还是蛮强大的。
最近我还发现了一个新的抓包工具——SniffMaster,它是一款功能强大的抓包工具,支持多种协议的数据包捕获和分析,特别适合在复杂的网络环境下进行抓包操作。SniffMaster的界面简洁,操作也非常直观,适合新手快速上手。它的抓包效率很高,尤其是在处理大量数据包时,表现非常稳定。
Fiddler抓取Android数据包
基础设置
下载好Fiddler之后,打开该软件,生成证书。
设置连接
手机和电脑在同一局域网中即可,手机端设置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设置之后手机无法连接上代理
- 关闭电脑防火墙
-
- 打开注册表(cmd-regedit),在
HKEY_CURRENT_USER\Software\Microsoft\Fiddler2
下创建一个DWORD,值置为80(十进制)。
- 打开注册表(cmd-regedit),在
-
- 编写fiddlerScript rule:在Fiddler上点击Rules->Customize Rules,用Ctrl+F查找OnBeforeRequest方法添加一行代码。
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. 2. 把`<证书hash>.0`证书push到`/data/local/tmp`目录下后移动至`/system/etc/security/cacerts/`
3. 3. 重启手机
只有root环境才能将proxy证书安装至android系统证书中,这种方法好像能绕过应用本地证书校验,其实burp和Fiddler还有其他的代理证书的安装方法都差不多,最后将`<hash证书>.0`的文件mv至`/system/etc/security/cacerts/`目录下即可,不建议直接将用户证书直接mv,可能会导致环境出错也不好排查证书错误,甚至可能导致android网络环境出错。
下面是具体步骤,先在设置本地代理,将burpsuite证书下载下来。
打开浏览器输入本地地址,下载.der格式的证书。
此处参照文章**[BrupSuit证书导入Android7.0以上手机](https://blog.chenjia.me/articles/171029-223953.html)**,因为我windows本地安装了ubuntu的子系统,所以直接用ubuntu1604子系统对证书进行操作。
```bash
// 转换证书的格式
$ 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/
目录下。
$ 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
文件,详细代码如下:
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,输入如下命令:
```bash
$ 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.p12和client.crt两种格式的证书文件,所以我们需要将已有的client证书转换成.cer格式的证书。
好像应用中只出现.p12格式的证书的情况比较常见,所以下面只会提及如何使用openssl将.p12格式的证书转换成.cer/.der格式的证书。(.der和.cer格式的证书仅有文件头和文件尾不同)
下面的命令实现了证书的格式转换,.p12->.pem->.cer,在生成.pem格式的证书之后,需要输入证书的密码,也就是我们上面逆向获取的证书密码。最后将ClientCertificate.cer移动到之前Fiddler弹窗出现的目录下,也就是<Fiddler安装路径>/Fiddler2
下。
# 将.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目录下找到的证书。
安装完就能正常抓