Berkeley 数据包过滤器 (BPF)

WiresharkBeginner
立即练习

简介

欢迎来到 Berkeley 数据包过滤器 (BPF) 实验!

想象一下,你试图在嘈杂拥挤的体育场中寻找某一段特定的对话。分析原始网络流量的感觉正是如此。一台繁忙的服务器每秒可能会处理数千个数据包。为了找到你需要的特定数据,你需要一个极其精确的过滤器。

这就是 Berkeley 数据包过滤器 (BPF) 的用武之地。BPF 是一项深度集成且高效的技术,它允许你设置规则——就像一张特制的渔网——只捕获你关心的网络流量,而让其余流量悄然流过。

关键在于,过滤不仅仅是为了方便,更是为了在问题发生前减少干扰。没有过滤器,数据包分析很快就会演变成信息过载。有了过滤器,你可以将庞大而混乱的数据流转化为聚焦的问题,例如「显示来自该主机的流量」或「仅显示发往此端口的 Web 请求」。这种能力是 tcpdump 即便在大型生产环境中依然不可或缺的主要原因。

在本实验中,你将使用 tcpdump 练习编写这些 BPF 规则。你将学习如何按特定的 IP 地址过滤混乱的网络流、控制流量方向(发送与接收),以及定位特定的应用程序端口。实验结束时,你将掌握如何组合这些规则,从而精准提取你所需的特定事件。

按 IP 地址(主机/网络)过滤

过滤流量最基本的方法是聚焦于特定的机器,即通过其 IP 地址进行识别。当你运行不带任何过滤器的 tcpdump 时,它会无情地抓取所见到的每一个数据包。要让它忽略除涉及特定机器之外的所有流量,你需要使用 host 关键字后跟 IP 地址。

现在是区分两个初学者常混淆概念的好时机:接口 (interface) 是你监听的位置,而 IP 过滤器描述了你希望从该监听点获取哪些对话。换句话说,-i lo 决定了你的麦克风放在哪里,而 host 127.0.0.1 决定了你关心房间里的哪位发言者。

为了确保我们有流量可观察,你的环境中已经运行了一个后台脚本。它正在持续向你的本地机器发送数据,该机器的内部 IP 地址始终为 127.0.0.1(也称为 localhost)。

让我们捕获 5 个涉及此本地主机的数据包。我们将使用 -i lo 在本地回环接口上监听,并使用 -c 5 自动停止。

在终端中运行以下命令:

sudo tcpdump -i lo -c 5 host 127.0.0.1

你的屏幕将显示类似以下的输出:

tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on lo, link-type EN10MB (Ethernet), snapshot length 262144 bytes
10:15:32.123456 IP localhost.45678 > localhost.http-alt: Flags [S], seq 123456789, win 65495, options [mss 65495,sackOK,TS val 123456 ecr 0,nop,wscale 7], length 0
10:15:32.123489 IP localhost.http-alt > localhost.45678: Flags [S.], seq 987654321, ack 123456790, win 65483, options [mss 65495,sackOK,TS val 123456 ecr 123456,nop,wscale 7], length 0
10:15:32.124000 IP localhost > localhost: ICMP echo request, id 1234, seq 1, length 64
...
5 packets captured

请注意,在列出的每个数据包中,都出现了 localhost(这是 127.0.0.1 的友好名称)。host 过滤器具有高度的包容性:无论指定的 IP 地址是发送数据还是接收数据,它都会捕获该数据包。

如果你需要监控整个计算机群组而不是单台机器,可以将 host 关键字替换为 net(例如 net 192.168.1.0/24)。目前,我们先专注于探索单台主机。

按方向(源/目的)过滤

知道某台特定的计算机参与了对话很有帮助,但有时你需要更高的精度。想象一下邮局:你可能只想查看某人寄出的信件,而完全忽略他们收到的信件。

方向很重要,因为发送和接收流量通常回答不同的调查问题。出站流量可以揭示主机正在尝试联系的对象,这在追踪恶意软件回连或数据外泄时非常有用。入站流量可以揭示哪些服务正成为目标,这在调查针对服务器的扫描或攻击时非常有用。

