用 tcpdump 和 tshark 分析 wss 流量

需求

用 tcpdump 抓本地所有 wss 流量并得到对应的时间戳和明文

实现

1. SSL Keylog

为了解密 TLS 流量,需要得到每个会话的 keylog

如果 TLS 是自己写的,以 c++ openssl 为例,可以通过 SSL_CTX_set_keylog_callback 设置 keylog 回调,直接将输出的 keylog 写入文件即可。无须维护 keylog 和会话的对应关系。

假设最后得到的 keylog 文件是 keylog,be-like:

CLIENT_RANDOM 1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef 1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
CLIENT_RANDOM 1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef 1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
CLIENT_RANDOM 1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef 1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef

2. 抓包

为了成功解密 TLS 流量,抓到的包必须包含 TLS handshake,所以抓包需要在目标连接建立以前开始

sudo tcpdump -w output.pcap -i any 'tcp port 443 or tcp port 9443'
# run wss client ...

3. 解密

抓包结束后,只要提供 keylog 文件和抓包文件,tshark 会自动解密并输出明文

tshark -r output.pcap -o "tls.keylog_file:./keylog"  -Y websocket -T fields -e frame.time -e websocket.payload.text

遇到的问题

truncated

一开始 tshark -e text 来获取明文,发现 websocket payload 超出 226B 的部分会被截断,并且输出前会展示 [truncated] 或者 [...],原因

解决方法参考 Displaying WebSocket traffic content

  • 使用 -e websocket.payload.text 来获取明文

如果一定要用 -e text,可以改源码里的 ITEM_LABEL_LENGTH,然后从源码编译 tshark

从源码编译 tshark,并修改 ITEM_LABEL_LENGTH

修改 ITEM_LABEL_LENGTH 为 2048:

diff --git a/epan/proto.h b/epan/proto.h
index 0d2a27ee86..42d627c168 100644
--- a/epan/proto.h
+++ b/epan/proto.h
@@ -48,7 +48,7 @@ extern "C" {
 WS_DLL_PUBLIC int hf_text_only;
  
 /** the maximum length of a protocol field string representation */
-#define ITEM_LABEL_LENGTH       240
+#define ITEM_LABEL_LENGTH       2048
  
 #define ITEM_LABEL_UNKNOWN_STR  "Unknown"

编译流程

git clone https://gitlab.com/wireshark/wireshark.git
cd wireshark
# setup, 需要根据系统选择脚本,参考 https://www.wireshark.org/docs/wsdg_html_chunked/ChapterSetup.html
sudo ./tools/rpm-setup.sh 
# 应用修改,假设修改是 patch.diff
git apply patch.diff
# 编译安装
mkdir build && cd build
cmake .. -DBUILD_wireshark=OFF
make && sudo make install