Android应用防止第三方代理抓包的攻防

本文主要介绍安卓应用的网络通信如何防止被第三方代理抓包,以及安全测试人员如何绕过这些限制进行抓包。文中用到的 vuls 漏洞应用代码及应用可以在https://github.com/AndroidAppSec/vuls/releases/tag/v4.4 下载。

在测试时,我们知道可以通过使用代理工具(如brup)抓取Android应用的网络通信流量的方法。那么很多开发人员就有疑问了,是不是我的应用通过这种方法就一定会被代理抓取到流量,有没有办法防止第三方代理抓包呢。遗憾的是,此处的回答只能是 Maybe。原因待我细细道来。

如何使请求不走默认的系统代理

概述

一般通过 burp 去抓取网络流量是需要设置系统的代理的(注意这里写的是一般,当然也有其他方法)。如下图所示:

 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,我们来看看它是何方神圣。

Proxy.NO_PROXY

大概意思是告诉协议处理器不使用任何的代理,直连互联网。一般用于绕过全局代理。

此时,我们设置代理之后,使用 burp 确实抓不到请求包了。具体功能在 vuls 应用中的“传输安全 -> 不走代理”。

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]); 
            }
        }); 
}

正常安装插件之后,就可以抓取数据包了,如下:

Xposed hook 大法

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 脚本之后,就可以抓取数据包了,如下:

Frida hook 大法

流量转发

还可以通过 iptables 将应用的流量转发到 burp 代理。同样需要一些前置条件:手机需要 adb root,且安装了 iptables(部分机型上可能无效)。

命令如下:

iptables -t nat -A OUTPUT -p tcp -m owner --uid-owner 应用uid  -j DNAT --to-destination ip:端口

通过以下命令获取应用的 uid:

获取应用的 uid

最终命令如下:

iptables -t nat -A OUTPUT -p tcp -m owner --uid-owner u0_a70  -j DNAT --to-destination 192.168.8.233:8080

同时 burp 要设置为透明代理:

burp设置为透明代理

此时 iptables 规则如下:

 iptables规则

可以成功抓取到数据包了:

burp抓请求包

注:可以使用 iptables -t nat -F 命令来清除规则。

方法对比

Android应用防止第三方代理抓包的攻防



留言