前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >快手抓包问题分析

快手抓包问题分析

作者头像
mythsman
发布2022-11-14 13:39:56
3.9K0
发布2022-11-14 13:39:56
举报
文章被收录于专栏:mythsman的个人博客

背景

不知从什么版本后,对快手进行简单抓包似乎“不可行”了。表现就是使用常规的 HTTP 正向代理抓包工具(charlesmitmproxyfiddler 之类)并且把自签名证书种到系统证书里后,数据依然能刷出来,也能抓到一些零星的报文,但是关键出数据的那些接口报文都没有。

一般来说,常规方法无法抓安卓应用的 https 包,通常有以下几种可能:

  1. 证书信任问题。在 Android 7 以上,应用会默认不信任用户证书,只信任系统证书,如果配置不得当则是抓不到包的。
  2. 应用配置了 SSL pinning,强制只信任自己的证书。这样一来由于客户端不信任我们种的证书,因此也无法抓包。
  3. 应用使用了纯 TCP 传输私有协议(通常也会套上一层 TLS)。由于甚至都不是 HTTP 协议,当然就抓不到包了。
  4. 应用使用 WebSocket 长链接,将不同的接口封装在这个长链接里。在 WebSocket 里承载的协议一般是用某种自定义方式来模拟 http 请求,因此也难以抓包。
  5. 应用使用了基于 UDP 的 http3.0协议等。大部分代理工具目前还不支持 quic 等协议,所以这样一般是抓不到包的。
  6. 应用配置了 Proxy.NO_PROXY ,强制不走系统代理。这样http流量就绕过我们配置的代理,自然抓不到包。

当前的现象是数据能刷出来,那就说明并不是证书信任相关的问题。接下来就需要验证它究竟是使用了什么样的传输方式,对症下药。

最稳妥的验证方式当然是白盒测试看源码,不过快手反编译的代码看起来也费劲,于是考虑直接当成黑盒来测试看看。以下验证方式均以 快手 8.2.31.17191 版本为例。

分析

环境部署

准备自签名CA证书

需要在 Linux 主机上使用 openssl 工具生成一波证书。当然,这一步可以忽略,直接使用mitmproxy生成的证书。只是手动配置一下能够加深一下对 openssl 的理解。

代码语言:javascript
复制
# 生成RSA私钥 cert.key 
openssl genrsa -out cert.key 2048

# 生成有效期为15年的X509证书 cert.crt(DN信息随便填填似乎都行,但是不能全空)
openssl req -new -x509 -key cert.key -out -days 5480 cert.crt

# 私钥和证书放一起,构成PEM格式的 cert.pem
cat cert.key cert.crt > cert.pem

# 将之前生成的pem证书作为mitmproxy使用的根证书
cp cert.pem ~/.mitmproxy/mitmproxy-ca.pem

# 以普通正向代理模式启动在8000端口,并配合curl简单验证证书可用性
mitmproxy -p 8000 

# 能正常访问没有SSL相关报错,就说明之前生成的自签名证书是OK的
curl -x localhost:8000 --cacert ~/.mitmproxy/mitmproxy-ca.pem https://www.baidu.com

# 从证书文件中计算出用于放置在安卓中的文件hash名,假设结果为 a5176621 
openssl x509 -subject_hash_old -in cert.crt -noout

# 将cert.crt复制出一个上述hash结果的新文件
cp cert.crt a5176621.0

值得注意的是,不要尝试使用 mitmproxy --certs 来配置证书,这种方式只能配置 leaf 证书,而不能配置根 CA 证书。因此还是老老实实的把根证书放在默认路径下。

准备设备

为了方便测试,我在 arm 服务器上使用 redroid 准备了一台安卓虚拟机。

代码语言:javascript
复制
docker run -itd --rm --memory-swappiness=0 \
--privileged --name redroid \
--mount type=bind,source=/home/myths/exp/a5176621.0,target=/system/etc/security/cacerts/a5176621.0 \
-p 5555:5555 \
redroid/redroid:11.0.0-arm64 \
redroid.width=720 \
redroid.height=1280 \
redroid.fps=15 \
redroid.gpu.mode=guest

其中 /home/myths/exp/a5176621.0 替换成实际文件所在路径。

然后在arm主机上用 adb 连接安卓的 tcpip 端口,下载并安装快手 8.2.31.17191 版本。

代码语言:javascript
复制
# 在arm服务器上用adb连接安卓虚拟机
adb connect localhost:5555

# 安装快手
adb install kuaishou.apk

为了方便远程操作,需要在本地机器上连接 arm 服务器上的安卓虚拟机,并用scrcpy操作。

代码语言:javascript
复制
# 在本地主机上连接远程arm服务器上的安卓虚拟机
adb connect <ip for arm server>:5555

# 启动scrcpy
scrcpy

到这一步骤时,可以检测安卓中的网络应该都已经是通的了。

复现抓包问题

先尝试使用传统正向代理的方式进行抓包。

代码语言:javascript
复制
# 在arm服务器上用正向代理启动mitmproxy
mitmproxy -p 8000

# 对安卓设置正向代理,其中 172.17.0.1 为安卓下访问arm主机的ip
adb shell settings put global http_proxy 172.17.0.1:8000

