Wireshark
提供了一种显示过滤器语言,使能够以精确控制显示哪些数据包。它们可以使用检查协议或字段是否存在、字段的值或甚至将两个字段相互比较。这些比较可以组合在一起使用逻辑运算符,如“and”和“or”
,以及括号变成复杂的表达式。
以下部分将介绍显示过滤器的功能更多细节。
1.显示过滤器字段
最简单的显示筛选器是显示单个协议的筛选器。要仅显示包含特定协议的数据包,请键入协议 进入Wireshark
的显示过滤器工具栏。例如,仅显示TCP
数据包,在Wireshark
的显示过滤器工具栏中键入tcp。同样,仅显示 包含特定字段的数据包,键入该字段 进入Wireshark
的显示过滤器工具栏。例如,仅显示HTTP
请求,在Wireshark
的显示过滤器工具栏中键入http.request。
我们可以过滤Wireshark
支持的任何协议。如果剖析器添加到树视图的任何字段,则还可以筛选为该字段添加了缩写。可用协议的完整列表和字段可通过菜单项点击:视图→内部→Supported Protocols获得。
2.比较值
我们可以构建显示筛选器,使用多个不同的比较运算符。比如,仅显示数据包发往或从IP地址113.240.75.252,可以用下面的过滤表达式:
ip.addr==113.240.75.252
常用的显示筛选器比较运算符如下表所示:
英文 | 别名 | 符号 | 描述 | 示例 |
---|---|---|---|---|
eq |
any_eq |
== | 相等(如果超过一个,则为任意) | ip.src == 10.0.0.5 |
ne |
all_ne |
!= | 不相等(如果多个,则全部相等) | ip.src != 10.0.0.5 |
all_eq |
=== | 相等(如果有多个,则全部相等) | ip.src === 10.0.0.5 |
|
any_ne |
!== | 不相等(如果超过一个,则不等于) | ip.src !== 10.0.0.5 |
|
gt |
> | 大于 | frame.len > 10 |
|
lt |
< | 小于 | frame.len < 128 |
|
ge |
>= | 大于或等于 | frame.len ge 0x100 |
|
le |
<= | 小于或等于 | frame.len <= 0x20 |
|
contains |
协议、字段或切片包含值 | sip.To contains "a1762" |
||
matches |
~ | 协议或文本字段与 Perl 兼容的正则表达式匹配 | `http.host matches "acme.(org |
2.1显示过滤器字段类型
2.1.1无符号整数
它们可以是8、16、24、32 或 64 位
。可以用十进制、八进制、 十六进制或二进制。
以下显示筛选器是等效的:
ip.len le 1500
ip.len le 02734
ip.len le 0x5dc
ip.len le 0b10111011100
如上2个图,它们过滤显示是一样的,也就是表达式等效。
2.1.2有符号整数
它们可以是 8、16、24、32 或 64 位
。与无符号整数一样,可以使用十进制、八进制、十六进制或二进制。
2.1.3布尔
可以是 1 或“True”、0 或“False”(不带引号)。
布尔字段存在,无论其值是真还是假。例如,存在于包含该标志的所有TCP数据包中,无论SYN标志为0 或 1
。
要仅匹配设置了SYN 标志的TCP数据包,需要使用下面的表达式:
tcp.flags.syn == 1 or tcp.flags.syn == True
2.1.4以太网地址
6 个字节,用冒号 (:)、点 (.) 或短划线 (-) 分隔,分隔符之间有一个或两个字节:
eth.dst == ff:ff:ff:ff:ff:ff
eth.dst == ff-ff-ff-ff-ff-ff
eth.dst == ffff.ffff.ffff
2.1.5 IPv4 地址
ip.addr == 192.168.0.1
无类别域间路由(CIDR)表示法可用于测试是否IPv4
地址位于某个子网中。
例如,此显示器 过滤器将找到129.111
B类网络中的所有数据包:
ip.addr == 129.111.0.0/16
2.1.6 IPv6 地址
ipv6.addr == ::1
与IPv4
地址一样,IPv6
地址可以与子网匹配。
2.1.7文本字符串
http.request.uri == "https://www.wireshark.org/"
字符串是字节序列。功能像lower()
使用ASCII
这样的函数,否则不假定特定的编码。字符串文本使用双精度指定引号。还可以使用字节转义序列指定字符,使用十六进制 xhh 或八进制 ddd,这里h 和d是十六进制和八进制
dns.qry.name contains "www.x77x69x72x65x73x68x61x72x6b.org"
或者,可以使用原始字符串语法。此类字符串以 r or R并将反斜杠作为文字字符。
http.user_agent matches r"(X11;"
2.1.8日期和时间
frame.time == "Sep 26, 2004 23:18:04.954975"
ntp.xmt ge "2023-10-07 12:34:56"
绝对时间字段的值表示为字符串,使用上面两种格式之一。小数秒可以省略或指定为纳秒精度;允许使用额外的尾随零,但不允许使用其他数字。字符串不能带有时区后缀,并且始终按照本地时区进行解析,即使是以UTC显示的字段也是如此。
在第一种格式中,无论区域设置如何,缩写的月份名称都必须是英文。
在第二种格式中,可以省略任意数量的时间字段,从最低有效期(秒)到最高有效期,但至少必须指定整个日期:
frame.time < "2022-01-01"
在第二种格式中,T可能出现在日期和时间之间,如ISO 8601中所示,但在删除不太重要的时间时则不会出现。
2.2一些实例
udp contains 81:60:03
上面的显示筛选器匹配UDP标头或有效负载中任何位置包含3字节序列0x81、0x60、0x03
的数据包。
sip.To contains "a1762"
上面的显示匹配 SIP To-标头在标头中任意位置包含字符串a1762
的数据包。
http.host matches "acme\.(org|com|net)"
上面的显示筛选器匹配HOST标头包含acme.org、acme.com或acme.net
的HTTP数据包。比较不区分大小写。
tcp.flags & 0x02
该显示筛选器将匹配所有包含tcp.flags
字段的数据包,并设置0x02
位,即SYN位。
2.3使用正则表达式可能出现的陷阱
包含正则表达式的字符串文本将分析两次。一次由Wireshark
的显示器 过滤器引擎,并再次由PCRE2
库。使用时请务必牢记这一点 “匹配”运算符与正则表达式转义序列和特殊字符。
例如,筛选器表达式使用字符串作为输入模式到PCRE
。但是,表达式使用字符串作为模式。在这种情况下,两个表达式给出相同的结果,因为 Wireshark
和PCRE
两者都支持相同的字节转义序列(0x43
是ASCII
十六进制代码)。
严重失败的一个例子是。因为0x28
是ASCII
输入到 PCRE
的模式的代码为 。此正则表达式在语法上是无效(缺少右括号)。匹配显示筛选器常规中的文本括号 表达式 必须使用反斜杠对其进行转义(两次)。
3.组合表达式
逻辑运算符在 Wireshark
中组合过滤器表达式如下:
英文 | 符号 | 描述 | 示例 |
---|---|---|---|
and |
&& | 逻辑与 | ip.src==10.0.0.5 and tcp.flags.fin |
or |
|| | 逻辑或 | ip.src==10.0.0.5 or ip.src==192.1.1.1 |
xor |
^^ | 逻辑异或 | tr.dst[0:3] == 0.6.29 xor tr.src[0:3] == 0.6.29 |
not |
! | 逻辑非 | not llc |
[…] |
子序列 | ||
in |
设置成员资格 |
4.切片运算符
Wireshark
允许以相当精细的方式选择序列的子序列方式。在标签后,可以放置一对包含逗号的括号 [] 范围说明符的分隔列表。
eth.src[0:3] == 00:00:83
上面的示例使用n:m
格式来指定单个范围。在这种情况下,n是开始偏移,m是指定范围的长度。
eth.src[1-2] == 00:83
上面的示例使用n-m
格式来指定单个范围。在这种情况下,n是开始偏移,m是结束偏移。
eth.src[:4] == 00:00:83:00
上面的例子使用了:m
格式,它从序列的开头到偏移量m的所有内容。它相当于0:m
eth.src[4:] == 20:20
上面的例子使用了n:
格式,它采用了从偏移量n到序列末尾的所有内容。
eth.src[2] == 83
上面的示例使用n
格式来指定单个范围。在这种情况下,在偏移量n处的序列中的元素被选择。这相当于n:1
。
eth.src[0:3,1-2,:4,4:,2] ==
00:00:83:00:83:00:00:83:00:20:20:83
Wireshark
允许您将逗号分隔列表中的单个范围串在一起,以形成如上所示的复合范围。
5.图层操作符
可以使用层运算符(#)将字段限制在协议栈中的某一层,后面跟一个十进制数:
ip.addr#2 == 192.168.30.40
只匹配数据包中的内部(第二)层。层使用简单的堆叠语义,协议层从1开始按顺序计数。例如,在包含两个IPv4标头的数据包中,外部(第一)源地址可以与ip.src#1
匹配,内部(第二)源地址则可以与ip.src#2
匹配。
对于更复杂的范围,与切片使用的语法相同是有效的:
tcp.port#[2-4]
是指层数为2、3或4的层。散列符号是区分层范围和切片所必需的。
6.成员运算符
Wireshark
允许您测试字段在一组值或字段中的成员身份。在字段名称之后,使用in
运算符,后跟用大括号{}包围的集合项。例如,要显示TCP
源或目标端口为80、443或8080
的数据包,可以在{80、443、8080}
中使用TCP.port
。集合元素必须用逗号分隔。该组值还可以包含范围:{4434430..4434}
中的tcp.port
。
集合不仅限于数字,还可以使用其他类型:
http.request.method in {"HEAD", "GET"}
ip.addr in {10.0.0.5 .. 10.0.0.9, 192.168.1.1..192.168.1.9}
frame.time_delta in {10 .. 10.5}
7.算术运算符
过滤器算术运算如下表:
名称 | 语法 | 描述 |
---|---|---|
一元减号 | -A |
否定 A |
加法 | A + B |
将 B 添加到 A |
减法 | A - B |
从 A 中减去 B |
乘法 | A * B |
A 乘以 B |
除法 | A / B |
A 除以 B |
求模 | A % B |
A除以B的余数 |
按位各和 | A & B |
A 和 B 的按位 AND |
算术表达式可以使用大括号进行分组。
例如,捕获长度导致TCP
选项被截断的帧:
frame.cap_len < { 14 + ip.hdr_len + tcp.hdr_len }
8.函数
显示过滤器语言具有许多转换字段的函数
函数 | 功能描述 |
---|---|
upper | 将字符串字段转换为大写。 |
lower | 将字符串字段转换为小写。 |
len | 返回字符串或字节字段的字节长度。 |
count | 返回帧中出现的字段数。 |
string | 将非字符串字段转换为字符串。 |
max | 返回参数的最大值。 |
min | 返回参数的最小值。 |
abs | 返回参数的绝对值。 |
upper和lower函数可用于强制不区分大小写的匹配:lower(http.server)
包含“apache”
。
要查找具有长请求uri
的HTTP
请求,请执行以下操作:len(HTTP.request.uri)>100
。请注意,len
函数生成的字符串长度以字节为单位,而不是(多字节)字符。
通常一个IP
帧只有两个地址(源和目的地),但在ICMP
错误或隧道传输的情况下,一个数据包可能包含更多的地址。这些数据包的计数(ip.addr)>2
。
字符串函数将字段值转换为字符串,适合与“matches”
或“contains”
等运算符一起使用。整数字段将转换为其十进制表示形式。它可以与IP/以太网地址
(以及其他地址)一起使用,但不能与字符串或字节字段一起使用。
例如,要匹配奇数帧数:
string(frame.number) matches "[13579]$"
要匹配子网块(172.16到172.31)中以255结尾的IP地址:
string(ip.dst) matches r"^172.(1[6-9]|2[0-9]|3[0-1]).[0-9]{1,3}.255"
函数max()和min()接受任意数量的相同类型的参数,并分别返回集合中最大/最小的参数。
max(tcp.srcport, tcp.dstport) <= 1024
9.有时字段会更改名称
随着协议的发展,它们有时会更改名称或被较新的标准所取代。例如,DHCP扩展并在很大程度上取代了BOOTP,TLS取代了SSL。如果协议解析器最初使用协议的旧名称和字段,Wireshark开发团队可能会将其更新为使用新名称和字段。在这种情况下,他们会将旧协议名称中的别名添加到新协议名称中,以使转换更容易。
例如,DHCP解析器最初是为BOOTP协议开发的,但从Wireshark 3.0开始,所有“BOOTP”显示筛选器字段都已重命名为其“DHCP”等效字段。您暂时仍然可以使用旧的筛选器名称,例如,“bootp.type”相当于“dhcp.type”,但Wireshark在使用时会显示警告“bootp”已弃用。将来可能会删除对弃用字段的支持。
10.某些协议名称可能不明确
在某些特定情况下,关系表达式(等于、小于等)可能是不明确的。协议或协议字段的筛选器名称可以包含任何顺序的任何字母和数字,可能用点分隔。这可能与文字值(通常是十六进制的数值)无法区分。例如,fc的语义值可以是协议光纤通道或十六进制数字0xFC,因为0x前缀对于十六进制数字是可选的。
任何与注册的协议或协议字段过滤器名称匹配的值都会被语义解释为这样。如果它与协议名称不匹配,则应用解析文字值的正常规则。
因此,在“fc”的情况下,词法标记被解释为“光纤通道”,而不是0xFC。在“fd”的情况下,它将被解释为0xFD,因为它是一个格式良好的十六进制文字值(根据显示筛选器语言语法的规则),并且没有使用筛选器名称“fd”注册的协议。
对模糊值的解释方式可能会在未来发生变化。为了避免这个问题并解决歧义,提供了额外的语法。以句点为前缀的值始终被视为协议名称。点代表协议名称空间的根,是可选的)。以冒号为前缀的值总是被解释为字节数组。
frame[10:] contains .fc or frame[10] == :fc
如果您正在编写脚本,或者您认为由于某些筛选表达式的语法歧义,您的表达式可能无法给出预期的结果,则建议使用显式语法来指示该表达式的正确含义。
学习|生活|分享|积累|永不停步
请留下你指尖的温度
让太阳拥抱你
公众号:imoonrong
发表评论