安卓抓包总结

1.大纲

主要是从几个点来了解安卓APP通用的解决办法:

  • wifi代理抓包
  • vpn抓包
  • 客户端ssl验证解决方案
  • 服务器ssl验证解决方案
  • 双向ssl验证
  • 非http协议抓包
  • 自有的ssl验证协议

1.wifi代理抓包

当我们准备抓一个app的时候,第一件事肯定是抓包。传统的抓包解决方案是电脑安装Fiddler/Charles,手机WIFI配置好代理。给手机流量代理到我们的抓包软件,这样我们就可以完成对app的抓包:


image.png

一般没有证书效验的app,或者抓包检测的app我们都可以通过这种办法进行抓包。但是这里我们并不推介这种抓包的办法。我个人的习惯一般是使用vpn抓包的方式。

因为网上很多对wifi配置代理抓包的文章,这里就不一一概述。主要就是wifi设置代理,app安装抓包软件的证书。

这里简单的说说我们通过抓包软件抓到的包的原理,方便后面理解为什么需要过ssl验证:


image.png

这里用猿人学一张图简单来说明,非常简单明了。就是客户端 -> 抓包软件 -> 服务端。

1.1 优点

wifi代理抓包的优点可能就是配置非常非常方便,导入抓包软件的证书后也可以抓https的包。

1.2 缺点

相对于vpn抓包方案,wifi代理抓包最容易被检测。

1.2.1 wifi代理检测

缺点就是很容易被检测是否使用了代理:

System.getProperty("http.proxyHost")
System.getProperty("http.proxyPort")

如何判断app进行了wifi代理检测?
配置好代理,打开抓包软件,可以抓到app的其它请求但是抓不到这个app的数据,app直接显示无网络。这时候可能就是wifi代理被检测,或者有ssl证书效验。

wifi代理检测用的app还是比较多,建议采用vpn抓包的方式规避。

1.2.2 强制代理

或者是某些APP直接强制使用代理:

OkHttpClient client = new OkHttpClient().newBuilder().proxy(Proxy.NO_PROXY).build();

和我们py的requests一样,安卓也可以设置代理。设置请求走默认代理而不走系统代理,防止被抓包。

如何判断app是进行了强制代理?
设置了wifi代理后,关闭抓包软件,app依旧可以正常请求网络。可能是app强制进行了代理转发,或者压根没走http协议。

强制代理的情况很少,目前没有遇见过,这时候可以通过tcpdump抓取网络报文可以发现App直接和服务器建立了连接而没有和代理建立连接

2 VPN抓包

vpn抓包个人习惯使用Postern+Charles的组合。这里非常推介,所以写一下安装和配置的过程

2.1 环境

简单的介绍一下我的环境:

  • Postern-3.1.2
  • charles-proxy-4.6.2-win64
  • win 10
  • 安卓8,面具root

注意电脑的防火墙要关闭,否则可能导致流量无法转发。之前出现过公司电脑不行,个人笔记本可以的情况。然后关闭公司电脑后charles才能连接到手机。害我折腾了半天

2.2 安装配置

先给我们的手机安装Postern,电脑安装charles。然后配置charles

2.2.1 Charles配置

打开charles设置proxy,点击proxy->proxy-settings,开启socks然后配置一个端口,我这里给的是8889,使用socks代理来转发流量。


image.png

保存后再点击proxy->ssl proxying后,配置抓https的包


image.png

规则,两个都填*就行了


image.png

2.2.2 charles导出证书

从charles导出证书,注意charles导出证书的时候会导出在你选择的路径上一级(有点坑)


image.png

推送到手机,并安装该证书

adb push xxx.pem /sdcard

安卓7以后不信用户目录的证书,所以需要把证书移至系统证书目录。利用面具的Move Certificates模块来移动证书。


image.png

重启自动迁移证书。


image.png

2.2.3 没有面具迁移证书的办法

有时候手机使用的su去进行的root,没有使用面具。所以这么好的插件就无法使用了,这时候我们可以用命令进行操作:

先安装charles证书,再获取root权限

su
mount -o rw,remount -t auto /system
image.png

执行后,通过 mount | grep /system 查看,很明显有了rw权限。还有就是mount的时候要加上-t auto,不然我手机提示设备繁忙。

再移动用户证书到系统证书:

mv /data/misc/user/0/cacerts-added/* /system/etc/security/cacerts/

执行完后考虑到系统安全,最好改回ro权限:

mount -o ro,remount -t auto /system

验证一下证书是否在系统目录:


image.png

2.2.4 Postern配置

charles配置好后,打开手机的Postern添加一个代理


image.png

名字随便取,地址是电脑的局域网ip,端口是之前设置的socket端口,然后协议选择socks5,保存。


image.png

配置代理规则,添加一个规则。匹配类型是匹配所有地址,动作是通过代理连接,代理组选择刚配置好的代理即可。


de5fc79c353ff91d9a86245bdb29b42.jpg

app设置vpn为charles的代理后,正常情况下会弹出这个提示:


image.png

这样就配置就可以通过vpn抓包的办法去抓包了。

2.3 优点

相较于wifi代理抓包的办法,vpn检测相对较少。而且一次配置终生受益。

2.4 缺点

虽然vpn抓包的方式非常棒,但是也并不是全能的,它也是可以被检测的。

    public void isDeviceInVPN() {
        try {
            List all = Collections.list(NetworkInterface.getNetworkInterfaces());
            for (NetworkInterface nif : all) {
                if (name.equals("tun0") || name.equals("ppp0")) {
                    Log.i("TAG", "isDeviceInVPN  current device is in VPN.");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

可以通过判断网络接口名字包含 ppp0 或 tun0是否有vpn代理,当然也有很多其它的办法进行检测。但是对app进行vpn检测的还是很少,除非是安全性要求较高的app。

并且现在的许多app都开始增加了app抓包的防范,比如说ssl 单向/双向验证,socket协议,某些有实力的大厂自己实现一套协议。

3 客户端ssl验证

在抓https的包的时候我们经常涉及到一个证书的问题,再说这个之前简单的说说http和https:
http是明文传播,易被拦截和修改。
https在HTTP的基础上加了一安全层(SSL或TSL)

这也就引出了我们抓https包的时候,容易遇见的ssl证书问题。

https实际上就是http+ssl。由于http发送的数据直接就是明文。安全性非常差。https会在数据发送前,先用ssl进行加密

客户端ssl验证简单来说就是客户端验证服务端返回的证书,从刚才第一点说的wifi代理抓包的原来来说,如果我们使用了中间人软件来抓包,其实真正请求服务端和响应客户端的是我们抓包软件。这时候客户端验证的是抓包软件的证书,所以肯定验证会失败!

刚好这里有hatch的一个案例,我们通过这个案例来学习如何bypass 客户端的ssl验证。

3.1 案例

该app是波兰某电商app,刚好app客户端验证了服务端的证书。

3.1.1 vpn抓包

先看看我们vpn抓包的表现效果,打开我们的charles和postern。然后打开app进行抓包:

app显示:


image.png

虽然看不懂波兰语,但是大概的意思应该是没有网络连接了

charles显示:


image.png

抓包都是连接失败,请求里面也提示了证书问题:SSL handshake with client failed: An unknown issue occurred processing the certificate (certificate_unknown)

3.1.2 bypass ssl pinning

一般这种情况都是app验证了服务端的证书,服务端验证app证书的app非常少,因为太消耗服务器资源。除了soul之前是双向验证之外(后面新版本好像也取消了双向验证)

这里推介使用frida 的一个bypass 脚本,就是hook掉验证的代码即可:

https://github.com/WooyunDota/DroidSSLUnpinning/blob/master/ObjectionUnpinningPlus/hooks.js

下载这段通用的hook脚本,先启动我们的frida server:

ail@aildeMacBook-Pro ~ % adb shell
hammerhead:/ $ su
hammerhead:/ # cd /data/local/tmp/                                             
hammerhead:/data/local/tmp # ./frs14  

使用spwan的方式hook:

ail@aildeMacBook-Pro ObjectionUnpinningPlus % workon firda14
ERROR: Environment 'firda14' does not exist. Create it with 'mkvirtualenv firda14'.
ail@aildeMacBook-Pro ObjectionUnpinningPlus % workon frida14
(frida14) ail@aildeMacBook-Pro ObjectionUnpinningPlus % frida -U -f pl.allegro -l hooks.js --no-pause
     ____
    / _  |   Frida 14.2.18 - A world-class dynamic instrumentation toolkit
   | (_| |
    > _  |   Commands:
   /_/ |_|       help      -> Displays the help system
   . . . .       object?   -> Display information about 'object'
   . . . .       exit/quit -> Exit
   . . . .
   . . . .   More info at https://frida.re/docs/home/
Spawned `pl.allegro`. Resuming main thread!                             
[Nexus 5::pl.allegro]-> message: {'type': 'send', 'payload': 'Custom, Empty TrustManager ready'} data: None
message: {'type': 'send', 'payload': 'com.squareup.okhttp not found'} data: None
message: {'type': 'send', 'payload': 'registerClass from hostnameVerifier >>>>>>>> Missing implementation for: boolean verify(java.lang.String, javax.net.ssl.SSLSession)'} data: None
message: {'type': 'send', 'payload': 'Xutils hooks not Found'} data: None
message: {'type': 'send', 'payload': 'httpclientandroidlib Hooks not found'} data: None
message: {'type': 'send', 'payload': 'OpenSSLSocketImpl pinning'} data: None
message: {'type': 'send', 'payload': 'Trustkit pinner not found'} data: None
[-] Cronet pinner not found
message: {'type': 'send', 'payload': 'OpenSSLSocketImpl.verifyCertificateChain'} data: None
message: {'type': 'send', 'payload': 'Overriding SSLContext.init() with the custom TrustManager'} data: None
message: {'type': 'send', 'payload': 'Overriding SSLContext.init() with the custom TrustManager'} data: None
message: {'type': 'send', 'payload': 'Overriding SSLContext.init() with the custom TrustManager'} data: None
message: {'type': 'send', 'payload': 'Overriding SSLContext.init() with the custom TrustManager'} data: None
message: {'type': 'send', 'payload': 'Overriding SSLContext.init() with the custom TrustManager'} data: None
message: {'type': 'send', 'payload': 'Overriding SSLContext.init() with the custom TrustManager'} data: None
message: {'type': 'send', 'payload': 'Overriding SSLContext.init() with the custom TrustManager'} data: None
message: {'type': 'send', 'payload': 'OpenSSLSocketImpl.verifyCertificateChain'} data: None
message: {'type': 'send', 'payload': 'OpenSSLSocketImpl.verifyCertificateChain'} data: None
message: {'type': 'send', 'payload': 'OpenSSLSocketImpl.verifyCertificateChain'} data: None
message: {'type': 'send', 'payload': 'OpenSSLSocketImpl.verifyCertificateChain'} data: None
message: {'type': 'send', 'payload': 'OpenSSLSocketImpl.verifyCertificateChain'} data: None

抓包成功:


image.png

当然解决方案不止这一种,我们还可以hook掉加载证书的地方,给证书替换成我们抓包软件的证书就行

4 服务端ssl验证

服务端ssl验证就是服务端验证ssl证书,这时候就需要我们找到app的证书和密码。然后将app中内置的证书导入到Charles中去。

一般通用的找证书的办法就是反编译apk后,直接通过grep搜索p12后缀的文件名。但是一些app会将证书改成jpg或者gif等其它后缀名。这时候我们可以hook app加载证书的地方,输出证书路径和密码。

这时候我们可以使用肉丝巨巨的r0capture,github地址是:

https://github.com/r0ysue/r0capture

r0capture不止提供了证书导出的功能,还提供了非常强大的功能,这里因为我用的比较少后面有机会进行补充。

找到证书后,再charles的Proxy→SSL Proxy Settings→Client Certificates→Add添加新的证书即可。

5 双向验证

双向验证的app太少了,这里没有案例。参考单向的客户端验证和服务端验证的解决方案。只是需要同时解决客户端验证和服务端验证证书的问题。

6 非http协议抓包

现在一些app不走http协议,而选择一些开源的非http协议。比如某手的quic协议和某宝的Spdy协议,默认并不采用传统的http或者https协议。

这种情况下我们如何进行抓包呢?

6.1 某宝抓包

我们以某宝为例,淘宝采用的是Spdy协议,如果要直接去抓这个协议的数据估计要去研究该协议了或者直接hook app构造参数的地方,输出参数内容,避免直接抓包需要研究一个协议带来的时间成本。

但是索性的是不论是某宝还是某手,某团都提供了一个降级成http协议方案,当他们协议使用的服务器无法连接时会采用http协议去连接其他服务器。所以这里就提出来了两个解决方案:

  • iptables 直接干掉所有tcp或者udp这种可疑的协议,使他们被迫降级成http协议
  • hook掉开关,直接让app采用http协议

这里只说hook的方案:


image.png

这里就是它的开关,我们hook后直接返回false就行:

Java.perform(
        function(){
                
                var SwitchConfig_2 = Java.use('mtopsdk.mtop.global.e')
                SwitchConfig_2.d.implementation = function(){
                    return  false
                }
                
                SwitchConfig_2.e.implementation = function(){
                    return  false
                }
                
        }
)

hook后app就会采用http协议了

7 自集成的SSL库

除了使用tcp协议外,现在还有一些有实力的大厂APP基于开源的SSL库,自己集成了一套SSL库。这样我们传统的单向/双向证书解决的方案又行不通了。因为它是自己实现的一套SSL库,和安卓默认的SSL效验的地方肯定不一样。

这里我们就以最新版本的抖音为例。

7.1 最新版的抖音

定位过程参考:https://bbs.pediy.com/thread-269028.htm

你可能感兴趣的:(安卓抓包总结)