APP抓包小记

https://blog.csdn.net/l331258747/article/details/128233881 抓包原文在这里

在一次偶然的机会,看到了抓包抖音app的文章,记得以前抓包很简单,没有现在这么复杂,所以学习一下。(一篇超级水的水文)

SSL/TLS协议

首先介绍一下SSL/TLS,TLS和SSL是什么?为什么有人把这两个协议混为一谈?

​ 安全套接字层(SSL)是一种通信协议或一组规则,用于在网络上的两个设备或应用程序之间创建安全连接。在通过互联网共享凭证或数据之前,建立信任并对另一方进行身份验证非常重要。SSL 是一种技术,您的应用程序或浏览器可能使用该技术在任何网络上创建安全的加密通信通道。但是,SSL 是一种较老的技术,包含一些安全漏洞。传输层安全性协议(TLS)是 SSL 的升级版本,用于修复现有 SSL 漏洞。TLS 可以更高效地进行身份验证,并继续支持加密的通信通道。

​ SSL 和 TLS 都是通信协议,用于加密服务器、应用程序、用户和系统之间的数据。这两种协议都会对通过网络连接的双方进行身份验证,以便他们能安全交换数据。

​ Taher Elgamal 领导了 SSL 的开发,并于 1995 年公开发布了 SSL 2.0。SSL 旨在确保万维网上的通信安全。在 SSL 经历多次迭代后,Tim Dierks 和 Christopher Allen 于 1999 年创建了 TLS 1.0,作为 SSL 3.0 的后继者。

为什么要用TLS协议呢?这个协议解决了哪些问题?

​ TLS 是一种支持加密和身份验证的安全通信协议,SSL 在被弃用之前也是如此。TLS 和 SSL 都使用数字证书来简化握手过程并在浏览器和 Web 服务器之间建立加密通信。

​ 超文本传输协议(HTTP)是用于客户端-服务器通信的协议或一组通信规则。当您访问网站时,您的浏览器会向 Web 服务器发送 HTTP 请求,该服务器将以 HTTP 响应进行响应。Web 服务器将以纯文本形式与您的浏览器交换数据。简而言之,HTTP 协议是为网络通信提供支持的底层技术。顾名思义,安全超文本传输协议(HTTPS)是 HTTP 的一种更安全的版本或扩展。在 HTTPS 中,浏览器与服务器会在传输数据之前建立安全的加密连接。

​ 简单来说,HTTPS=HTTP+TLS,传输还是用HTTP协议传输,但是报文的内容不再是以前的明文传输,而是改为了加密后的内容。即使有人在中途获取了你发送的HTTP请求报文,没有密钥也无法解密看到明文内容。TLS协议就是客户端和服务端协商密钥的协议。

TLS/SSL协议工作原理

写在前面:如果下面的内容看不懂,移步:https://www.bilibili.com/video/BV1KY411x7Jp/,下面的图片就是从该视频中截出来的

本节参考文章:https://www.biaodianfu.com/https-ssl-tls.html 以下内容比较通俗易懂,很多技术细节没有讲到,有想要详细了解的可以点开这个链接去深入了解,或者直接去看RFC-TLS官方文档:https://datatracker.ietf.org/doc/html/rfc5246

客户端和服务端要建立TCP连接之后才能进行如下会话:image-20240108145402225

我用Wireshark抓包vivo.com 为例子演示:

image-20240108153532074

Client Hello

握手第一步是客户端向服务端发送 Client Hello 消息,这个消息里包含了一个客户端生成的随机数 Random1、客户端支持的加密套件(Support Ciphers)和 SSL Version 等信息。

Client Hello中涉及到的消息具体如下:

image-20240108153622210

  • 客户端版本:按优先级列出客户端支持的协议版本,首选客户端希望支持的最新协议版本。
  • 客户端随机数Random
  • 会话ID(Session id):如果客户端第一次连接到服务器,那么这个字段就会保持为空。上图中该字段为空,说明这是第一次连接到服务器。如果该字段不为空,说明以前是与服务器有连接的,在此期间,服务器将使用Session ID映射对称密钥,并将Session ID存储在客户端浏览器中,为映射设置一个时间限。如果浏览器将来连接到同一台服务器(在时间到期之前),它将发送Session ID,服务器将对映射的Session ID进行验证,并使用以前用过的对称密钥来恢复Session,这种情况下不需要完全握手。也叫作SSL会话恢复。
  • 加密套件:客户端会给服务器发送自己已经知道的密码套件列表,这是由客户按优先级排列的,但完全由服务器来决定发送与否。TLS中使用的密码套件有一种标准格式。上面的报文中,客户端发送了74套加密套件。服务端会从中选出一种来作为双方共同的加密套件。
  • 压缩方法:为了减少带宽,可以进行压缩。但从成功攻击TLS的事例中来看,其中使用压缩时的攻击可以捕获到用HTTP头发送的参数,这个攻击可以劫持Cookie,这个漏洞我们称为CRIME。从TLS 1.3开始,协议就禁用了TLS压缩。
  • 扩展包:其他参数(如服务器名称,填充,支持的签名算法等)可以作为扩展名使用。

ServerHello

image-20240108153748732

​ 收到客户端问候之后服务器必须发送服务器问候信息,服务器会检查指定诸如TLS版本和算法的客户端问候的条件,如果服务器接受并支持所有条件,它将发送其证书以及其他详细信息,否则,服务器将发送握手失败消息。

​ Server Hello会从Client Hello 传过来的 Support Ciphers 里确定一份加密套件,这个套件决定了后续加密和生成摘要时具体使用哪些算法,另外还会生成一份随机数 Random2。注意,至此客户端和服务端都拥有了两个随机数(Random1+ Random2),这两个随机数会在后续生成对称秘钥时用到。

ServerHello中涉及到的具体参数:

  • 服务器版本Version:服务器会选择客户端支持的最新版本。
  • 服务器随机数Random:服务器和客户端都会生成32字节的随机数。用来创建加密密钥。
  • 加密套件:服务器会从客户端发送的加密套件列表中选出一个加密套件。
  • 会话ID(Session ID):服务器将约定的Session参数存储在TLS缓存中,并生成与其对应的Session id。它与Server Hello一起发送到客户端。客户端可以写入约定的参数到此Session id,并给定到期时间。客户端将在Client Hello中包含此id。如果客户端在此到期时间之前再次连接到服务器,则服务器可以检查与Session id对应的缓存参数,并重用它们而无需完全握手。这非常有用,因为服务器和客户端都可以节省大量的计算成本。在涉及亚马逊和谷歌等流量巨大的应用程序时,这种方法存在缺点。每天都有数百万人连接到服务器,服务器必须使用Session密钥保留所有Session参数的TLS缓存。这是一个巨大的开销。为了解决这个问题,在扩展包里加入了Session Tickets, 在这里,客户端可以在client hello中指定它是否支持Session Ticket。然后,服务器将创建一个新的会话票证(Session Ticket),并使用只有服务器知道的经过私钥加密的Session参数。它将存储在客户端上,因此所有Session数据仅存储在客户端计算机上,但Ticket仍然是安全的,因为该密钥只有服务器知道。此数据可以作为名为Session Ticket的扩展包含在Client Hello中。在TLS 1.2中才用的就是Session Ticket机制。
  • 压缩算法:如果支持,服务器将同意客户端的首选压缩方法。
  • 扩展包

Certificate, Server Key Exchange, Server Hello Done

image-20240108154733754

Certificate

服务端将自己的证书下发给客户端,让客户端验证自己的身份,客户端验证通过后取出证书中的公钥。这些SSL证书是通过CA证书机构签名认证过的证书,所谓的签名就是首先对证书进行hash计算,然后用CA根证书的私钥加密之后保存在证书里,客户端是默认信任CA根证书(系统级别),根证书中就有公钥,通过公钥解密得到证书的hash,然后客户端自己再对证书进行hash计算,比对这两个hash是否相同,这样就可以验证证书的真伪。其实这里也会导致 问题,会导致MITM攻击(中间人攻击)。

image-20240108155358023

Server Key Exchange(可选)

image-20240108160827255

根据之前在ClientHello消息中包含的CipherSuite信息,决定了密钥交换方式(例如RSA或者DH),因此在Server Key Exchange消息中便会包含完成密钥交换所需的一系列参数。

Server Hello Done

image-20240108160924580

该消息表示服务器已经将所有信息发送完毕,接下来等待客户端的消息。

Client Key Exchange, Change Cipher Spec, Encrypted Handshake Message

Client Key exchange

根据之前从服务器端收到的随机数,按照不同的密钥交换算法,算出一个pre-master,发送给服务器,服务器端收到pre-master算出main master。而客户端当然也能自己通过pre-master算出main master。如此以来双方就算出了对称密钥。pre-master 应该是预主密钥,这里的预备主密钥是通过公钥加密过的,服务器端可以根据私钥解密出来。

image-20240108161819959

Change Cipher Spec :客户端发送消息告诉服务器更改为加密模式。告诉服务器下面的消息是加密过的。

image-20240108162121118

Encrypted handshake message是使用对称秘钥进行加密的第一个报文,供客户端和服务端去验证是否能够通过计算出来的这个主密钥去解密出这个message

image-20240108162153460

New Session Ticket, Change Cipher Spec, Encrypted Handshake Message

Session Ticket: 加密后的session status信息,包含了master key,以及cipher suite,这些信息会被用来生成新的session key,保证前向安全。同时这个信息只有服务器才能解密。

Session Ticket LIfetime Hint: 保存时间指示,当时间到期时,客户端必须删除该ticket。

image-20240108163919666

下面的内容和之前的内容一样,服务端给客户端发送加密Message,看客户端是否能够恢复Message

image-20240108164837846

如果双方都恢复成功,就可以进入加密通话了。

MITM攻击

类似于burp之类的工具可以直接抓到HTTPS的明文,使用的就是MITM攻击,我简单叙述一下原理。