设置完成后,观察手机的网络状况,现象如下:

  1. 使用浏览器访问普通网站,返回均正常,mitmproxy也能抓到包。
  2. 刷快手推荐页,返回也正常,但是mitmproxy只能抓到一些静态资源,无法抓到接口。

Ban掉不走代理的所有流量

有数据但是抓不到包,怀疑应当是有些流量漏掉了,于是尝试把这些流量Ban掉看看效果。

代码语言:javascript
复制
# 首先需要打开内核的 ip_forward 功能
echo 1 > /proc/sys/net/ipv4/ip_forward

# 依然在arm服务器上用正向代理启动mitmproxy
mitmproxy -p 8000

# 继续在手机上配置http代理,其中172.17.0.1为安卓下访问arm主机的ip
adb shell settings put global http_proxy 172.17.0.1:8000

# 在 arm 服务器上配置iptables,将来源于安卓虚拟机但目的地不是arm服务器的流量重定向到一个无用端口。
# 其中 172.17.0.12 位安卓虚拟机的ip,1234为一个无用端口。
sudo iptables -t nat -I PREROUTING -p tcp -s 172.17.0.12 ! -d 172.17.0.1 -j REDIRECT --to-ports 1234
# 如果上述操作报了 Couldn't load match `owner':No such file or directory 的错,那么需要在 arm 服务器上启动下相关模块。
sudo modprobe ipt_owner

# 记得测试完成后,将上面这个记录干掉
iptables -t nat -D PREROUTING 1

设置完成后,观察手机的网络状况,现象如下:

  1. 使用浏览器访问普通网站,返回均正常,mitmproxy也能抓到包。
  2. 刷快手推荐页,显示“无网络连接“。

说明这里的确是有流量漏了,没有走正向代理,但是依然出了外网。

Ban掉不走代理的443/80流量

那么这些流量到底是私有的四层TCP流量、还是没走正向代理的80/443流量呢?因此尝试把非80/443的流量放开试试。

代码语言:javascript
复制
# 依然在arm服务器上用正向代理启动mitmproxy
mitmproxy -p 8000

# 继续在手机上配置http代理
adb shell settings put global http_proxy 172.17.0.1:8000

# 在 arm 服务器上配置iptables,将来源于安卓虚拟机但目的端口不是80/443的流量重定向到一个无用端口。
# 其中 172.17.0.12 位安卓虚拟机的ip,1234为一个无用端口。
sudo iptables -t nat -I PREROUTING -p tcp -s 172.17.0.12  --dport 80 -j REDIRECT --to-ports 1234
sudo iptables -t nat -I PREROUTING -p tcp -s 172.17.0.12  --dport 443 -j REDIRECT --to-ports 1234

# 记得测试完成后,将上面这两条记录干掉
iptables -t nat -D PREROUTING 1
iptables -t nat -D PREROUTING 1

设置完成后,观察手机的网络状况,现象如下:

  1. 使用浏览器访问普通网站,返回均正常,mitmproxy也能抓到包。
  2. 刷快手推荐页,依然显示“无网络连接“。

这就说明,控制快手推荐页的流量并不是所谓私有流量,而就是走的80/443端口,只是没有走正向代理。

改用透明代理模式

既然七层的代理配置会被忽略,那就尝试使用四层的透明代理,将流量强制转到透明代理服务器上即可。

代码语言:javascript
复制
# 在arm服务器上以透明代理模式启动mitmproxy
mitmproxy -p 8000 -m transparent

# 将手机上的http代理移除
adb shell settings put global http_proxy :0

# 在arm服务器上配置将来源于安卓虚拟机的的80/443流量直接路由到mitmproxy
# 其中 172.17.0.12 位安卓虚拟机的ip
sudo iptables -t nat -I PREROUTING -p tcp  -s 172.17.0.12 --dport 80 -j REDIRECT --to-ports 8000
sudo iptables -t nat -I PREROUTING -p tcp  -s 172.17.0.12 --dport 443 -j REDIRECT --to-ports 8000

# 记得测试完成后,将上面这两个记录干掉
iptables -t nat -D PREROUTING 1
iptables -t nat -D PREROUTING 1

设置完成后,观察手机的网络状况,现象如下:

  1. 使用浏览器访问普通网站,返回均正常,mitmproxy也能抓到包。
  2. 刷快手推荐页,能成功刷出,并且mitmproxy也抓到了包。

总结

目前看来,快手并非像很多网上传的那样,大多数接口都走了 kquic 协议导致无法抓包。其实很多接口只是做了一个禁止走系统代理的设置,简单使用透明代理模式进行抓包即可轻松绕过。当然,不排除有些关键接口也做了SSL pinning、走私有协议之类的。。。

参考

https://docs.mitmproxy.org/stable/concepts-certificates/

https://stackoverflow.com/questions/56830858

https://square.github.io/okhttp/4.x/okhttp/okhttp3/-ok-http-client/-builder/proxy/

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • 分析
    • 环境部署
      • 准备自签名CA证书
      • 准备设备
    • 复现抓包问题
      • Ban掉不走代理的所有流量
        • Ban掉不走代理的443/80流量
          • 改用透明代理模式
          • 总结
          • 参考
          相关产品与服务
          容器服务
          腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档