HTTPS网络流量解密方法探索系列1

前言

分析网络流量总是绕不开HTTPS,因其广泛使用甚至是强制使用逐渐被大众熟知,在保证其安全的同时也提高了对流量进行研究的难度。目前解析HTTPS协议的文章很多,有很多不错的文章可以带着入门,老实说,HTTPS协议还是挺复杂的,尤其是握手交换密钥的过程;虽然大部分的文章只是对协议握手的过程做了详细的解析,却很少涉及HTTPS网络数据包解密的部分,因此,本文即是从数据包层面,在知道私钥的情况下,来一步一步看如何对HTTPS的内容进行解密。

正文

要对HTTPS网络数据包进行解密,其实是有一些工具是可以使用的,比如wireshark和ssldump,现在,先让我们来看看这两款工具如何使用。

一、wireshark解密HTTPS数据包

首先是wireshark,在wireshark界面上方,依次点击编辑->首选项

再点击Protocols找到SSL,并进行必要配置。

先是对RSA keys list进行编辑,点击Edit完成配置,如下所示。

点击加号,依次配置(服务器IP、目的端口、应用层协议、私钥路径)。然后对SSL debug file进行配置,在这里面,wireshark会打印出解密过程中的调试信息,非常有用,后文在进行手动解密的时候即是通过它发现的错误,按照前文配置到一个路径下,配置完成点击ok后,可在wireshark主界面解密出通信内容。

ssldump是一款Linux下的小工具,可直接用apt包管理工具安装,目前最新版本是ssldump0.9b3(13年后就停止更新了。可以下载源码)。在shell中运行:

ssldump -Ad -k./private.pem -r ./ssl.pcap

该条命令会打印出部分的解密过程,如下图所示。

从该图中可以看到client/server产生的随机数(random),加密的预主密码(EncryptedPremaster secret),以及用到的加密套件:

TLS_RSA_WITH_AES_256_CBC_SHA

表示采用RSA进行身份认证和对称密钥交换,采用AES 256位对称加密算法,加密模式为CBC,采用SHA进行消息认证。虽然工具已经解出了HTTP的请求内容,但是打印信息中未打印出解密后的主密码和对称密钥,因此,打印信息没有完整反映解密过程,这款工具在centos下还会出现coredumped,不是十分好用,不如自己写一个。

二、HTTPS协议简介

虽然已经有不少的帖子非常详细地介绍了HTTPS协议,但是本文依然选择简单介绍一下HTTPS协议,主要侧重于对解密中要用到的参数进行说明。如下图所示,为HTTPS完整握手的流程图。

