Tcpdump 高级过滤器
大家读完觉得有意义记得关注和点赞!!!
Tcpdump 高级过滤器
介绍
在本文中,我将介绍如何使用 tcpdump 来:
- 了解是否设置了 IP 选项
- 查找 DF 数据包(我们不想分段的数据包)
- 查找分片数据包
- 查找具有低 TTL 的数据报
- 查找特定的 TCP 标志组合
- 查找包含特定数据的数据报(此处为来自 SMTP 协议的带有命令 MAIL 和来自 HTTP 的 GET 命令的数据包)
笔记
我通常在过滤器之前键入,但我不会在整篇文章中这样做。tcpdump -n -i eth1 -s 1600
-n
阻止 DNS 查找。-i
指定接口。-s
指定数据包的大小(默认值为 65536 字节)。
使用时要小心,因为根据 tcpdump 的版本,您可能会捕获 64K 或全长数据包。-s 0
所有命令都以 root 身份键入。
如有评论、建议或报告错误,请随时与我联系。如果有什么不清楚的地方,请告诉我!
我将尝试使用新的有用规则来更新本文档。
让我们学习语法
在开始高级筛选器之前,让我们回顾一下 tcpdump 的基本语法。
基本语法
筛选主机
将涉及 192.168.1.1 的任何流量匹配为目标或源:
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">tcpdump host 192.168.1.1
</code></span></span></span></span>
仅作为源:
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">tcpdump src host 192.168.1.1
</code></span></span></span></span>
仅作为目标:
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">tcpdump dst host 192.168.1.1
</code></span></span></span></span>
端口筛选
将涉及端口 25 作为源或目标的任何流量匹配:
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">tcpdump port <span style="color:#ae81ff">25</span>
</code></span></span></span></span>
仅作为源:
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">tcpdump src port <span style="color:#ae81ff">25</span>
</code></span></span></span></span>
仅作为目标:
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">tcpdump dst port <span style="color:#ae81ff">25</span>
</code></span></span></span></span>
网络筛选
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">tcpdump net 192.168
tcpdump src net 192.168
tcpdump dst net 192.168
</code></span></span></span></span>
协议过滤
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">tcpdump arp
tcpdump ip
tcpdump tcp
tcpdump udp
tcpdump icmp
</code></span></span></span></span>
让我们组合表达式
请记住这一点:
类型 | 表达 | 也可以 | ||
---|---|---|---|---|
否定 | ! | not | ||
连接 | && | and | ||
互生 | || | or |
例如,以下规则将匹配端口 80 (web) 上以 192.168.1.254 或 192.168.1.200 作为目标主机的任何 TCP 流量:
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">tcpdump <span style="color:#e6db74">'((tcp) and (port 80) and ((dst host 192.168.1.254) or (dst host 192.168.1.200)))'</span>
</code></span></span></span></span>
此 ICMP 流量将匹配涉及物理/MAC 地址 00:01:02:03:04:05 的目标的任何 ICMP 流量:
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">tcpdump <span style="color:#e6db74">'((icmp) and ((ether dst host 00:01:02:03:04:05)))'</span>
</code></span></span></span></span>
这将匹配目标网络 192.168 的任何流量,但目标主机 192.168.1.200 除外:
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">tcpdump <span style="color:#e6db74">'((tcp) and ((dst net 192.168) and (not dst host 192.168.1.200)))'</span>
</code></span></span></span></span>
高级标头筛选
在我们继续之前,我们需要知道如何从 header 中过滤掉信息:
表达 | 解释 |
---|---|
proto[x:y] | 将从字节 x 开始过滤 y 字节。 将筛选字节 3 和 4(第一个字节以 0 开头)ip[2:2] |
proto[x:y] & z = 0 | 将匹配在应用掩码时设置为 0 的位zproto[x:y] |
proto[x:y] & z !=0 | 将 Mask 应用于 时设置了一些位zproto[x:y] |
proto[x:y] & z = z | 将蒙版应用于zproto[x:y] |
proto[x:y] = z | p[x:y] 的 Bits 恰好设置为z |
运营商:
算子 | 意义 |
---|---|
> | 大 |
< | 降低 |
>= | 大于或等于 |
<= | 更低或等于 |
= | 平等 |
!= | 不同 |
这可能一开始就不清楚,但您会在下面找到涉及这些表达式的示例。
当然,在深入研究更高级的过滤器之前,了解协议标头的外观很重要。
IP 标头:
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash"><span style="color:#ae81ff">0</span> <span style="color:#ae81ff">1</span> <span style="color:#ae81ff">2</span> <span style="color:#ae81ff">3</span>
<span style="color:#ae81ff">0</span> <span style="color:#ae81ff">1</span> <span style="color:#ae81ff">2</span> <span style="color:#ae81ff">3</span> <span style="color:#ae81ff">4</span> <span style="color:#ae81ff">5</span> <span style="color:#ae81ff">6</span> <span style="color:#ae81ff">7</span> <span style="color:#ae81ff">8</span> <span style="color:#ae81ff">9</span> <span style="color:#ae81ff">0</span> <span style="color:#ae81ff">1</span> <span style="color:#ae81ff">2</span> <span style="color:#ae81ff">3</span> <span style="color:#ae81ff">4</span> <span style="color:#ae81ff">5</span> <span style="color:#ae81ff">6</span> <span style="color:#ae81ff">7</span> <span style="color:#ae81ff">8</span> <span style="color:#ae81ff">9</span> <span style="color:#ae81ff">0</span> <span style="color:#ae81ff">1</span> <span style="color:#ae81ff">2</span> <span style="color:#ae81ff">3</span> <span style="color:#ae81ff">4</span> <span style="color:#ae81ff">5</span> <span style="color:#ae81ff">6</span> <span style="color:#ae81ff">7</span> <span style="color:#ae81ff">8</span> <span style="color:#ae81ff">9</span> <span style="color:#ae81ff">0</span> <span style="color:#ae81ff">1</span>
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version| IHL |Type of Service| Total Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identification |Flags| Fragment Offset |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Time to Live | Protocol | Header Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Destination Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding | <-- optional
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| DATA ... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
</code></span></span></span></span>
对于这些示例,我将考虑我们只使用 IPv4 协议套件。
在理想情况下,每个字段都适合一个字节。当然,事实并非如此。
习题
练习:是否设置了 IP 选项?
假设我们想知道 IP 标头是否设置了选项。我们不能只尝试过滤掉第 21 个字节,因为如果未设置任何选项,数据将从第 21 个字节开始。我们知道 “正常” 报头的长度通常为 20 字节(160 位)。设置 options 后,标头会比这更长。IP 报头具有报头长度字段,我们将在此处对其进行筛选,以了解报头是否超过 20 字节。
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">+-+-+-+-+-+-+-+-+
|Version| IHL |
+-+-+-+-+-+-+-+-+
</code></span></span></span></span>
通常,第一个字节的二进制值为 01000101。
无论如何,我们需要将第一个字节分成两半......
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash"><span style="color:#ae81ff">0100</span> <span style="color:#ae81ff">0101</span>
0100 <span style="color:#f92672">=</span> <span style="color:#ae81ff">4</span> in decimal. This is the IP version.
0101 <span style="color:#f92672">=</span> <span style="color:#ae81ff">5</span> in decimal. This is the number of blocks of <span style="color:#ae81ff">32</span> bits in the headers. <span style="color:#ae81ff">5</span> x <span style="color:#ae81ff">32</span> bits <span style="color:#f92672">=</span> <span style="color:#ae81ff">160</span> bits or <span style="color:#ae81ff">20</span> bytes.
</code></span></span></span></span>
如果标头设置了 IP 选项,则第一个字节的后半部分将大于 5。
我们有两种方法可以处理这种过滤器。
- 尝试匹配大于 01000101 的值。这将触发设置了 IP 选项的 IPv4 流量的匹配项,但也触发任何 IPv6 流量的匹配项!
十进制等于 。0100010169
让我们回顾一下如何用十进制计算。
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash"><span style="color:#ae81ff">0</span> : <span style="color:#ae81ff">0</span> <span style="color:#ae81ff">\
</span><span style="color:#ae81ff">1</span> : 2^6 <span style="color:#f92672">=</span> <span style="color:#ae81ff">64</span> <span style="color:#ae81ff">\ </span>First field <span style="color:#f92672">(</span>IP version<span style="color:#f92672">)</span>
<span style="color:#ae81ff">0</span> : <span style="color:#ae81ff">0</span> /
<span style="color:#ae81ff">0</span> : <span style="color:#ae81ff">0</span> /
-
<span style="color:#ae81ff">0</span> : <span style="color:#ae81ff">0</span> <span style="color:#ae81ff">\
</span><span style="color:#ae81ff">1</span> : 2^2 <span style="color:#f92672">=</span> <span style="color:#ae81ff">4</span> <span style="color:#ae81ff">\ </span>Second field <span style="color:#f92672">(</span>Header length<span style="color:#f92672">)</span>
<span style="color:#ae81ff">0</span> : <span style="color:#ae81ff">0</span> /
<span style="color:#ae81ff">1</span> : 2^0 <span style="color:#f92672">=</span> <span style="color:#ae81ff">1</span> /
</code></span></span></span></span>
64 + 4 + 1 = 69
IP 报头中的第一个字段通常具有 69 的十进制值。如果我们设置了 IP 选项,我们可能会有 01000110 (IPv4 = 4 + 标头 = 6),十进制等于 70。
此规则应完成以下工作:
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">tcpdump <span style="color:#e6db74">'ip[0] > 69'</span>
</code></span></span></span></span>
不知何故,正确的方法是屏蔽第一个字节的前半部分/字段,因为如前所述,此过滤器将匹配任何 IPv6 流量。
- 正确/正确的方法:“掩盖”字节的前半部分
0100 0101
将变为0000 01010000 1111
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash"><span style="color:#ae81ff">0100</span> <span style="color:#ae81ff">0101</span> : 1st byte originally
<span style="color:#ae81ff">0000</span> <span style="color:#ae81ff">1111</span> : mask <span style="color:#f92672">(</span>0xf in hex or <span style="color:#ae81ff">15</span> in decimal<span style="color:#f92672">)</span>. <span style="color:#ae81ff">0</span> will mask the values <span style="color:#66d9ef">while</span> <span style="color:#ae81ff">1</span> will keep the values intact.
---------
<span style="color:#ae81ff">0000</span> <span style="color:#ae81ff">0101</span> : final result
</code></span></span></span></span>
您应该将掩码视为 “power switch”。1 表示打开/启用,0 表示关闭/禁用。
正确的过滤器:
以十进制表示:
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">tcpdump <span style="color:#e6db74">'ip[0] & 15 > 5'</span>
</code></span></span></span></span>
或
十六进制:
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">tcpdump <span style="color:#e6db74">'ip[0] & 0xf > 5'</span>
</code></span></span></span></span>
我使用六角面具。
让我们回顾一下..如果您想:
- 保持最后 4 位不变,使用 (binary 00001111)
0xf
- 保持前 4 位不变,使用 (binary 11110000)
0xf0
练习:是否设置了 DF 位(不分段)?
现在让我们尝试知道是否发生了碎片化。碎片化是不可取的。当发送方的 MTU 大于目标路径上的路径 MTU 时,就会发生分片。
分段信息可以在 IP 报头的第 7 个和第 8 个字节中找到。
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Flags| Fragment Offset |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Bit 0: reserved, must be zero
Bit 1: <span style="color:#f92672">(</span>DF<span style="color:#f92672">)</span> 0 <span style="color:#f92672">=</span> May Fragment, 1 <span style="color:#f92672">=</span> Don<span style="color:#960050"><span style="background-color:#1e0010">'</span></span>t Fragment.
Bit 2: <span style="color:#f92672">(</span>MF<span style="color:#f92672">)</span> 0 <span style="color:#f92672">=</span> Last Fragment, 1 <span style="color:#f92672">=</span> More Fragments.
</code></span></span></span></span>
fragment offset 字段仅在发生碎片时使用。
如果我们想匹配 DF 位(不要分段位,以避免 IP 分段):
第 7 个字节的值为 10 进制0100000064
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">tcpdump <span style="color:#e6db74">'ip[6] = 64'</span>
</code></span></span></span></span>
练习:匹配碎片
匹配 MF(更多片段集)?这将匹配分段数据报,但不匹配最后一个分段(第 2 位设置为 0):
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">tcpdump <span style="color:#e6db74">'ip[6] = 32'</span>
</code></span></span></span></span>
最后一个片段的前 3 位设置为 0...但在 fragment offset 字段中有数据。
匹配片段和最后一个片段:
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">tcpdump <span style="color:#e6db74">'((ip[6:2] > 0) and (not ip[6] = 64))'</span>
</code></span></span></span></span>
一点解释:
ip[6:2] > 0
将返回值至少为 1 的任何内容。
不过,我们不希望数据报设置了 DF 位..原因not ip[6] = 64
If you want to test fragmentation use something like:
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">ping -M want -s <span style="color:#ae81ff">3000</span> 192.168.1.1
</code></span></span></span></span>
练习:匹配具有低 TTL 的数据报
TTL 字段位于第 9 个字节中,非常适合 1 个字节。
因此,TTL 字段的最大十进制值为 ( in binary)。25511111111
这可以验证,我们将尝试指定 TTL 为 256:
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">ping -M want -s <span style="color:#ae81ff">3000</span> -t <span style="color:#ae81ff">256</span> 192.168.1.200
</code></span></span></span></span>
实际上,ping 告诉 use 256 超出了范围:
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">ping: ttl <span style="color:#ae81ff">256</span> out of range
</code></span></span></span></span>
TTL 字段:
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">+-+-+-+-+-+-+-+-+
| Time to Live |
+-+-+-+-+-+-+-+-+
</code></span></span></span></span>
我们可以尝试通过在网关上使用类似这样的东西来查找我们网络上是否有人正在使用 trace route:
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">tcpdump <span style="color:#e6db74">'ip[8] < 5'</span>
</code></span></span></span></span>
练习:匹配长度超过 X 字节的数据包
其中 X 为 600 字节:
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">tcpdump <span style="color:#e6db74">'ip[2:2] > 600'</span>
</code></span></span></span></span>
更多 IP 过滤
我们可以想象直接以十进制寻址过滤源地址和目标地址。我们还可以通过过滤第 10 个字节来匹配协议。
无论如何,这都是没有意义的,因为 tcpdump 已经很容易过滤掉这类信息了。
TCP 标头:
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash"><span style="color:#ae81ff">0</span> <span style="color:#ae81ff">1</span> <span style="color:#ae81ff">2</span> <span style="color:#ae81ff">3</span>
<span style="color:#ae81ff">0</span> <span style="color:#ae81ff">1</span> <span style="color:#ae81ff">2</span> <span style="color:#ae81ff">3</span> <span style="color:#ae81ff">4</span> <span style="color:#ae81ff">5</span> <span style="color:#ae81ff">6</span> <span style="color:#ae81ff">7</span> <span style="color:#ae81ff">8</span> <span style="color:#ae81ff">9</span> <span style="color:#ae81ff">0</span> <span style="color:#ae81ff">1</span> <span style="color:#ae81ff">2</span> <span style="color:#ae81ff">3</span> <span style="color:#ae81ff">4</span> <span style="color:#ae81ff">5</span> <span style="color:#ae81ff">6</span> <span style="color:#ae81ff">7</span> <span style="color:#ae81ff">8</span> <span style="color:#ae81ff">9</span> <span style="color:#ae81ff">0</span> <span style="color:#ae81ff">1</span> <span style="color:#ae81ff">2</span> <span style="color:#ae81ff">3</span> <span style="color:#ae81ff">4</span> <span style="color:#ae81ff">5</span> <span style="color:#ae81ff">6</span> <span style="color:#ae81ff">7</span> <span style="color:#ae81ff">8</span> <span style="color:#ae81ff">9</span> <span style="color:#ae81ff">0</span> <span style="color:#ae81ff">1</span>
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Acknowledgment Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data | |C|E|U|A|P|R|S|F| |
| Offset| Res. |W|C|R|C|S|S|Y|I| Window |
| | |R|E|G|K|H|T|N|N| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Checksum | Urgent Pointer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
</code></span></span></span></span>
将任何 TCP 流量与源端口> 1024 匹配:
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">tcpdump <span style="color:#e6db74">'tcp[0:2] > 1024'</span>
</code></span></span></span></span>
或
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">tcpdump <span style="color:#e6db74">'tcp src portrange 1025-65535'</span>
</code></span></span></span></span>
将 TCP 流量与特定标志组合匹配:
标志在 TCP 报头的第 14 个字节中定义。
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">+-+-+-+-+-+-+-+-+
|C|E|U|A|P|R|S|F|
|W|C|R|C|S|S|Y|I|
|R|E|G|K|H|T|N|N|
+-+-+-+-+-+-+-+-+
</code></span></span></span></span>
在 TCP 3 次握手中,主机之间的交换是这样的:
- 源发送 SYN
- 使用 SYN、ACK 的目标答案
- 源发送 ACK
如果我们想匹配仅设置了 SYN 标志的数据包,则第 14 个字节的二进制值将等于十进制的 2:00000010
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">tcpdump <span style="color:#e6db74">'tcp[13] = 2'</span>
</code></span></span></span></span>
匹配 SYN、ACK
00010010
或十进制:18
tcpdump 'tcp[13] = 18'
匹配 SYN only 或 SYN-ACK 数据报
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">tcpdump <span style="color:#e6db74">'tcp[13] & 2 = 2'</span>
</code></span></span></span></span>
我们在这里使用了口罩。它将返回设置了 ACK 位的任何内容(因此也返回 SYN-ACK 组合)
我们假设以下示例 (SYN-ACK)
00010010 : SYN-ACK packet
00000010 : mask (2 in decimal)
--------
00000010 : result (2 in decimal)
面具的每一个部分都匹配!
匹配 PSH-ACK 数据包
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">tcpdump <span style="color:#e6db74">'tcp[13] = 24'</span>
</code></span></span></span></span>
匹配任何包含 FIN 的组合
FIN 通常总是带有 ACK,因此我们要么需要使用掩码,要么匹配 ACK-FIN 组合。
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">tcpdump <span style="color:#e6db74">'tcp[13] & 1 = 1'</span>
</code></span></span></span></span>
Matching RST flag
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">tcpdump <span style="color:#e6db74">'tcp[13] & 4 = 4'</span>
</code></span></span></span></span>
与 tcpflags 匹配
实际上,有一种更简单的方法来过滤标志(并查找 tcpflags):man pcap-filter
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">tcpdump <span style="color:#e6db74">'tcp[tcpflags] == tcp-ack'</span>
</code></span></span></span></span>
匹配设置了 TCP-SYN 或 TCP-FIN 的所有软件包:
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">tcpdump <span style="color:#e6db74">'tcp[tcpflags] & (tcp-syn|tcp-fin) != 0'</span>
</code></span></span></span></span>
通过查看 TCP 状态机,我们可以找到我们可能想要分析的不同标志组合。
理想情况下,ACK_WAIT模式下的套接字不必发送 RST。这意味着 3 次握手尚未完成。我们可能想要分析这种流量。
练习:匹配 SMTP 数据
我将创建一个过滤器,该过滤器将匹配任何包含来自 SMTP 交换的 “MAIL” 命令的数据包。
您可以使用 http://www.easycalculation.com/ascii-hex.php 之类的工具将值从 ASCII 转换为十六进制,也可以使用 Python。
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">$ python -c <span style="color:#e6db74">'print "MAIL".encode("hex")'</span>
4d41494c
</code></span></span></span></span>
所以十六进制中的 “MAIL” 是0x4d41494c
规则为:
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">tcpdump <span style="color:#e6db74">'((port 25) and (tcp[20:4] = 0x4d41494c))'</span>
</code></span></span></span></span>
它将检查字节 21 到 24。“MAIL” 长 4 字节/32 位..
此规则不会匹配设置了 IP 选项的数据包。
这是数据包(当然是垃圾邮件)的一个示例:
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">Capturing on eth0
Frame <span style="color:#ae81ff">1</span> <span style="color:#f92672">(</span><span style="color:#ae81ff">92</span> bytes on wire, <span style="color:#ae81ff">92</span> bytes captured<span style="color:#f92672">)</span>
Arrival Time: Sep 25, <span style="color:#ae81ff">2007</span> 00:06:10.875424000
<span style="color:#f92672">[</span>Time delta from previous packet: 0.000000000 seconds<span style="color:#f92672">]</span>
<span style="color:#f92672">[</span>Time since reference or first frame: 0.000000000 seconds<span style="color:#f92672">]</span>
Frame Number: <span style="color:#ae81ff">1</span>
Packet Length: <span style="color:#ae81ff">92</span> bytes
Capture Length: <span style="color:#ae81ff">92</span> bytes
<span style="color:#f92672">[</span>Frame is marked: False<span style="color:#f92672">]</span>
<span style="color:#f92672">[</span>Protocols in frame: eth:ip:tcp:smtp<span style="color:#f92672">]</span>
Ethernet II, Src: Cisco_X <span style="color:#f92672">(</span>00:11:5c:X<span style="color:#f92672">)</span>, Dst: 3Com_X <span style="color:#f92672">(</span>00:04:75:X<span style="color:#f92672">)</span>
Destination: 3Com_X <span style="color:#f92672">(</span>00:04:75:X<span style="color:#f92672">)</span>
Address: 3Com_X <span style="color:#f92672">(</span>00:04:75:X<span style="color:#f92672">)</span>
.... ...0 .... .... .... .... <span style="color:#f92672">=</span> IG bit: Individual address <span style="color:#f92672">(</span>unicast<span style="color:#f92672">)</span>
.... ..0. .... .... .... .... <span style="color:#f92672">=</span> LG bit: Globally unique address <span style="color:#f92672">(</span>factory default<span style="color:#f92672">)</span>
Source: Cisco_X <span style="color:#f92672">(</span>00:11:5c:X<span style="color:#f92672">)</span>
Address: Cisco_X <span style="color:#f92672">(</span>00:11:5c:X<span style="color:#f92672">)</span>
.... ...0 .... .... .... .... <span style="color:#f92672">=</span> IG bit: Individual address <span style="color:#f92672">(</span>unicast<span style="color:#f92672">)</span>
.... ..0. .... .... .... .... <span style="color:#f92672">=</span> LG bit: Globally unique address <span style="color:#f92672">(</span>factory default<span style="color:#f92672">)</span>
Type: IP <span style="color:#f92672">(</span>0x0800<span style="color:#f92672">)</span>
Internet Protocol, Src: 62.163.X <span style="color:#f92672">(</span>62.163.X<span style="color:#f92672">)</span>, Dst: 192.168.X <span style="color:#f92672">(</span>192.168.X<span style="color:#f92672">)</span>
Version: <span style="color:#ae81ff">4</span>
Header length: <span style="color:#ae81ff">20</span> bytes
Differentiated Services Field: 0x00 <span style="color:#f92672">(</span>DSCP 0x00: Default; ECN: 0x00<span style="color:#f92672">)</span>
<span style="color:#ae81ff">0000</span> 00.. <span style="color:#f92672">=</span> Differentiated Services Codepoint: Default <span style="color:#f92672">(</span>0x00<span style="color:#f92672">)</span>
.... ..0. <span style="color:#f92672">=</span> ECN-Capable Transport <span style="color:#f92672">(</span>ECT<span style="color:#f92672">)</span>: <span style="color:#ae81ff">0</span>
.... ...0 <span style="color:#f92672">=</span> ECN-CE: <span style="color:#ae81ff">0</span>
Total Length: <span style="color:#ae81ff">78</span>
Identification: 0x4078 <span style="color:#f92672">(</span>16504<span style="color:#f92672">)</span>
Flags: 0x04 <span style="color:#f92672">(</span>Don<span style="color:#e6db74">'t Fragment)
</span><span style="color:#e6db74"> 0... = Reserved bit: Not set
</span><span style="color:#e6db74"> .1.. = Don'</span>t fragment: Set
..0. <span style="color:#f92672">=</span> More fragments: Not set
Fragment offset: <span style="color:#ae81ff">0</span>
Time to live: <span style="color:#ae81ff">118</span>
Protocol: TCP <span style="color:#f92672">(</span>0x06<span style="color:#f92672">)</span>
Header checksum: 0x08cb <span style="color:#f92672">[</span>correct<span style="color:#f92672">]</span>
<span style="color:#f92672">[</span>Good: True<span style="color:#f92672">]</span>
<span style="color:#f92672">[</span>Bad : False<span style="color:#f92672">]</span>
Source: 62.163.X <span style="color:#f92672">(</span>62.163.X<span style="color:#f92672">)</span>
Destination: 192.168.X <span style="color:#f92672">(</span>192.168.XX<span style="color:#f92672">)</span>
Transmission Control Protocol, Src Port: <span style="color:#ae81ff">4760</span> <span style="color:#f92672">(</span>4760<span style="color:#f92672">)</span>, Dst Port: smtp <span style="color:#f92672">(</span>25<span style="color:#f92672">)</span>, Seq: 0, Ack: 0, Len: <span style="color:#ae81ff">38</span>
Source port: <span style="color:#ae81ff">4760</span> <span style="color:#f92672">(</span>4760<span style="color:#f92672">)</span>
Destination port: smtp <span style="color:#f92672">(</span>25<span style="color:#f92672">)</span>
Sequence number: <span style="color:#ae81ff">0</span> <span style="color:#f92672">(</span>relative sequence number<span style="color:#f92672">)</span>
<span style="color:#f92672">[</span>Next sequence number: <span style="color:#ae81ff">38</span> <span style="color:#f92672">(</span>relative sequence number<span style="color:#f92672">)]</span>
Acknowledgement number: <span style="color:#ae81ff">0</span> <span style="color:#f92672">(</span>relative ack number<span style="color:#f92672">)</span>
Header length: <span style="color:#ae81ff">20</span> bytes
Flags: 0x18 <span style="color:#f92672">(</span>PSH, ACK<span style="color:#f92672">)</span>
0... .... <span style="color:#f92672">=</span> Congestion Window Reduced <span style="color:#f92672">(</span>CWR<span style="color:#f92672">)</span>: Not set
.0.. .... <span style="color:#f92672">=</span> ECN-Echo: Not set
..0. .... <span style="color:#f92672">=</span> Urgent: Not set
...1 .... <span style="color:#f92672">=</span> Acknowledgment: Set
.... 1... <span style="color:#f92672">=</span> Push: Set
.... .0.. <span style="color:#f92672">=</span> Reset: Not set
.... ..0. <span style="color:#f92672">=</span> Syn: Not set
.... ...0 <span style="color:#f92672">=</span> Fin: Not set
Window size: <span style="color:#ae81ff">17375</span>
Checksum: 0x6320 <span style="color:#f92672">[</span>correct<span style="color:#f92672">]</span>
<span style="color:#f92672">[</span>Good Checksum: True<span style="color:#f92672">]</span>
<span style="color:#f92672">[</span>Bad Checksum: False<span style="color:#f92672">]</span>
Simple Mail Transfer Protocol
Command: MAIL FROM:<wguthrie_at_mysickworld--dot--com><span style="color:#ae81ff">\r\n</span>
Command: MAIL
Request parameter: FROM:<wguthrie_at_mysickworld--dot--com>
</code></span></span></span></span>
匹配 HTTP 数据
让我们创建一个过滤器,用于查找包含 GET 请求的任何数据包。
HTTP 请求将以以下方式开头:
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">GET / HTTP/1.1<span style="color:#ae81ff">\r\n</span>
</code></span></span></span></span>
总共 16 个字节,计算回车,但不计算反斜杠!
如果未设置 IP 选项..GET 命令将使用字节 20、21 和 22。通常,options 需要 12 个字节(第 12 个字节表示标头长度,应报告 32 字节)。因此,我们应该匹配字节 32、33 和 34(第 1 个字节 = 字节 0)。
Tcpdump 只能匹配 1、2 或 4 字节的数据大小,我们将在 GET 命令后面采用以下 ASCII 字符(一个空格)。
十六进制中的 “GET” 是47455420
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">tcpdump <span style="color:#e6db74">'tcp[32:4] = 0x47455420'</span>
</code></span></span></span></span>
匹配 HTTP 数据(示例取自 tcpdump 手册页):
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">tcpdump <span style="color:#e6db74">'tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)'</span>
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
ip<span style="color:#f92672">[</span>2:2<span style="color:#f92672">]</span> <span style="color:#f92672">=</span> | Total Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+-+-+-+-+-+-+-+-+
ip<span style="color:#f92672">[</span>0<span style="color:#f92672">]</span> <span style="color:#f92672">=</span> |Version| IHL |
+-+-+-+-+-+-+-+-+
+-+-+-+-+-+-+-+-+
ip<span style="color:#f92672">[</span>0<span style="color:#f92672">]</span>&0xf <span style="color:#f92672">=</span> |<span style="color:#75715e"># # # #| IHL | <-- that's right, we masked the version bits</span>
+-+-+-+-+-+-+-+-+ with 0xf or <span style="color:#ae81ff">00001111</span> in binary
+-+-+-+-+
| Data |
tcp<span style="color:#f92672">[</span>12<span style="color:#f92672">]</span> <span style="color:#f92672">=</span> | Offset|
| |
+-+-+-+-+
</code></span></span></span></span>
所以我们在这里做的是“(IP 总长度 - IP 报头长度 - TCP 报头长度)!= 0”
我们将匹配任何包含数据的数据包。
我们采用 IHL(IP 总长度)
练习:匹配其他有趣的 TCP 内容
SSH 连接(在任何端口上)
我们将寻找 SSH 服务器给出的回复。
OpenSSH 通常回复类似 “SSH-2.0-OpenSSH_3.6.1p2” 的内容。前 4 个字节 (SSH-) 的十六进制值为 .0x5353482D
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">tcpdump <span style="color:#e6db74">'tcp[(tcp[12]>>2):4] = 0x5353482D'</span>
</code></span></span></span></span>
如果我们想找到与旧版本的 OpenSSH(版本 1,不安全且容易受到 MITM 攻击)建立的任何连接。
来自服务器的回复将类似于 “SSH-1.99..”
tcpdump '(tcp[(tcp[12]>>2):4] = 0x5353482D) and (tcp[((tcp[12]>>2)+4):2] = 0x312E)'
可以在下面的参考资料部分找到解释。>>2
UDP 标头
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash"> <span style="color:#ae81ff">0</span> <span style="color:#ae81ff">7</span> <span style="color:#ae81ff">8</span> <span style="color:#ae81ff">15</span> <span style="color:#ae81ff">16</span> <span style="color:#ae81ff">23</span> <span style="color:#ae81ff">24</span> <span style="color:#ae81ff">31</span>
+--------+--------+--------+--------+
| Source | Destination |
| Port | Port |
+--------+--------+--------+--------+
| | |
| Length | Checksum |
+--------+--------+--------+--------+
| |
| DATA ... |
+-----------------------------------+
</code></span></span></span></span>
这里没什么特别有趣的。
如果我们想过滤端口,我们会使用如下内容:
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">tcpdump udp dst port <span style="color:#ae81ff">53</span>
</code></span></span></span></span>
ICMP 标头
查看不同的 ICMP 消息:
我们通常会过滤 ICMP 消息的类型(1 个字节)和代码(1 个字节)。
以下是常见的 ICMP 类型:
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash"> <span style="color:#ae81ff">0</span> Echo Reply <span style="color:#f92672">[</span>RFC792<span style="color:#f92672">]</span>
<span style="color:#ae81ff">3</span> Destination Unreachable <span style="color:#f92672">[</span>RFC792<span style="color:#f92672">]</span>
<span style="color:#ae81ff">4</span> Source Quench <span style="color:#f92672">[</span>RFC792<span style="color:#f92672">]</span>
<span style="color:#ae81ff">5</span> Redirect <span style="color:#f92672">[</span>RFC792<span style="color:#f92672">]</span>
<span style="color:#ae81ff">8</span> Echo <span style="color:#f92672">[</span>RFC792<span style="color:#f92672">]</span>
<span style="color:#ae81ff">11</span> Time Exceeded <span style="color:#f92672">[</span>RFC792<span style="color:#f92672">]</span>
</code></span></span></span></span>
我们可能想要过滤 4 类型的 ICMP 消息,这些类型的消息是在网络拥塞的情况下发送的。
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">tcpdump <span style="color:#e6db74">'icmp[0] = 4'</span>
</code></span></span></span></span>
如果我们只想查找 ICMP 回显回复,则 ID 为 500。通过查看包含所有 ICMP 数据包描述的图像,我们可以看到 ICMP 回应应答的 ID 分布在第 5 个和第 6 个字节中。出于某种原因,我们必须用 hex 的值过滤掉。
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">tcpdump -i eth0 <span style="color:#e6db74">'(icmp[0] = 0) and (icmp[4:2] = 0x1f4)'</span>
</code></span></span></span></span>
确认
-
贡献和更新:周友松(中国)
- tcp标志
- Python 十六进制转换
- portrange
- 拼写错误更正
-
出版物/参考资料:Keith Makan (南非)
- Packt Publishing 出版的《使用 Bash shell 进行渗透测试》,可在此处获取。
-
文档/参考:Tcpdump 项目
- Home | TCPDUMP & LIBPCAP
-
文档/参考:pfSense 项目
- Additional References | pfSense Documentation
-
博客文章中的参考资料:Daniel Miessler (California)
- https://danielmiessler.com/study/tcpdump/
-
论文参考:Andrés Geovanny Muñoz Ponguillo (厄瓜多尔)
- http://repositorio.ug.edu.ec/bitstream/redug/16465/1/B_CISC_PTG.1167.Mu%C3%B1oz%20Ponguillo%20Andr%C3%A9s%20Geovanny.pdf
引用
- tcpdump 手册页:tcpdump(1) man page | TCPDUMP & LIBPCAP
- 转化次数: http://easycalculation.com/hex-converter.php
- 筛选 HTTP 请求:http://www.wireshark.org/tools/string-cf.html
- 无论 TCP 选项如何,都筛选数据:http://www.wireshark.org/lists/wireshark-users/201003/msg00024.html
以防最后一个链接中的帖子消失,以下是内容的副本:
<span style="color:#ebebeb"><span style="background-color:#3b4252"><span style="color:#f8f8f2"><span style="background-color:#2e3440"><code class="language-bash">From: Sake Blok <sake@xxxxxxxxxx>
Date: Wed, <span style="color:#ae81ff">3</span> Mar <span style="color:#ae81ff">2010</span> 22:42:29 +0100
Subject: Wireshark-users: Re: <span style="color:#f92672">[</span>Wireshark-users<span style="color:#f92672">]</span> Hex Offset Needed
Or <span style="color:#66d9ef">if</span> your capturing device is capable of interpreting tcpdump style filters <span style="color:#f92672">(</span>or more accurately, BPF style filters<span style="color:#f92672">)</span>, you could use:
tcp<span style="color:#f92672">[(((</span>tcp<span style="color:#f92672">[</span>12:1<span style="color:#f92672">]</span> & 0xf0<span style="color:#f92672">)</span> >> 2<span style="color:#f92672">)</span> + 8<span style="color:#f92672">)</span>:2<span style="color:#f92672">]</span> <span style="color:#f92672">=</span> 0x2030
Which in English would be:
- take the upper <span style="color:#ae81ff">4</span> bits of the 12th octet in the tcp header <span style="color:#f92672">(</span> tcp<span style="color:#f92672">[</span>12:1<span style="color:#f92672">]</span> & 0xf0 <span style="color:#f92672">)</span>
- multiply it by four <span style="color:#f92672">(</span> <span style="color:#f92672">(</span>tcp<span style="color:#f92672">[</span>12:1<span style="color:#f92672">]</span> & 0xf0<span style="color:#f92672">)</span>>>2 <span style="color:#f92672">)</span> which should give the tcp header length
- add <span style="color:#ae81ff">8</span> <span style="color:#f92672">(</span> <span style="color:#f92672">((</span>tcp<span style="color:#f92672">[</span>12:1<span style="color:#f92672">]</span> & 0xf0<span style="color:#f92672">)</span> >> 2<span style="color:#f92672">)</span> + <span style="color:#ae81ff">8</span> <span style="color:#f92672">)</span> gives the offset into the tcp header of the space before the first octet of the response code
- now take two octets from the tcp stream, starting at that offset <span style="color:#f92672">(</span> tcp<span style="color:#f92672">[(((</span>tcp<span style="color:#f92672">[</span>12:1<span style="color:#f92672">]</span> & 0xf0<span style="color:#f92672">)</span> >> 2<span style="color:#f92672">)</span> + 8<span style="color:#f92672">)</span>:2<span style="color:#f92672">]</span> <span style="color:#f92672">)</span>
- and verify that they are <span style="color:#e6db74">" 0"</span> <span style="color:#f92672">(</span> <span style="color:#f92672">=</span> 0x2030 <span style="color:#f92672">)</span>
Of course this can give you false positives, so you might want to add a test <span style="color:#66d9ef">for</span> <span style="color:#e6db74">"HTTP"</span> and the start of the tcp payload with:
tcp<span style="color:#f92672">[((</span>tcp<span style="color:#f92672">[</span>12:1<span style="color:#f92672">]</span> & 0xf0<span style="color:#f92672">)</span> >> 2<span style="color:#f92672">)</span>:4<span style="color:#f92672">]</span> <span style="color:#f92672">=</span> 0x48545450
resulting in the filter:
tcp<span style="color:#f92672">[((</span>tcp<span style="color:#f92672">[</span>12:1<span style="color:#f92672">]</span> & 0xf0<span style="color:#f92672">)</span> >> 2<span style="color:#f92672">)</span>:4<span style="color:#f92672">]</span> <span style="color:#f92672">=</span> 0x48545450 and tcp<span style="color:#f92672">[(((</span>tcp<span style="color:#f92672">[</span>12:1<span style="color:#f92672">]</span> & 0xf0<span style="color:#f92672">)</span> >> 2<span style="color:#f92672">)</span> + 8<span style="color:#f92672">)</span>:2<span style="color:#f92672">]</span> <span style="color:#f92672">=</span> 0x2030
A bit cryptic, but it works, even when TCP options are present <span style="color:#f92672">(</span>which would mess up a fixed offset into the tcp data<span style="color:#f92672">)</span>.
Cheers,
Sake</code></span></span></span></span>