本文主要介绍安卓应用的网络通信如何防止被第三方代理抓包,以及安全测试人员如何绕过这些限制进行抓包。文中用到的 vuls 漏洞应用代码及应用可以在https://github.com/AndroidAppSec/vuls/releases/tag/v4.4 下载。
在测试时,我们知道可以通过使用代理工具(如brup)抓取Android应用的网络通信流量的方法。那么很多开发人员就有疑问了,是不是我的应用通过这种方法就一定会被代理抓取到流量,有没有办法防止第三方代理抓包呢。遗憾的是,此处的回答只能是 Maybe。原因待我细细道来。
如何使请求不走默认的系统代理
概述
一般通过 burp 去抓取网络流量是需要设置系统的代理的(注意这里写的是一般,当然也有其他方法)。如下图所示:
一般网络请求库都提供了不走默认代理的功能,这里以常见的 HttpURLConnection 和 OkHttp 为例来做介绍。
HttpURLConnection:
URL url = new URL(urlStr); urlConnection = (HttpURLConnection) url.openConnection(Proxy.NO_PROXY);
OkHttp:
OkHttpClient client = new OkHttpClient().newBuilder().proxy(Proxy.NO_PROXY).build();
可见其关键在于 Proxy.NO_PROXY,我们来看看它是何方神圣。
大概意思是告诉协议处理器不使用任何的代理,直连互联网。一般用于绕过全局代理。
此时,我们设置代理之后,使用 burp 确实抓不到请求包了。具体功能在 vuls 应用中的“传输安全 -> 不走代理”。
此时又该如何抓包呢
这个时候开发表示很开心,可是做安全测试的小伙伴则有点不高兴了。不过没关系,还是有一些办法可以尝试的。
Xposed hook 大法
可以通过 Xposed 来 hook 掉设置代理的地方,修改为 burp 的代理。不过需要一些前置条件:手机需要完整 root,且仅限于 android 9 之前。
插件关键代码如下:
if (lpparam.packageName.equals("ddns.android.vuls")) {
findAndHookMethod("java.net.URL", lpparam.classLoader, "openConnection", Proxy.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
Proxy proxy = (Proxy) param.args[0];
if (proxy.type().equals(Proxy.Type.DIRECT)) {
param.args[0] = new Proxy( Proxy.Type.HTTP, new InetSocketAddress("192.168.8.233",8080) );
XposedBridge.log("proxy " + (Proxy)param.args[0]);
}
});
findAndHookMethod("okhttp3.OkHttpClient.Builder", lpparam.classLoader, "proxy", Proxy.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
Proxy proxy = (Proxy) param.args[0];
if (proxy.type().equals(Proxy.Type.DIRECT)) {
param.args[0] = new Proxy( Proxy.Type.HTTP, new InetSocketAddress("192.168.8.233",8080) );
XposedBridge.log("proxy " + (Proxy)param.args[0]);
}
});
}
正常安装插件之后,就可以抓取数据包了,如下:
Frida hook 大法
也可以通过 Frida hook 来去掉设置代理的地方。同样需要一些前置条件:frida-server 方式,手机需要 adb root;frida-gadget 方式,虽无需 root,仅适用于非系统应用。
插件关键代码如下:
Java.perform(function() {
try {
var URL = Java.use("java.net.URL");
URL.openConnection.overload('java.net.Proxy').implementation = function(arg1){
return this.openConnection();
}
} catch(e) {
console.log("" + e);
}
try {
var Builder = Java.use("okhttp3.OkHttpClient$Builder");
var mybuilder = Builder.$new();
Builder.proxy.overload('java.net.Proxy').implementation = function(arg1){
return mybuilder;
}
} catch(e) {
console.log("" + e);
}
});
运行 frida 脚本之后,就可以抓取数据包了,如下:
流量转发
还可以通过 iptables 将应用的流量转发到 burp 代理。同样需要一些前置条件:手机需要 adb root,且安装了 iptables(部分机型上可能无效)。
命令如下:
iptables -t nat -A OUTPUT -p tcp -m owner --uid-owner 应用uid -j DNAT --to-destination ip:端口
通过以下命令获取应用的 uid:
最终命令如下:
iptables -t nat -A OUTPUT -p tcp -m owner --uid-owner u0_a70 -j DNAT --to-destination 192.168.8.233:8080
同时 burp 要设置为透明代理:
此时 iptables 规则如下:
可以成功抓取到数据包了:
注:可以使用 iptables -t nat -F 命令来清除规则。
方法对比