BPF 提供了 src(源)和 dst(目的)修饰符来指定流量的确切方向。

让我们优化过滤器,仅捕获源自 127.0.0.1 的数据包。通过将 src 修饰符与我们之前的 host 关键字结合使用,我们可以明确告诉 tcpdump 要查找的内容。

执行以下命令:

sudo tcpdump -i lo -c 3 src host 127.0.0.1

小贴士:直接写 src 127.0.0.1 也可以,因为系统会自动推断出 host,但写成 src host 被认为是最佳实践,因为它使命令的可读性极高。

你的输出将如下所示:

tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on lo, link-type EN10MB (Ethernet), snapshot length 262144 bytes
10:20:15.555111 IP localhost.54321 > localhost.http-alt: Flags [P.], seq 1:85, ack 1, win 512, options [nop,nop,TS val 234567 ecr 234567], length 84
10:20:15.555888 IP localhost.http-alt > localhost.54321: Flags [.], ack 85, win 512, options [nop,nop,TS val 234568 ecr 234567], length 0
10:20:16.111222 IP localhost > localhost: ICMP echo request, id 5678, seq 1, length 64
3 packets captured

如果你仔细观察输出,数据包描述的第一部分(> 符号之前的部分)代表发送者(源)。因为我们是在内部回环接口上进行捕获,所以双方都显示为 localhost,但在跨越多台计算机的实际场景中,src 可以确保你只查看来自该特定地址的出站流量。

反之,如果你想作为接收者,仅观察到达机器的入站流量,只需使用 dst host 127.0.0.1 即可。

按端口和协议过滤

按 IP 地址过滤可以让我们定位到正确的机器,但现代服务器通常承担多项任务。同一台服务器可能同时充当 Web 服务器、邮件服务器和安全访问点。这些不同的服务通过使用称为端口的编号「门」来保持独立。

端口不是物理插槽,而是操作系统用来同时保持多个对话独立的逻辑编号。这就是为什么「同一主机」并不一定意味着「同一应用程序」。一台机器可能参与许多不相关的网络活动,而端口过滤可以帮助你隔离你打算研究的确切服务。

例如,常规 Web 流量几乎总是通过端口 80 流动。为了聚焦于特定服务并忽略其余流量,我们使用 port 关键字。

我们的后台脚本正在端口 8080 上静默生成 Web 流量。让我们配置 tcpdump,仅捕获通过此特定端口的数据。

运行以下命令:

sudo tcpdump -i lo -c 4 port 8080

示例输出:

tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on lo, link-type EN10MB (Ethernet), snapshot length 262144 bytes
10:25:10.123456 IP localhost.34567 > localhost.http-alt: Flags [S], seq 1122334455, win 65495, options [mss 65495,sackOK,TS val 345678 ecr 0,nop,wscale 7], length 0
10:25:10.123489 IP localhost.http-alt > localhost.34567: Flags [S.], seq 5544332211, ack 1122334456, win 65483, options [mss 65495,sackOK,TS val 345678 ecr 345678,nop,wscale 7], length 0
10:25:10.123501 IP localhost.34567 > localhost.http-alt: Flags [.], ack 1, win 512, options [nop,nop,TS val 345678 ecr 345678], length 0
10:25:10.124111 IP localhost.34567 > localhost.http-alt: Flags [P.], seq 1:85, ack 1, win 512, options [nop,nop,TS val 345679 ecr 345678], length 84
4 packets captured

你可能还记得在之前的步骤中,周围有一些 ICMP (ping) 数据包。然而,在此输出中,完全没有它们的踪迹。port 8080 过滤器成功忽略了所有不相关的杂音,提供了仅针对 Web 服务的清晰视图。

除了端口,你还可以通过直接命名协议来按广泛的网络协议进行过滤,使用 tcp、udp 或 icmp 等关键字。让我们通过仅捕获 ICMP (ping) 数据包来测试这一点,从而有效地忽略繁忙的 Web 流量。

运行此命令:

sudo tcpdump -i lo -c 2 icmp

示例输出:

tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on lo, link-type EN10MB (Ethernet), snapshot length 262144 bytes
10:28:05.999111 IP localhost > localhost: ICMP echo request, id 9012, seq 1, length 64
10:28:05.999133 IP localhost > localhost: ICMP echo reply, id 9012, seq 1, length 64
2 packets captured

使用 port 和协议关键字,你可以切断干扰,精准锁定你试图调查的应用程序。

结合逻辑运算符 (AND/OR) 使用过滤器

要真正掌握 Berkeley 数据包过滤器,我们必须学习如何将多条规则组合在一起。现实世界的调查很少是简单的;你通常需要定义非常具体的场景。

这就是 BPF 开始看起来不像是一堆关键字,而更像是一种小型数据包查询语言的地方。你正在以结构化、逻辑化的方式描述你想要的流量。在后续课程中,这种思维方式将出现在许多工具中:SIEM 搜索、入侵检测规则,甚至数据库风格的日志查询,都依赖于将广泛的数据集缩小为精确条件的相同习惯。

BPF 允许你使用标准的逻辑运算符将条件连接起来:

  • and(两条规则都必须为真)
  • or(至少一条规则为真)
  • not(规则必须明确为假)

一个重要提示:在 Linux 终端中使用这些逻辑运算符时,养成将整个 BPF 表达式用引号括起来(例如 "port 80 and tcp")的好习惯非常重要。这可以确保 Linux shell 不会意外地将你的过滤命令与系统命令混淆。

让我们测试一下。我们想要捕获严格使用 TCP 协议 且 主动发往目的端口 8080 的流量。

运行以下命令:

sudo tcpdump -i lo -c 4 "tcp and dst port 8080"

示例输出:

tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on lo, link-type EN10MB (Ethernet), snapshot length 262144 bytes
10:32:15.111222 IP localhost.45678 > localhost.http-alt: Flags [S], seq 2233445566, win 65495, options [mss 65495,sackOK,TS val 456789 ecr 0,nop,wscale 7], length 0
10:32:15.111255 IP localhost.45678 > localhost.http-alt: Flags [.], ack 3344556678, win 512, options [nop,nop,TS val 456789 ecr 456789], length 0
...
4 packets captured

在这个定制的结果中,localhost.http-alt 只出现在 > 箭头的右侧,证明我们只捕获了发往该特定端口的数据包。

最后,让我们看看 not 运算符。它对于过滤掉「已知噪声」非常有用,这样你就可以专注于未知内容。假设我们想要监控回环接口上的所有流量,除了我们在端口 8080 上的繁忙 Web 流量。

运行此命令:

sudo tcpdump -i lo -c 2 "not port 8080"

示例输出:

tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on lo, link-type EN10MB (Ethernet), snapshot length 262144 bytes
10:35:22.333444 IP localhost > localhost: ICMP echo request, id 3456, seq 1, length 64
10:35:22.333466 IP localhost > localhost: ICMP echo reply, id 3456, seq 1, length 64
2 packets captured

因为我们明确告诉 tcpdump 将端口 8080 从结果中排除,它反而平静地捕获了底层的后台 ICMP ping 数据包。通过策略性地链接 and、or 和 not,你可以打造一个极其精确的镜头,在任何网络上准确地看到你需要的内容。

总结

恭喜!你已经成功迈入了高级数据包过滤的世界。

你已经学会了如何筛选混乱的网络流以找到你真正需要的内容。你练习了使用 host 关键字定位特定计算机,并使用 src 和 dst 控制流量方向。你通过过滤特定的 port 和协议隔离了特定的应用程序。最重要的是,你学会了如何使用逻辑运算符(and、or、not)将所有这些独立的部分组合在一起,以构建外科手术般精确的搜索。

这些技能是不可或缺的。无论你是追踪异常连接的系统管理员,还是追踪复杂攻击的安全分析师,掌握 Berkeley 数据包过滤器都能确保你永远不会再被网络噪声所淹没。请继续尝试不同的组合!