APP代理检测对抗

APP代理检测对抗

原文链接:https://xz.aliyun.com/t/11398

代理与VPN

1、代理

代理(proxy) 也称网络代理,是一种特殊的网络服务,允许一个终端(一般为客户端)通过这个服务与另外一个终端(一般为服务器)进行非直接的连接。

一个完整的代理请求过程为:客户端首先根据代理服务器所使用的代理协议,与代理服务器创建连接,接着按照协议请求对目标服务器创建连接、或者获得目标服务器的指定资源。

2、VPN

VPN(virtual private network)(虚拟专用网络 )是常用于连接中、大型企业或团体间私人网络的通讯方法。它利用隧道协议(Tunneling Protocol)来达到发送端认证、消息保密与准确性等功能。

3、代理和VPN的区别

从各自的定义,我们就能看出VPN的特点是采取隧道协议进行数据传输和保护;而代理使用的则是对应的代理协议

下面是VPN和代理的常用协议:

协议名称
VPN OpvenVPN、IPsec、IKEv2、PPTP、L2TP、WireGuard等
代理 HTTP、HTTPS、SOCKS、FTP、RTSP等

VPN 协议大多是作用在 OSI 的第二层和第三层之间,所以使用 VPN 时,几乎能转发所有的流量。

而代理协议多作用在应用层,最高层。

安卓代理检测

知道了代理与VPN的作用后,在APP中,如果开发人员在代码中添加了一些网络层的检测机制,而这些机制恰恰又是针对工作层协议进行的检测,那么只要分析出工作在IOS的哪一层,抢先一步在下层做出应对,那APP在上层无论怎么检测,都没有用。下面将对测试场景进行详细分析。

抓包的步骤:

1.在客户端(手机)中设置代理服务器的地址

2.开启代理服务器(burp)的代理功能

如果在客户端对代理服务进行过滤,禁止客户端通过代理服务器进行访问Internet,添加如下代码:

connection = (HttpURLConnection) url.openConnection(Proxy.NO_PROXY);

官方对于Proxy.NO_PROXY的描述如下:

/**
 * A proxy setting that represents a {@code DIRECT} connection,
 * basically telling the protocol handler not to use any proxying.
 * Used, for instance, to create sockets bypassing any other global
 * proxy settings (like SOCKS):
 * <P>
 * {@code Socket s = new Socket(Proxy.NO_PROXY);}
 *
 */public final static Proxy NO_PROXY = new Proxy();

// Creates the proxy that represents a {@code DIRECT} connection.private Proxy() {
    type = Type.DIRECT;
    sa = null;
}

NO_PROXY实际上就是type属性为DIRECT的一个Proxy对象,这个type有三种:

  • DIRECT
  • HTTP
  • SOCKS

所以,Proxy.NO_PROXY的意思是connection的请求是直连

此时若通过系统进行代理,app对外请求会失效,也就是视觉上看到的卡死状态,就是不让走系统代理。

安卓手机上设置系统代理即是在【设置】-【WLAN】-【修改网络】手动设置代理。

针对不走系统代理的情况有如下两种应对:

1、使用基于VPN模式的Postern

2、使用基于iptablesProxyDroid

对此,我做出了如下一些测试:

使用系统代理

APP关键代码如下:

private void sendRequestWithHttpURLConnection(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                HttpURLConnection connection = null;
                BufferedReader reader = null;
                try{
                    URL url = new URL("http://www.baidu.com");
                    connection = (HttpURLConnection) url.openConnection(Proxy.NO_PROXY);
                    connection.setRequestMethod("GET");
                    InputStream in = connection.getInputStream();

                    reader = new BufferedReader(new InputStreamReader(in));
                    StringBuilder response = new StringBuilder();
                    String line;
                    while ((line = reader.readLine()) != null){
                        response.append(line);
                    }

                    showResponse(response.toString());

                } catch (Exception e){
                    e.printStackTrace();
                } finally {
                    if (reader != null) {
                        try {
                            reader.close();
                        } catch (IOException e){
                            e.printStackTrace();
                        }
                    }
                    if (connection != null){
                        connection.disconnect();
                    }
                }
            }
        }).start();
    }

针对Proxy.NO_PROXY,先测试一下,系统代理是否真的不能抓包。

如下图先设置系统代理,burp监听8888,此时打开APP,点击发送请求无任何反应,burp中也抓不到包,说明系统代理被禁了。

img

img

使用Postern代理

用过这款软件的都知道,当开启代理服务后状态栏会有个钥匙的标志,这可能也是基于VPN模式工作的特征

img

同样的APP,点击请求,此时成功绕过了Proxy.NO_PROXY检测!也说明了VPN协议在HTTP协议的下层。

img

安卓VPN检测

VPN也是代理的一种,但是由于通讯协议的差异,所以检测代码也不一样。

当客户端运行VPN虚拟隧道协议时,会在当前节点创建基于eth之上的tun0接口或ppp0接口,所以一旦出现带有明显特征的网络接口名称,就可以认定是使用了VPN协议进行通信。

下面这段代码的检测方式:出现特征tun0或者ppp0则退出应用,也就是我们看到的闪退效果。

private void isDeviceInVPN() {
        try {
            Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
            while (networkInterfaces.hasMoreElements()) {
                String name = networkInterfaces.nextElement().getName();
                if (name.equals("tun0") || name.equals("ppp0")) {
                    stop();
                }
            }
        } catch (SocketException e) {
            e.printStackTrace();
        }
    }

在点击监听中放置isDeviceInVPN()功能,点击即触发,如果检测到了使用了VPN则直接退出。