(图片来源:https://juejin.im/post/5b88a93df265da43231f1451)

图中完整地反映了HTTPS的握手过程,在此过程中,Client会同Server交互若干参数来协商对称密钥,用来对应用数据进行加密。这里笔者以TLS_RSA_WITH_AES_256_CBC_SHA这个密码套件为例,讲述在这个密码套件下交换的参数。解密过程需用到:

1. clientrandom客户端随机数

2. serverrandom服务器随机数

3. EncryptedPreMaster加密的预备主密码

解密的过程大致为:先用私钥对EncryptedPreMaster进行解密,得到decryptedPreMaster;再用clientrandom、serverrandom、decryptedPreMaster得到MasterSecret;再用MasterSecret计算出消息认证密钥、数据加密对称密钥和CSC模式用到的初始化向量值,得到密钥后即可对通信内容进行解密了。看似过程很简单,实际上只有自己操作一把才知道坑在哪里。

三、HTTPS网络数据包手动解密

在解密之前,需要说明的是,并不需要自己写解密代码来完成数据的解密,有很多好用的工具可以完成这件事。本文中所使用的解密工具为openssl,很强大的工具,非对称加解密和对称加解密用起来相当方便。

实验准备:本文的流量样本采用的TLS1.0版本,虽然目前主流是用TLS1.2,但是这两个版本差别不大,弄懂了前者,后者也是很好理解的,流程稍作改动也能解密;以学习为目的,从1.0开始是一个不错的选择。本文流量的加密套件采用RSA非对称加密交换对称密钥参数,采用AES256对通信流量进行加密。所有的实验材料已上传到github(https://github.com/scu-igroup/https_packets_decrypt)中。

那就正式开始吧,首先是在数据包中将clientrandom,serverrandom和EncryptedPreMaster的二进制数据提取出来。如下图所示,在wireshark中分别找到clienthello、serverhello、clientkey exchange数据包,选择要导出的字段,点击鼠标右键,选择导出分组字节流,存成bin文件,分别为client_random.bin、server_random.bin、premaster-encrypted.bin。

在Ubuntu中查看结果,这三个二进制文件的内容分别为:

首先,是对premaster-encrypted.bin进行解密。利用已获得的私钥private.pem进行解密,解密命令为:

openssl pkeyutl -decrypt -in ./premaster-encrypted.bin -inkey ./private.pem -outpremaster-decrypted.bin

如未报错,代表执行成功,将解密的数据存入到premaster-decrypted.bin文件中,用hexdump可查看。

就得到解密后的预备主密码,对密码专家来说,得到预备主密码跟最后一步解密内容是等价的。但对于我们来说,还有几步要折腾。

下一步,即是利用预备主密码计算主密码,在此过程中,还需利用clientrandom和serverrandom,用命令将client_random.bin,server_random.bin两个文件合并起来。

cat client_random.binserver_random.bin > random_cs.bin

用hexdump查看有如下结果:

然后用伪随机函数计算(PRF)计算主密码,伪随机函数计算程序需在windows下运行,命令如下。

.\PRF.exe--label "master secret" --length 48 --secret .\premaster-decrypted.bin--data .\random_cs.bin --outputmaster-secret.bin

PRF.exe为网上分享的计算程序,源程序见这里,本文的github中已作分享。利用这款程序就可得到主密码文件master-secret.bin,用hedump查看为:

这种计算主密钥的方法存在漏洞,在TLS1.2版本中已做调整。接下来,就可以利用主密码算加密传输数据的对称密钥和其他参数了。在解密之前,需要用先生成random_sc.bin,如下:

cat server_random.bin client_random.bin > random_sc.bin

与上一个文件不同的是clientrandom和serverrandom的顺序不一样,得到random_sc.bin。然后,同样在windows下运行,命令如下:

.\PRF.exe--secret .\master-secret.bin --label "key expansion" --data.\random_sc.bin -n 136 -o key-expansion.bin

得到key-expansion.bin文件,用hexdump查看为:

这样利用主密码生成了6种信息,分别是:

20字节的消息认证码密钥(客户端→服务器)

20字节的消息认证码的密钥(服务器→客户端)

32字节的对称密码密钥(客户端→服务器)

32字节的对称密码的密钥(服务器→客户端)

16字节的对称密码的CBC模式所使用的初始化向量(客户端→服务器)

16字节的对称密码的CBC模式所使用的初始化向量(服务器→客户端)

字节数加起来刚好同key-expansion.bin文件的字节数吻合,在此,就得到了对称加密时所使用的密钥。客户端到服务器的密钥为:

我们就可以用它来解密客户端到服务器的应用数据内容。在正式解密前,我们先按照上述方法将客户端到服务端的应用层数据提取成二进制文件,为client-request.bin,然后用如下命令进行解密。

openssl enc-aes-256-cbc -d -K $cs_key -iv $iv_value -in .\client-request.bin -out.\client-request-decrypted.bin

其中,$cs_key为客户端到服务器传送消息的密钥,iv为上一个消息中最后一个分组的值,iv的值仅凭这句话,不太好找,我也是试出来的。如下图所示。

第24个数据包为要解密的内容,上一个消息指的是客户端到服务器方向的上一个消息,为第20个包,最后一个分组的值为该数据包最后16位数,如下图所示。

iv就是: ed605d761378241c7add3c921022b268。得到iv就可执行解密命令,并将解密内容存在client-request-decrypted.bin文件中,用hexdump和cat查看:

顺利解出HTTP协议的请求内容,最后有一段乱码,那是HMAC的值,做消息认证用,感兴趣的朋友可以自己去看怎么认证,这里只解出明文数据就行了。对于服务器到客户端的消息,也采用同样的方法,也可以解出来。

大家照着这个流程可以很快地复现出来,但笔者在此过程中踩过很多坑,有时也不知道哪一步错了,只要任何一部出错,后面的都不对。要解决调试问题,wireshark的debug文件很有用,里面把每一步需要计算的参数都打印出来了,如下图所示。

在手动计算的过程中,可对照着这个结果,查看哪一步算错了,可以帮助你快速定位到问题。

既然手动能解出来,那下一步就是自动化实现了,这也不难,openssl提供有C和Python开发库,复杂的密码算法不用我们来实现,调用API函数即可实现。在以后的系列篇中,即是完成自动解析脚本,以及加上对TLS1.2的支持。

总结

HTTPS协议是比较复杂的一个协议,要想学习它,光看它的技术原理是不得要领的,本文也是在笔者对它学习的过程中产生,手动解一下使用它交互的数据包是很有趣的,也能加强对它的理解。其中关于数字证书验证和消息认证本文没有涉及,得靠读者自己去专研啦。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20181218G1MEOX00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券