1. 已有方案
如下 link 告知在 pcap 文件中如何使用 (Pre)-Master-Secret 文件,以及如何把 pcap 和 (Pre)-Master-Secret 文件转为 pcapng文件。
https://wiki.wireshark.org/TLS
如下 link 在国内打不开:
https://gist.github.com/Lekensteyn/f64ba6d6d2c6229d6ec444647979ea24
不过可以搜索到如下 link,应该可以实现同样的功能:
https://github.com/triplewy/quic/blob/master/inject-tls-secrets.py
2. 新的方案
需要提前了解下 pcapng 规范:
PCAP Next Generation (pcapng) Capture File Format
https://github.com/pcapng/pcapng
该方案可以在输入文件的同路径下生成 pcapng 文件:
源码如下:
inject-tls-secrets-by-pcapng.py
# -*- coding: utf-8 -*-
"""
Created on Sat Dec 3 19:31:06 2022
@author: litao
"""
from tkinter import *
from tkinter import ttk
from tkinter import filedialog
from tkinter.scrolledtext import ScrolledText
import binascii
from scapy.all import *
from pcapng import FileWriter
import pcapng.blocks as blocks
from pcapng.structs import (
PacketBytes,
)
@blocks.register_block
class DecryptionSecretsBlock(blocks.SectionMemberBlock):
magic_number = 0x0000000A
__slots__ = []
schema = [
# We don't actually use this field; see _decode()/_encode()
("data", PacketBytes("data"), b""),
]
class GeneratePcapngWithTLSKey:
def __init__(self):
pass
def create_pcapng(self, in_pcap_file, out_pcapng_file, tls_key_file):
out = open(out_pcapng_file, 'wb')
shb = blocks.SectionHeader(
options={
'shb_hardware': 'Any',
'shb_os': 'Any OS',
'shb_userappl': 'Built in TLS password',
}
)
idb_raw = shb.new_member(
blocks.InterfaceDescription,
link_type=101,
snaplen=65535
)
idb_user15 = shb.new_member(
blocks.InterfaceDescription,
link_type=162,
snaplen=65535
)
writer = FileWriter(out, shb)
with open(tls_key_file, 'r') as keys:
dsk = shb.new_member(DecryptionSecretsBlock)
keys_list = [line.strip() for line in keys.readlines() if line.startswith('CLIENT_RANDOM')]
data = bytes('\n'.join(keys_list), encoding='utf-8')
data_len = binascii.a2b_hex(f'{len(data):08x}')[::-1]
data_type = binascii.a2b_hex('544c534b')[::-1]
dsk.data = data_type + data_len + data
writer.write_block(dsk)
packets = rdpcap(in_pcap_file)
for count, packet in enumerate(packets):
blk = shb.new_member(blocks.EnhancedPacket)
blk.interface_id = 0
timestamp_pcap = int(packet.time * 1000000)
blk.timestamp_high = timestamp_pcap >> 32
blk.timestamp_low = timestamp_pcap & 0xFFFFFFFF
blk.packet_data = bytes(packet.payload)
blk.packet_len = len(bytes(packet.payload))
writer.write_block(blk)
out.close()
class UI:
def __init__(self, root):
root.title('Inject TLS Keys v0.1')
root.minsize(960, 508)
mainframe = ttk.Frame(root, padding="3 3 3 3")
mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)
configlf = ttk.Labelframe(mainframe, text='Settings')
configlf.grid(column=0, row=0, ipadx=5, ipady=5,padx=5, pady=5, sticky=(W, E))
mainframe.columnconfigure(0, weight=1)
keyfilelb = ttk.Label(configlf, text='Key File:')
keyfilelb.grid(column=0, row=0, padx=5, sticky=(W, E))
self.keyfileet = ttk.Entry(configlf, width=35)
self.keyfileet.grid(column=1, row=0, padx=5, sticky=(W, E))
self.keyfilebn = ttk.Button(configlf, width=5, text='...', command=self.set_key_file_path)
self.keyfilebn.grid(column=2, row=0, padx=5, sticky=(W, E))
pcapfilelb = ttk.Label(configlf, text='Pcap FIle:')
pcapfilelb.grid(column=0, row=2, padx=5, sticky=(W, E))
self.pcapfileet = ttk.Entry(configlf, width=35)
self.pcapfileet.grid(column=1, row=2, padx=5, sticky=(W, E))
self.pcapfilebn = ttk.Button(configlf, width=5, text='...', command=self.set_pcap_file_path)
self.pcapfilebn.grid(column=2, row=2, padx=5, sticky=(W, E))
configlf.columnconfigure(1, weight=1)
resultlf = ttk.Labelframe(mainframe, text='Result')
resultlf.grid(column=0, row=1, ipadx=5, ipady=5, padx=5, pady=5, sticky=(N, W, E, S))
self.resulttext = ScrolledText(resultlf, font='TkFixedFont')
self.resulttext.grid(column=0, row=0, padx=5, pady=2, sticky=(N, S, E, W))
resultlf.rowconfigure(0, weight=1)
resultlf.columnconfigure(0, weight=1)
mainframe.rowconfigure(1, weight=1)
def set_key_file_path(self):
self.key_file_name = filedialog.askopenfilename()
if os.path.exists(self.key_file_name):
self.keyfileet.delete(0, 'end')
self.keyfileet.insert(0, self.key_file_name)
def set_pcap_file_path(self):
self.pcap_file_name = filedialog.askopenfilename()
print(os.path.splitext(self.pcap_file_name)[0])
print(os.path.splitext(self.pcap_file_name)[1])
if os.path.exists(self.pcap_file_name) and (os.path.splitext(self.pcap_file_name)[-1] in ['.pcap', '.cap']):
self.pcapfileet.delete(0, 'end')
self.pcapfileet.insert(0, self.pcap_file_name)
self.resulttext.delete(1.0,'end')
self.resulttext.insert(1.0, 'Generate pcapng file, please waiting...')
self.resulttext.after(10, self.create_pacpng)
def create_pacpng(self):
gen = GeneratePcapngWithTLSKey()
pcapng_file_name = os.path.splitext(self.pcap_file_name)[0] + '.pcapng'
gen.create_pcapng(self.pcap_file_name, pcapng_file_name, self.key_file_name)
self.resulttext.delete(1.0,'end')
self.resulttext.insert(1.0, 'Generate completed.')
if __name__ == '__main__':
root = Tk()
UI(root)
root.mainloop()
3. 安装软件
https://pypi.org/project/scapy/
pip install scapy
https://pypi.org/project/python-pcapng/
pip install python-pcapng