@Override
    public void onClick(View view){
        if (view.getId() == R.id.send_request){
            isDeviceInVPN();
            sendRequestWithHttpURLConnection();

        }
    }

使用ProxyDroid代理

当前场景:APP同时开启了代理检测以及VPN检测

这时使用iptables进行数据转发的软件 ProxyDroid 进行测试,配置如下图所示:

iptables原理

我们都知道安卓使用的是linux内核,而linux内核提供的防火墙工具是Netfilter/Iptables

Netfilter是由linux内核集成的IP数据包过滤系统,其工作在内核内部,而Iptables则是让用户定义规则集的表结构。

也就是,iptables是一个命令行工具,位于用户空间,它真正操作的框架实现在内核当中。

Netfilter是一个数据包处理模块,它具有网络地址转换数据包内容修改数据包过滤等功能。 要使netfilter能够工作,就需要将所有的规则读入内存中。netfilter自己维护一个内存块,在此内存块中有4个表:filter表、NAT表、mangle表和raw表。在每个表中有相应的链,链中存放的是一条条的规则,规则就是过滤防火的语句或者其他功能的语句。也就是说表是链的容器,链是规则的容器。实际上,每个链都只是一个hook函数(钩子函数)而已。

Iptables主要工作在OSI七层的2.3.4层,好像也没比VPN的工作协议低,反而还有高的,但是测试结果证明,是我想错了,iptables不是由于协议低,而是没有出现tun0或者ppp0这两个关键的网卡特征,所以成功绕过了VPN的检测。

基于iptables这个流量转发,我还发现了一个新的名词,叫做“透明代理”,iptables的转发模式就是这种。

由此,延伸了一个新的代理模式,通过burp进行“透明代理”,网上的教程错综复杂,亲测使用过程如下。

7.透明代理

  • 原理:透明代理技术可以让客户端感觉不到代理的存在,用户不需要在浏览器中设置任何代理,只需设置缺省网关即可。在访问外部网络时,客户端的数据包被发送到缺省网关,通过缺省网关的路由,最终到达代理服务器,最后代理服务器运行代理进程,数据实际被重定向到代理服务器的代理端口,即由本地代理服务器向外请求所需数据然后拷贝给客户端。

接下来我将尝试:结合安卓端的透明代理技术与burp存在的invisible模式

7.1、使用Burp透明代理

(1)安卓端设置

首先在设备上手动进行设置:将所以请求80、443端口的tcp流量进行nat转发到192.168.50.177(burp的监听地址)的对应端口上

adb shell
su
iptables -t nat -A OUTPUT -p tcp --dport 80 -j DNAT --to  192.168.50.177:80
iptables -t nat -A OUTPUT -p tcp --dport 443 -j DNAT --to  192.168.50.177:443

查看当前规则是否成功添加

iptables -t nat -L

img

Burp证书导入
# 转为pem格式
openssl x509 -inform DER -in cacert.der -out cacert.pem

# 重命名为<hash值>.0
mv cacert.pem `openssl x509 -inform PEM -subject_hash_old -in cacert.pem |head -1`'.0'

#移动证书到系统目录
mv /sdcard/<hash值>.0 /system/etc/security/cacerts/
mv /sdcard/<hash值>.0 /etc/security/cacerts/

#更改权限和chwon所属者
chmod 644 /system/etc/security/cacerts/<hash值>.0
自写脚本
#开启代理
#!/bin/bash
#将所以请求80、443端口的tcp流量进行nat转发到192.168.1.66:8080
iptables -t nat -A OUTPUT -p tcp --dport 80 -j DNAT --to  192.168.1.66:8080
iptables -t nat -A OUTPUT -p tcp --dport 443 -j DNAT --to  192.168.1.66:8080
# 打印OUTPUT链的iptables规则
echo `iptables -t nat -L OUTPUT`

#关闭代理
#!/bin/bash
# 清空iptables nat转发规则
iptables -t nat -F
# 只打印OUTPUT链的iptables规则
echo `iptables -t nat -L OUTPUT`

(2)代理服务器端设置

添加80和443的端口监听

在【Binding】中设置端口,选中 【All interfaces】

img

并对【Request handing】做出如下设置

img

img

Redirect to port - 如果配置了这个选项,Burp会在每次请求转发到指定的端口,而不必受限于浏览器所请求的目标。

Force use of SSL - 如果配置了这个选项,Burp会使用HTTPS在所有向外的连接,即使传入的请求中使用普通的HTTP。您可以使用此选项,在与SSL相关的响应修改选项结合,开展sslstrip般的攻击使用Burp,其中,强制执行HTTPS的应用程序可以降级为普通的HTTP的受害用户的流量在不知不觉中通过BurpProxy代理。

设置之后,Proxy状态如下

img

此时burp就可对转发到这里的80和443端口的流量进行透明代理

注意:如果出现443端口被占用,查找进程kill掉即可。

img

img

以管理员身份运行 cmd 执行如下代码

img

经过测试,burp成功抓取到了请求包。

这里不禁思考,如果是基于iptables进行的数据转发,那么刚才的ProxyDroid是否也内置了一些路由规则呢?

查看一下开启ProxyDroid时iptables当下的规则

img

从图中可以看到共有六条策略,其中最后两条就是我们刚才手动添加的,但并没有看到burp监听的8888端口,8123、8124一定是软件内置的代理转发端口,想要知道具体原理还需要详细分析ProxyDroid的源码。

血泪避坑:网上出现了很多教程,最关键的iptables规则写法不一,导致多次测试结果并不成功,如果将安卓终端的80和443端口同时转发到burp上监听的唯一一个端口则会出现连接错误。根据burp官方文档说明为每个端口号设置监听器会更加稳定,也就是要设置两个代理监听。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