​ 首先我们在抓包https之前都会有一个操作去信任一个burp的内置证书,这个证书其实就是根证书,根证书首先是自签名的,对于信任的根证书所签发的所有证书系统都是信任的,这就导致可以伪造证书。举个简单的例子,首先我们在系统上安装了burp的内置证书,当访问baidu.com的时候,burp会在与baidu.com TLS 握手的时候将baidu.com发回来的证书替换为自己根证书签名过的证书,然后burp获取了baidu.com的真实证书,就可以伪造下次握手的内容,代替客户端与其通话,客户端用伪造的证书发的报文burp也可以解密,之后再用正确的证书加密发送给baidu.com服务器,这样就完成了中间人攻击。

SSL pinning

HTTPS当下已经非常普遍,HTTPS全称是Hypertext Transfer Protocol Secure,在HTTP基础上增加了TLS加密,虽然名字里有个Secure,但HTTPS并不是绝对安全的,依然存在被中间人攻击(Man-in-the-middle attack)的风险,进而导致应用被抓包,HTTPS的加密流量被获取。

所以客户端提供了一种额外的机制来保证HTTPS通信的安全,SSL Pinning,SSL Pinning又可以细分为Certificate Pinning和Public Key Pinning。

Certificate Pinning

证书锁定:比如一些客户端会将自己的证书也打包进安装包,在客户端与服务端通信时,客户端会对服务端返回来的证书进行检测,如果与安装包打包的证书不一致时就会停止通信。

Public Key Pinning

公钥锁定:就是可以在配置文件中配置了公钥,证书更新时公钥和算法是可以保持不变的,Public Key Pinning主要是为了防止证书更新带来的不便。

android抓包环境配置

首先下载一款模拟器软件,这里使用的是雷神模拟器,当然也可以选择其他模拟器,我这里因为雷电模拟器配置的android可以选择桥接的网卡,所以选择了雷电模拟器。下载地址:https://www.ldmnq.com/,我这里直接就用android 9了。一定要保证模拟器和你的windows在同一网段下

image-20240108193333078

image-20240108190958434

android7.0+

我是用的fiddler抓包,fiddler默认导出的证书然后访问对应的端口下载证书并安装,这里就不详细去说了

在android系统中内置的系统证书是默认信任的,而用户导入的证书是不信任的。用户导入的证书会被重命名为证书hash.0 前面的数字是证书的hash的一部分,可能是为了防止证书名字重复

用户默认安装的证书位置:/data/misc/user/0/cacerts-added/

系统证书的安装位置:/system/etc/security/cacerts/

首先在安卓7.0之后默认不信任用户的证书,所以应该将证书拖到系统的目录,中间可能会出现read only权限错误,解决方法如下:

1
2
adb root
adb remount

adb remount就是将 system目录部分置于可写入的模式。

image-20240106153739805

最后重启模拟器就行,之后就可以看到证书已经被导入进来了

image-20240106153529687

对于一些简单的APP可以安装Magisk+LSPosed+TrustMeAlready进行绕过,TrustMeAlready应该是屏蔽掉ssl证书校验的步骤了。但是实际测试dy确实不行,还是无法抓到内容,对于低版本的dy是可以抓到包的。

https://github.com/ViRb3/TrustMeAlready

An Xposed module to disable SSL verification and pinning on Android using the excellent technique provided by Mattia Vinci. The effect is system-wide.

dy历史版本下载可以到豌豆荚中找,测试版本为23.3.0

雷电模拟器在安装的位置会内置adb,用adb把安装后的文件pull下来

1
2
3
adb devices # 查看当前主机所连接的设备
adb -s 你的设备名字 root
adb -s 你的设备名字 pull /data/app/com.ss.android.ugc.aweme-pEmEAiO82FVGhuVi5epAHw==/lib/arm64/libsscronet.so ./

image-20240108194257430

然后在当前目录下就会有这个文件,之后用IDA打开这个文件,之后的操作步骤如下,我就不复制了

https://blog.csdn.net/l331258747/article/details/128233881

修改过后再adb push 进去就ok了

1
2
3
4
5
6
adb devices # 查看当前主机所连接的设备
adb -s 你的设备名字 root
adb -s 你的设备名字 shell
rm /data/app/com.ss.android.ugc.aweme-pEmEAiO82FVGhuVi5epAHw==/lib/arm64/libsscronet.so
exit
adb -s 你的设备名字 push ./修改过后so的名字 /data/app/com.ss.android.ugc.aweme-pEmEAiO82FVGhuVi5epAHw==/lib/arm64/libsscronet.so

我自己在复现的时候,发现dy23.3.0的so文件不是32位的,而是64位的,可能跟模拟器有关系。总结一下就是该so文件中包含了ssl证书检测相关函数,因为是在本地检测,我可以通过修改so文件某些函数的返回值去绕过证书检测,具体的修改过程就不贴了,一方面不知道这东西能不能贴,其次就是自己没有仔细去分析,直接贴别人的成果不太好。

实测最新版的dy也可以直接抓到,但是不能登录账号否则就会给你发短信,说账号锁定了,应该是检测了某些东西,因为没有相关APK逆向知识,所以这里也无法继续分析下去了,感觉很有意思,等之后如果弄明白回来更新这篇文章。

image-20240108212026082

抓包结果如图:

image-20240108205347228