wireshark解析器
问题树
1 |
|
wireshark 加载规则
wireshark页面上的数据包有一部分是加载出来的,很多不是原始包内的数据就是这样的,原始包的数据可以通过导出json查看
对于http协议来说
get模式的数据包正常来讲就是明文传输的,wireshark数据流能看到的基本在json中也可以看到
POST协议可能就会出现差异
这是wireshark中的POST的http数据流的效果
在json中的POST格式是这样的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20"urlencoded-form": {
"Form item: \"ReplySuccessPage\" = \"advanced.htm\"": {
"urlencoded-form.key": "ReplySuccessPage",
"urlencoded-form.value": "advanced.htm"
},
······
"Form item: \"AdminPassword\" = \"63c56363c523637c126363ab636bab63c7c76363232363961263c305639a1263c7c76363232363961263c305639a1263c7c76363232363961263c305639a1263\"": {
"urlencoded-form.key": "AdminPassword",
"urlencoded-form.value": "63c56363c523637c126363ab636bab63c7c76363232363961263c305639a1263c7c76363232363961263c305639a1263c7c76363232363961263c305639a1263"
},
"Form item: \"SessionKey\" = \"1735219692\"": {
"urlencoded-form.key": "SessionKey",
"urlencoded-form.value": "1735219692"
},
"Form item: \"ConfigSystemAdmin\" = \"Apply\"": {
"urlencoded-form.key": "ConfigSystemAdmin",
"urlencoded-form.value": "Apply"
}
}
}
对于非标准通信协议来说
在这个乐高通信协议中倒还是一样
wireshark解析的结果
json导出的结果
似乎目前尚且没有能导出加载器加载后的内容的方法
1 | tshark -r ev3_basic.pklg -X lua_script:ev3_dissector.lua -Y "ev3" -T json > T.json |
这是最接近可能导出加载完加载器之后以json格式导出文件的命令了,但是即便是这样,这个命令导出的json也仍然没有以明文的形式表示EV3 Message
(图片中)那样效果的内容
AI总结
在 Wireshark 界面 | 在导出的 JSON 文件 |
---|---|
分层显示(Frame / Ethernet / IP / TCP / HTTP) | layers 字段下有对应协议名 |
每一层字段人类可读、解释得很清楚 | 每一层字段作为 JSON 键值出现,原始值保存 |
HTTP报文一行一行展开 | HTTP字段拆成单独的 key:value 保存 |
动态解析部分(比如详细参数解释)只在GUI显示 | JSON只保留基本字段,不会包含详细解析描述 |
蓝牙协议学习
蓝牙核心技术概述(四):蓝牙协议规范(HCI、L2CAP、SDP、RFOCMM)-CSDN博客
HCI、L2CAP、SDP、RFCOMM。对比于英特网五层结构来说:HCI相当于与物理层打交道的协议,L2CAP协议则是链路层相关协议,SDP和RFCOMM则是运输层相关协议,当然其上也有对应的应用层相关的一些协议。SDP用来发现周围蓝牙服务,然后由L2CAP来建立信道链接,然后传输由上层RFCOMM给予的数据分组。
wireshark使用加载器
加载器启动分类
命令启动dissector
伴随加载器启动wireshark
1 | wireshark -X lua_script:ev3_dissector.lua |
配置默认启动项, 允许wireshark启动的时候自动加载自定义加载器
1 | bashCopyEdit~/.config/wireshark/init.lua # Linux/macOS |
在里面加入:
1 | dofile("C:\\path\\to\\your\\http_base64_dissector.lua") |
然后你只需要双击 .pcapng
文件,Wireshark 启动就会自动加载这个 dissector!
本题中使用了ev3格式的加载器
https://github.com/ev3dev/lms-hacker-tools/tree/master/EV3
Any packets to or from TCP port 5555 will be interpreted as “EV3” protocol. USB interrupt data with class IF_CLASS_UNKNOWN will also be interpreted as “EV3” protocol.
进出 TCP 端口 5555 的任何数据包都将被解释为“EV3” 协议。类为 IF_CLASS_UNKNOWN 的 USB 中断数据也将被解释为“EV3” 协议。You can also use the filter to search for packets that contain certain types of data. For example if you want to search for all packets that use the
LIST_FILES
system command, then you would useev3.sys_cmd == 0x99
for the filter.
您还可以使用筛选条件来搜索包含某些类型数据的数据包。例如,如果要搜索使用LIST_FILES
system 命令,则使用ev3.sys_cmd == 0x99
作为过滤器。
通过以上方式直接定义出一个EV3的类型(对比没加载器之前)
比如 hitCON CTF'18
的EV3-Basic
题目,实际上使用的蓝牙通信是直接通过16进制来进行传输直接控制机器,机器硬编码了一个映射表,对于传输进去的十六进制会直接变成机器语言执行,但是对于人来说进行wireshark审计就非常不方便, 所以使用加载器(ev3)进行加载,但是实际上并没有改变原来的十六进制实际上的数据包
加载器内对这些用十六进制传输的数据进行了映射,也就是说在使用这个拓展的wireshark打开这个数据包的时候就直接对着相应的数据进行了编码, 让人可以直观的看到是什么意思
翻译前如下:
翻译后如下:
通过对比可以清晰的发现这个Dessector
的作用主要有两个:
- 定义什么是
ev3
协议,并且做出归类标记,方便被过滤 - 按照
ev3
的映射关系进行了翻译
自定义加载器可以解决很多问题 dissector
先从简单出发,假设http包只有一个tcp包就完成
生成过程
这是一个demo,主要的解决问题如下:
能够处理http数据流,处理分片传输的http包(tcp分片)
先使用原生从
http_dissector
进行解析,然后对解析的结果寻找POST Body在进行base64解码以下是拦截监听时候对base64加密http包的处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81-- 定义一个新的 Wireshark 协议 dissector,协议名为 "b64http",显示名为 "HTTP Base64 Inspector"
local b64_proto = Proto("b64http", "HTTP Base64 Inspector")
-- 定义一个供显示用的字段,用于展示解码后的 Base64 内容
local f_decoded = ProtoField.string("b64http.decoded", "Decoded Base64 Content")
-- 把字段绑定到协议中
b64_proto.fields = { f_decoded }
-- 获取已有的 HTTP dissector(内置的 http 协议解析器)
local http_dissector = Dissector.get("http")
-- Base64 解码函数(纯 Lua 实现,无需外部库)
local function decode_b64(data)
local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' -- Base64 字符表
data = data:gsub('[^'..b..'=]', '') -- 移除所有非 Base64 合法字符
return (data:gsub('.', function(x)
if (x == '=') then return '' end -- padding 无需转换
local r,f='',(b:find(x)-1) -- 找到字符对应的索引(0~63)
for i=6,1,-1 do
r=r..(f%2^i - f%2^(i-1) > 0 and '1' or '0') -- 转为6位二进制字符串
end
return r
end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x) -- 每8位转换为1个字节
if (#x ~= 8) then return '' end
local c=0
for i=1,8 do c=c + (x:sub(i,i)=='1' and 2^(8-i) or 0) end
return string.char(c) -- 转成字符
end))
end
-- 主解析函数(每次抓包调用)
function b64_proto.dissector(buffer, pinfo, tree)
pinfo.cols.protocol = "B64HTTP" -- 修改协议列显示名称为 B64HTTP
-- 使用默认 HTTP dissector 先处理 HTTP 协议
http_dissector:call(buffer, pinfo, tree)
-- 如果不是“被访问过”的包(可能是 TCP 片段,还没组装完整),则不处理,避免重复
if not pinfo.visited then return end
-- 将整个 buffer 转为字符串,方便文本匹配
local payload = buffer():string()
-- 从 HTTP 头部提取 Content-Length,用来确认 body 的长度
local content_length = payload:match("Content%-Length: (%d+)")
if not content_length then return end
content_length = tonumber(content_length)
-- 找到 HTTP 头部结束位置(\r\n\r\n)
local header_end = payload:find("\r\n\r\n")
if not header_end then return end
local body_start = header_end + 4 -- body 起始位置
local body_actual_len = #payload - body_start + 1 -- 实际已经收到的 body 长度
-- 如果实际长度不够 Content-Length,说明数据还没收完,需要等待更多 TCP 数据
if body_actual_len < content_length then
pinfo.desegment_len = content_length - body_actual_len -- 告诉 Wireshark 需要继续重组
return
end
-- 提取完整的 body 数据(从 payload 中截取)
local body = payload:sub(body_start, body_start + content_length - 1)
-- 从 JSON 中提取 base64 字符串(假设格式是:"file": "....")
local base64_content = body:match('"file"%s*:%s*"([^"]+)"')
if not base64_content then return end
-- 解码 base64 内容
local decoded = decode_b64(base64_content)
-- 在 Wireshark 界面上添加新的子树显示解析结果
local subtree = tree:add(b64_proto, buffer(), "HTTP Base64 Analysis")
subtree:add(f_decoded, decoded)
end
-- 将 dissector 注册到指定 TCP 端口(这里是 8080,表示监听所有 8080 的 TCP 流量)
local tcp_port = DissectorTable.get("tcp.port")
tcp_port:add(8080, b64_proto)使用python手动生成一个符合这个加载器加载解析base64的数据包
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24from scapy.all import *
from scapy.layers.inet import IP, TCP
from scapy.packet import Raw
# 构造 HTTP POST 请求内容(包含 Base64 编码字段)
http_request = (
"POST /upload HTTP/1.1\r\n"
"Host: example.com\r\n"
"Content-Type: application/json\r\n"
"Content-Length: 28\r\n"
"\r\n"
'{ "file": "SGVsbG8gV29ybGQh" }'
)
# 构造 TCP/IP 包
packet = IP(src="192.168.0.2", dst="192.168.0.1") / \
TCP(sport=12345, dport=8080, flags="PA", seq=1000, ack=1) / \
Raw(load=http_request)
# 保存为 .pcapng 文件
wrpcap("http_base64_example.pcapng", [packet])
print("✅ 流量包已保存为 http_base64_example.pcapng")使用命令打开加载器
1
wireshark -X lua_script:http_base64_dissector.lua
效果展示
没有使用加载器
使用加载器之后就出现了新的一行单独展现数据包的内容
实际上http由多个tcp包完成
启动命令
1 | wireshark -X lua_script:http_base64_split_dissector.lua http_base64_split_example.pcapng |
效果展示
对于多个组成的http POST包直接增加一行进行翻译
使用加载器前
生成过程
由于 Scapy 构造的两个“孤立包”看起来像是 TCP,但 Wireshark 不能对它们做 TCP 重组,所以 HTTP dissector 不会解析出完整 body,自然也不会 Base64 解码逻辑。
也就是说这原来的连个tcp包,他们
- 没有 三次握手(SYN/SYN-ACK/ACK)
- 没有 TCP 连接状态管理
- 没有 ACK 回包
- Wireshark不会认为这两个包属于同一个 TCP 流,无法做重组!
所以需要使用抓包监听来获取真实的流量数据而不仅仅是模拟
使用flask起一个服务,不可以使用
python -m http.server 8080
因为只可以接受GET请求,但是问题是现在要的就是POST请求1
2
3
4
5
6
7
8
9
10
11
12from flask import Flask, request
app = Flask(__name__)
def upload():
data = request.get_json()
print("收到数据:", data)
return "OK"
if __name__ == '__main__':
app.run(port=8080)使用curl或者requests进行发包,这里选择的是requests
1
2
3
4
5
6
7import requests
import base64
data = {
"file": base64.b64encode(b"Hello World!").decode()
}
requests.post("http://127.0.0.1:8080/upload", json=data)使用wireshark监听回环地址
直接保存为
http_base64_split_example.pcapng
构建解析器
这种 dissector 不会取代 HTTP 协议本身,但能在 GUI 中添加额外显示内容
如果加入以下命令可以看到lua console
弹出的消息
1 | function b64_post.dissector(buffer, pinfo, tree) |
1 | -- 定义一个新的后解析器(post-dissector)协议,名称为 "b64post",描述为 "Base64 Post Dissector" |
这是专门针对json做的优化,由于base64数据是包含在json中发送的,所以需要去解析这个json获取base64编码的密文来进行解码
1 | local json_value = Field.new("json.value.string") |
增强版解析器
为了支持多层嵌套和多个字段的 Base64 解码,可以将原脚本扩展为以下功能:
- 遍历所有
json.value.string
字段; - 对每个字段尝试 base64 解码;
- 显示每一个成功解码的内容;
- 同样使用当前的 base64 解码函数。
下面是改进后的完整脚本:
1 | -- 定义协议和字段 |
加载器无法运用在http跟踪流的窗口!
Wireshark 中的“跟踪流(Follow Stream)”功能是原始 TCP 字节流的重建视图,它展示的是通信双方“看到”的原始数据,不经过 dissector 插件处理(也就是说,不调用 dissector()
函数)。这是设计上的决策,目的是让用户看到协议最原始的内容(用于取证、协议逆向等)
wireshark各类端口过滤命令
1 | tcp.dstport == 1234 过滤目标端口 |
数据包标号:Frame Number