要想解密https流量方法无非就两种
但由于我并没有去考虑如何用MITM去解密https流量,所以我只介绍我使用密钥解的总结,当然,我并不是通过了解了https的整个过程去自行代码实现的,只是通过别人实现好的模型去进行解密,以下分别使用wireshark和scapy去解密
如果你是客户端角度出发,那么需要获取到ssl/tls通信过程中的随机会话密钥,可以配置sslkeylogfile文件的环境变量,配置后会自动写入环境变量指定的文件中,详细网上自行搜,很多文章都有介绍如何写,也很简单
在配置好环境变量后,还需配置wireshark去进行使用,也自行到网上搜寻
以下方式访问https网站都会写入密钥
openssl(待验证)
可以使用openssl在linux命令行下生成
使用python带的ssl库来进行生成,方法是使用ssl.create_default_context函数即可
Python SSL操作手册
使用chrome和firefox
实际上新版的firefox和chrome并不支持写入SSLKEY了,具体哪个版本支持需自行在网上搜索文章查看
使用curl执行也会写入
使用wireshark可以直接解密所有版本的ssl/tls流量,非常强大
在服务端要是想获取密钥需要进行一些配置,本方法只尝试过apache2和nginx
首先保证服务端具有写SSLKEY密钥功能
先查看配置
libssl-dev/focal-updates,now 1.1.1f-1ubuntu2.16 amd64 [installed]
libssl1.1/focal-updates,now 1.1.1f-1ubuntu2.16 amd64 [installed]
openssl/focal-updates,now 1.1.1f-1ubuntu2.16 amd64 [installed]
确保有libssl的包以及openssl的包,如果直接安装不行,需要考虑吧换软件源或者在官方网站下载相应的包
http://security.ubuntu.com/ubuntu/pool/main/o/openssl/
复制该链接源码sslkeylog.c,粘贴为C文件,编译:cc sslkeylog.c -shared -o libsslkeylog.so -fPIC -ldl
,并将生成的so文件放于/usr/local/lib
配置nginx.service
vim /lib/systemd/system/nginx.service
或者使用命令
systemctl edit nginx
写入
写入内容如下
[Service]
Environment=SSLKEYLOGFILE=/tmp/sslkey.log
Environment=LD_PRELOAD=/usr/local/lib/libsslkeylog.so
最好赋予sslkey.log其用户写入权限
在./nginx/nginx.conf
中添加以下:
env LD_PRELOAD=/usr/local/lib/libsslkeylog.so;
env SSLKEYLOGFILE=/tmp/sslkey.log;
重启nginx
# systemctl daemon-reload
# systemctl restart nginx
最后使用外部curl https://xxx.xxx.xxx
来进行访问,然后查看/tmp/sslkey.log
是否有写入密钥
如若不行,则使用以下命令查看是否有引入libsslkey.so文件,-p参数为nginx的进程号PID
lsof -n -p 10313 |grep ssl
详细请看这篇
Extracting openssl pre-master secret from nginx
如果你使用的是apache,那么也需要配置,需要的话请看这篇文章
Extracting openssl pre-master secret from apache2
然后就可以使用wireshark去解了
这个方式说实话有很大的弊端,虽然可以在代码层面解,但是对于https协议只支持tls1.2以下版本解,tls1.3并不支持,并且最离谱的是只能一次解一个包,真的大无语(而且这方法找了好久,真的无语)
先配置nginx只支持TLS1.2
{
server_name xxx.xxx.com;
listen 443;
ssl on;
access_log /logs/nginx/xxx.xxx.com_access.log main;
error_log /logs/nginx/xxx.xxx.com_error.log;
ssl_certificate /opt/nginx/ssl/xxx.xxx.com.pem; # 公钥证书
ssl_certificate_key /opt/nginx/ssl/xxx.xxx.com.key; # 私钥证书
ssl_session_timeout 5m; # 客户端能够重用会话缓存中ssl参数的过期时间
# 指定支持的协议,这里表示支持1、1.1和1.2, 如果只写1.2表示仅支持1.2. 注:OpenSSL版本要求 >= 1.0.1
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
# 加密套件,多个之间用冒号分隔,前有感叹号的表示必须废弃
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
# 设置协商加密算法,优先使用服务端定义的加密套件
ssl_prefer_server_ciphers on;
}
或者apache2
vim /etc/apache2/sites-available/ssl.conf
## 添加
SSLProtocol ALL -SSLv2 -SSLv3
在python安装scapy库,需要到github原作者处下载(不要使用pip install scapy
)
git clone https://github.com/secdev/scapy.git
进入scapy目录里面执行python3 setup.py install
监听到的pcap包使用scapy去解
参照作者的笔记去写python代码吧
The lack of PFS: a danger to privacy
以下是自己写的垃圾测试代码:
from scapy.all import *
import os
import sys
import binascii
from scapy.layers.tls.record import TLSApplicationData
onesslkeyfile = './sslkey.log'
def method_filter_HTTP(pkt):
if pkt.haslayer(Raw):
pkt.payload.payload.show()
pktdump.write(pkt)
def method_filter_TLS(pkt):
if pkt.haslayer(TLS):
if pkt.haslayer(TLSApplicationData):
pkt[TLSApplicationData].show()
# print(pkt.src)
pktdump.write(pkt)
## pktdump_payload.write(pkt)
## else:
## pkt.payload.payload.show()
def method_save(pkt):
pktdump.write(pkt)
## resolve the tls traffic
## load_layer("http")
port = 80
try:
port = int(sys.argv[1])
except:
pass
if not os.path.exists('sss.pcap'):
pktdump = PcapWriter("sss.pcap", append=True, sync=True)
## pktdump_payload = PcapWriter("sss_payload.pcap", append=True, sync=True)
if port == 443:
print(port)
load_layer("tls")
pkts = sniff(filter=f'tcp and tcp port {port}', prn=method_filter_TLS, iface='eth0')
else:
print(port)
pkts = sniff(filter=f'tcp and tcp port {port}', prn=method_filter_HTTP, store=0, iface='eth0')
## src iZwz9gwr0avfole4msfavlZ
with open(os.getenv('SSLKEYLOGFILE'), 'r') as f:
sslkey = f.readlines()[-1]
data = sslkey.strip().split(" ")
## print('\n', data[1], '---', binascii.unhexlify(data[1]))
f = open(onesslkeyfile, 'w')
f.writelines(sslkey)
f.close()
else:
load_layer("tls")
# config of decrypting a pcap files automationly
# key = PrivKey('raw_data/pki/srv_key.pem')
conf.tls_session_enable = True
conf.tls_nss_filename = onesslkeyfile
## packets = rdpcap("./sss_payload_TLSv1.2.pcap")
pktdump = PcapWriter("sss1.pcap", append=True, sync=True)
packets = sniff(offline='sss.pcap', prn=method_save)
print("==============================================================================================================")
for i in range(len(packets)):
## packets[i].show()
if packets[i].haslayer(TLSApplicationData):
packets[i][TLSApplicationData].show()
## tls = packets[i][TLS].type
## print(tls)
## packets[i][TLS].show()
print("==============================================================================================================")
目前找过的方法有:
wireshark:这个说实话很强大,连tls1.3都可以解,但我需要的是可以使用python\命令行去解的
tshark :此命令在linux下使用,可以解析pcap包并且可以抓包,-o
参数有点可疑,这是在使用pyshark发现的
pyshark:python的库,本质是调用tshark去解析https报文,其中有个FileCapture()函数似乎可以解ssl traffic(override_prefs参数),但也失败了,或许可以继续尝试
How to decrypt TLS Packets using PyShark?
Decrypt SSL packets using PyShark
tcpdump:最常见的抓包工具
ssldump:这个专门用于抓https包,其中的-l,-k和-w,-S,-r参数曾专门研究过,但仍不可解密tls,但确实有文章能解出来,我没有成功,原因未知,其中还有个孪生工具sslsniffer
Decrypting SSL traffic using the SSL::sessionsecret iRules command
Analyzing HTTP/S traffic under Linux
httpry:也是一个抓包工具,但也不无法解析tls包
scapy:python库,和pyshark有点类似,一开始截包也失败了,直到看到原作者secdev写的文章,发现了,使用pip install scapy后发现无效,后来全局访问发现问题,从github下载scapy源文件,使用python setup.py install后,成功解密tls,但只尝试了tls2,tls3是肯定不行的。scapy还有其他的孪生库如scapy-ssl_tls或许今后可以用到
scapy文档
secdev/scapy/notebook
MITM Solution:国外一位小哥和我一样的困扰,在stack overflow求助
Decrypt SSL/TLS with specific Private Key via SCAPY
在了解情况后,貌似MITM也可以解决,原话为
At this time I was solved my problem with NGINX custom logging format and watchdog to detect fast new TLS events for my TCP services Because nginx has MITM ability and if i want to use this solution then its enough...
反向代理,使用nginx作为服务端的反向代理,同时提供http服务,再抓取client到nginx的traffic
nginx配置:
server {
listen *:80;
listen [::]:80;
server_name local.reverse.proxy.com;
location / {
proxy_pass https://www.google.com/;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Real-Port $remote_port;
proxy_set_header Connection "";
proxy_http_version 1.1;
}
}
python的sslkeylog库
https://sslkeylog.readthedocs.io/en/latest/
https://github.com/segevfiner/sslkeylog
https://github.com/tiandrey/nginx-sslkeylog
tls-decryption
JS-or-Python-to-decrypt-TLS-v1.2-https
xmpp-mitm
telepath
dssl
This is the standard, modern TLS 1.2 handshake:
JS-or-Python-to-decrypt-TLS-v1.2-https
xmpp-mitm
telepath
dssl
This is the standard, modern TLS 1.2 handshake: