疫情当下,口罩难抢啊,没有口罩的我不能出门。在 52 破解上看到了一个口罩查询余量的软件。
软件类似这样子:
我用这软件蹲点抢来好久,也没抢到。于是我寻思着,能不能把这个软件的口罩消息来源给搞到。由于是一枚菜鸡 web 狗,俺也不会逆向。通过 wireshark 来抓请求看看他到底是咋弄的。
看他软件上的提示,是每隔 5s 就请求一次数据。由于 wireshark 抓包的数据是抓这个网卡的全部流量,分析起来比较多。打开 wireshark,抓了一会包就停了没必要太久。不然会很多其他的流量请求。
可以看到居多数给 27.124.36.8 这个 IP 发包,我日还是 https,这可咋整。没有密钥咋解密呢。嗯,虽然解不开数据包,不知道他以什么样子的参数去发送,但是我们能看到服务器的证书信息。
发现了一个 app.tonystark.io
仅仅是找到了服务器的地址,具体的口罩信息的请求方式,我们还是不知道。
从上面 wireshark 的流量,我们可以知道程序与服务器之间的通信是使用 https 来连接,在解密之前我们先来学一下 https 的原理吧。
一、Https 原理学习
https 与 http 相比,仅仅多了一层的 tls:
1. 为什么要加入这一层tls安全层呢?
是因为最初的 HTTP 存在下面三个问题:
- 数据在裸奔。数据以明文的方式传播
- 无法验证通信双方的身份
- 无法防止数据被篡改
我们先来解决第一个问题,如何给数据加密?
- 密码学加密方式只有对称密码和非对称密码
- 对称密码:加密的加密和解密使用同一密钥。
从流程图中得到,这种加密方式在双方通信时候需要预先准备好密钥。但是服务器和浏览器之间传递密钥的过程被人监听,相当于明文传输。倘若预先把密钥保存在本地,到需要建立连接在取出,那么浏览器需要预存好世界上所以的 HTTPS 网站的密钥,显然不现实。
非对称密码:公钥加密,私钥解密
这种加密方式, 也称为非对称密钥加密,使用一对密钥用于加密和解密,分别为公开密钥和私有密钥。公开密钥所有人都可以获得,通信发送方获得接收方的公开密钥之后,就可以使用公开密钥进行加密,接收方收到通信内容后使用私有密钥解密。因为公钥加密,私钥解密,即使传输中的公钥被监听了,也解不开传输的流量。但是仅仅是客户端到服务器这条传输链路保证了传输的安全,那么怎么保证服务端下行到客户端这条链路的安全呢?
HTTPS 采用混合的加密机制,使用公开密钥加密用于传输对称密钥,之后使用对称密钥加密进行通信。
首先 Client 发起想要连接 Server,则会发送 ClientHello,这个 Hello 信息标识就是 Client 最高支持的 TLS 版本,支持的密码套件,Session 信息以及压缩算法。
而 Server 收到 Client 的请求后,会发送与协商确定 Client 的密码套件,同时会发送 Server Certificate 证书信息和服务器公钥。
Client 收到 ServerHello 后,会验证 Server 的证书信息是否合法,如果合法,则产生随机码(这一步又涉及到TLS的密钥计算,太过复杂了,大家有兴趣可以自己去查阅),作为对称密钥加密密钥,对随机码使用接收到的服务器公钥进行加密。
大概的流程图就是这样子,不同的 TLS 版本流程很不一样。
下面我用 wireshark 来抓一次 csdn 的 https 连接请求。
首先先看 ClientHello,TLS 版本信息,Session,以及支持的密码套件
随后的 ServerHello,不难发现选择了 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 的加密方法
可以看到,ServerHello 后面还跟着一个数据包。其中有三个关键字:Certificate 、Certificate Status 、Server Key Exchange
Certificate 就是证书信息:
从数据包可以看出是由 www.digicert.com 签发,并且采用 sha256WithRSAEncryption 进行签名
Certificate Status 则是证书的状态信息,包含证书的有效期至
最后 Server Key Exchange 则是 Server 的 Public Key 了
由于协商出来的是 ECDHE 密钥协商算法 ,所以 Server 把 ECDH 的参数和公钥发给 Client。这里的 ECDH 曲线是 secp256r1,公钥是 047b36092eb10...............
至此 ServerHello 结束。
由于是 ECDHE 协商算法,所以 Client 需要发送 ECC DH 公钥,也有三个关键字:
Client Key Exchange 不必多说,是 Client 发送的 ECCDH 公钥,其值是 04acb6e.....
ChangeCipherSpec 消息结构很简单,发送这条消息是为了告诉 Server ,Client 可以使用 TLS 记录层协议进行密码学保护了。第一条进行密码学保护的消息是 Finished 消息。
后面两个数据包则是流量控制。有助于确保只传播接受者需要使用的数据数据。之后就是新的 session 建立,Server 返回 ChangeCipherSpec 和 finish。这里还有一部分的 TLS 会话复用机制。请读者自行查阅。
目前为止 https 整个连接已经建立起来了。
现在我们已经解决了Https如何给数据加密的过程。
2. 现在来看第二个问题:如何验证通信双方的身份?
在上面的 wireshark 流量分析中,我们可以看到一个 Certificate 的身影。没错, HTTPS 通过使用 证书 来对通信方进行认证。
数字证书认证机构(CA,Certificate Authority)是客户端与服务器双方都可信赖的第三方机构。服务器的运营人员向 CA 提出公开密钥的申请,CA 在判明提出申请者的身份之后,会对已申请的公开密钥做数字签名,然后分配这个已签名的公开密钥,并将该公开密钥放入公开密钥证书后绑定在一起。
进行 HTTPS 通信时,服务器会把证书发送给客户端,客户端取得其中的公开密钥之后,先进行验证,如果验证通过,就可以开始通信。
举个例子
上图中的步骤 1、2、3、4 并不是每次都需要这样请求。1、2、3 步只需要在注册新的公钥的时候才会进行。第四步仅在第一次需要使用公钥密码的时候需要,之后保存到了电脑中,就不用每次都请求公钥了。
网站在使用HTTPS前,需要向“CA机构”申请颁发一份数字证书,数字证书里有证书持有者、证书持有者的公钥等信息,服务器把证书传输给浏览器,浏览器从证书里取公钥就行了,证书就如身份证一样,可以证明“该公钥对应该网站”
二、那么怎么认证数据的完整性?举个例子 :
A 向 B 汇钱 100 万元。如果攻击者从中攻击,篡改这条消息,就可能变成 A 向攻击者汇钱 1000 万元。这里针对汇款消息。如何保证两个问题:消息的 “完整性” 和 “认证” 。
这时候可以用到数字签名技术,相当于现实生活的盖章。数字签名可以识别篡改、伪装、防止抵赖。
非对称密钥是公钥加密,私钥解密。而数字签名是公钥解密,私钥加密。看一个流程
为了防止消息被篡改和被伪造,使用数字签名技术,服务端使用私钥对消息的 hash 进行加密,再把 hash 和签名发送给客户端,随后客户端利用公钥进行解密,比对传输的 hash 是否一致。如果一致就证明消息未被篡改和伪造。
我们都知道,指纹是一个人独一无二的东西,能通过它找他对应的唯一一个人。而消息的指纹就是密码学中的单向散列函数 (Hash)。每一个消息都有其对应的 Hash,如果消息发生了变换,其 hash 也会随之变换。
消息的完整性,就叫消息的一致性,这个可以用消息指纹来判断,通过对比单向散列函数的 hash 值来判断这条消息的完整性,有没有被篡改。
消息的认证,指的是,消息是否来自正确的发送者。如果确认汇款请求确实来自 A,就相当于对消息进行了认证,代表消息没有被伪装。
好了 Https 大概完成了 Http 不曾完成的三个使命。想必看完你也大概了解了 Https 是怎么实现它所说的安全的。
三、怎么才能够对流量进行解密?
网上搜索大多都是两种解法,一种是导入 RSA 私钥进入 wireshark。第二种是配置 SSLKEYLOGFILE。
第一种:导入 RSA 私钥进入 wireshark
实现过程:
1. 拿到百度的服务器证书
使用 fiddler 的中间人代理技术拿到含有私钥的服务器证书。
- 打开 fiddler 并启用 https 代理服务
- 用配置了 fiddler 代理的浏览器访问百度
- 运行 “certmgr.msc”打开证书管理器
- 从 Personal/Certificates 目录下找到 *.baidu.com 的证书,右键所有任务-导出
2、取出证书中的私钥
使用 openssl 取出私钥。
1) 将 pfx 证书转为 pem 证书
命令行:
- openssl pkcs12 -in <pfx证书路径> -nodes -out <输出的pem证书路径(.pem)>
2) 从 pem 证书中取出私钥
命令行:
- openssl rsa -in <pem证书路径> -out <输出的私钥文件路径(.key)>
3) 点击编辑——>首选项——>协议——>SSL(有的版本只有 TLS),导入 RSA key:
导入服务器证书:
点击 ok 后,Wireshark 会对捕获的报文进行解密:
这种方法仅仅对于使用 RSA 的密钥交换有用,在知晓了 RSA 密钥,就可以导入 wireshark 来解密流量。但是目前大多数的 HTTPS 网站都是采用 DH 密钥交换。在此说明一下 RSA 和 DH 的区别。先看这个两个的过程。
ssl_handshake_rsa:
- Client Hello,包含协议版本、客户端 random、密码套件列表
- Server Hello,服务器“hello”消息包含服务器随机、服务器选择的密码套件和服务器的证书
- Client Key Exchange Client 验证证书后,客户端创建一个随机的 pre-master secret。并使用公钥加密发送 之后服务器收到加密的 pre-master secret 会使用私钥进行解密。所以,我们知道私钥,就可以导入 wireshark ,解出 pre-master secret 来解密流量。
ssl_handshake_diffie_hellman:
- Client Hello,包含协议版本、客户端 random、密码套件列表
- Server Hello,服务器“hello”消息包含服务器随机、服务器选择的密码套件和服务器的证书
- Server Key Exchange 紧跟着 Server Hello,为了启动 DH 交换,服务器会发送 Diffie-Hellman 参数和签名
- Client Key Exchange 客户端会验证服务器的证书。然后会向服务器发送 DH 参数。
注:整个过程不存在密钥的交换,客户端服务端可以通过 DH 参数来计算 pre-master secret。
对于这种情况,由于 Premaster Secret 无需交换,中间人就算有私钥也无法获得 Premaster Secret 和 Master Secret。也就是说 Wireshark 无法通过配置 RSA Private Key 的方式解密「使用 ECDHE 进行密钥交换」的加密流量。
第二种 SSLKEYLOGFILE
在系统环境变量加入SSLKEYLOGFILE这个变量,并选择导出目录
Firefox 和 Chrome 都会在系统环境变量存在 SSLKEYLOGFILE 文件路径时,将每个 HTTPS 连接产生的 Premaster Secret 或 Master Secret 存下来。有了这个文件,Wireshark 就可以轻松解密 HTTPS 流量
然后打开 wireshark,ctrl+shift+P 在 Protocols 选择 TLS 协议,并导入即可
即可解除加密
可是这两种对我都没用啊。这个是程序与服务器连接,弄不出来 HTTPS 连接产生的 Premaster Secret 或 Master Secret。而且每次连接的 Secret 都是随机的啊。
下面就要说到另外一种。学安全的大家都知道,burp 在抓取 https 流量的时候,需要信任 burp 的证书。那么大家可想过,这是为何?
burp,Charles,fildder这些抓包工具,主要是利用了中间人攻击的思想,
正常的通信只有 Client,Server。
中间人攻击的时候,加入了一个中间方。Client 信任中间方的证书后,就会和中间方进行通信。然后中间方拿到 Client 发送的请求,就会伪装成 Client 对服务方建立请求。监听双方的通信。
所以只要 Client 信任了 burp 的证书,Client 会和 burp 建立 Https 连接。burp 收到 Client 的请求后,则会去和 Server 建立连接,伪造 Client 通信。
想必看到这里你们脑海中浮现一个疑问:不是说 Https 可以验证通信双方的身份?
是这样子的。Https 有单端验证和双端验证
图片来源:https://www.jianshu.com/p/a2a7ddce7075
一般 Web 应用都是采用 SSL 单向认证的,原因很简单,用户数目广泛,且无需在通讯层对用户身份进行验证,一般都在应用逻辑层来保证用户的合法登入。但如果是企业应用对接,情况就不一样,可能会要求对客户端(相对而言)做身份验证。这时就需要做 SSL 双向认证。
- 客户端向服务端发送SSL协议版本号、加密算法种类、随机数等信息。
- 服务端给客户端返回SSL协议版本号、加密算法种类、随机数等信息,同时也返回服务器端的证书,即公钥证书
- 客户端使用服务端返回的信息验证服务器的合法性,包括:证书是否过期、发型服务器证书的CA是否可靠、返回的公钥是否能正确解开返回证书中的数字签名、 服务器证书上的域名是否和服务器的实际域名相匹配、验证通过后,将继续进行通信,否则,终止通信
- 客户端向服务端发送自己所能支持的对称加密方案,供服务器端进行选择
- 服务器端在客户端提供的加密方案中选择加密程度最高的加密方式。
- 服务器将选择好的加密方案通过明文方式返回给客户端
- 客户端接收到服务端返回的加密方式后,使用该加密方式生成产生随机码,用作通信过程中对称加密的密钥,使用服务端返回的公钥进行加密,将加密后的随机码发送至服务器
- 服务器收到客户端返回的加密信息后,使用自己的私钥进行解密,获取对称加密密钥。在接下来的会话中,服务器和客户端将会使用该密码进行对称加密,保证通信过程中信息的安全。
- 客户端向服务端发送SSL协议版本号、加密算法种类、随机数等信息。
- 服务端给客户端返回SSL协议版本号、加密算法种类、随机数等信息,同时也返回服务器端的证书,即公钥证书
- 客户端使用服务端返回的信息验证服务器的合法性,包括:证书是否过期、发型服务器证书的CA是否可靠、返回的公钥是否能正确解开返回证书中的数字签名、服务器证书上的域名是否和服务器的实际域名相匹配、验证通过后,将继续进行通信,否则,终止通信
- 服务端要求客户端发送客户端的证书,客户端会将自己的证书发送至服务端
- 验证客户端的证书,通过验证后,会获得客户端的公钥
- 客户端向服务端发送自己所能支持的对称加密方案,供服务器端进行选择
- 服务器端在客户端提供的加密方案中选择加密程度最高的加密方式
- 将加密方案通过使用之前获取到的公钥进行加密,返回给客户端
- 客户端收到服务端返回的加密方案密文后,使用自己的私钥进行解密,获取具体加密方式,而后,产生该加密方式的随机码,用作加密过程中的密钥,使用之前从服务端证书中获取到的公钥进行加密后,发送给服务端
- 服务端收到客户端发送的消息后,使用自己的私钥进行解密,获取对称加密的密钥,在接下来的会话中,服务器和客户端将会使用该密码进行对称加密,保证通信过程中信息的安全
工具是:Burp+Proxiey
设置好规则
想要的内容就收到了:
总结
为了抢个口罩也是不容易,硬生生的把 HTTPS 原理给整明白了,学无止境,希望对大家有所帮助。