Files
nudtns2026spring/ICMP_Directing/Experiment_Guide.md
2026-04-10 10:24:42 +08:00

10 KiB
Raw Blame History

ICMP Redirect 与 MITM 实验演示手册

本文档按“实际演示”来写,不只解释原理,还给出每个容器要执行的具体命令。

当前仓库已经包含可用脚本:

  • Labsetup/volumes/task1.py
  • Labsetup/volumes/task1_improved.py
  • Labsetup/volumes/task1_sniff_and_redirect.py
  • Labsetup/volumes/mitm_attack.py

其中:

  • task1.py 是当前更适合展示的 ICMP Redirect 发送脚本
  • task1_sniff_and_redirect.py 只在攻击者容器能看到 victim 单播流量时才适用
  • mitm_attack.py 已修复死循环重发问题,可以直接用于 MITM 展示

1. 实验目标

本实验分两部分:

  1. 演示 ICMP Redirect 攻击,尝试让 victim 把发往 192.168.60.5 的流量改走恶意路由器 10.9.0.111
  2. 演示 MITM 篡改,在恶意路由器上把 hello seedlabs 改成 hello AAAAAAAA

2. 拓扑与角色

容器 IP 作用
victim-10.9.0.5 10.9.0.5 受害者
attacker-10.9.0.105 10.9.0.105 发送 ICMP Redirect 的攻击机
malicious-router-10.9.0.111 10.9.0.111 恶意路由器,负责 MITM
router 10.9.0.11 / 192.168.60.11 合法路由器
host-192.168.60.5 192.168.60.5 目标主机

3. 启动环境

在宿主机的项目根目录执行:

cd /home/gh0s7/project/netsecurity2026/ICMP_Directing/Labsetup
docker-compose up -d
docker ps

建议先确认容器都起来了:

docker ps --format 'table {{.Names}}\t{{.Status}}'

4. 打开 5 个终端

建议分别打开以下终端,便于课堂展示:

终端 1: victim

docker exec -it victim-10.9.0.5 bash

终端 2: attacker

docker exec -it attacker-10.9.0.105 bash

终端 3: malicious-router

docker exec -it malicious-router-10.9.0.111 bash

终端 4: target host

docker exec -it host-192.168.60.5 bash

终端 5: router

docker exec -it router bash

router 终端不是必须,但展示路径时有帮助。


5. 演示前检查

在 victim 容器执行

先确认默认到目标网段的路由仍然指向合法网关:

ip route

你应该看到类似结果:

192.168.60.0/24 via 10.9.0.11 dev eth0

再清理路由缓存:

ip route flush cache

再查看当前 redirect 相关内核参数:

sysctl net.ipv4.conf.all.accept_redirects
sysctl net.ipv4.conf.eth0.accept_redirects
sysctl net.ipv4.conf.all.secure_redirects
sysctl net.ipv4.conf.eth0.secure_redirects

在 malicious-router 容器执行

先看恶意路由器的默认路由:

ip route

在 attacker 容器执行

确认脚本在共享目录里:

ls -l /volumes

6. 第一阶段: ICMP Redirect 展示

这一阶段分为两种情况:

  1. 理想情况:当前内核接受 redirectvictim 会真的改路由
  2. 当前环境常见情况victim 能收到 redirect但不会真的安装这条重定向路由

6.1 在 attacker 容器执行

先运行静态 redirect 脚本:

python3 /volumes/task1.py

这个脚本会:

  • 伪造源 IP 为合法网关 10.9.0.11
  • 伪造源 MAC 为合法网关的 MAC
  • 发送 ICMP Type 5 Redirect
  • 引用一个最小合法长度的“原始触发包”片段

如果你想把发送次数调大一点,可以这样运行:

python3 /volumes/task1.py --count 50 --interval 0.2

6.2 在 victim 容器执行

在 attacker 正在发包时,触发 victim 访问目标主机:

ping -c 3 192.168.60.5

然后检查缓存和路径:

ip route show cache
ip route get 192.168.60.5
mtr -n -r -c 2 192.168.60.5

6.3 成功时你应看到什么

理想情况下,mtr 第一跳会变成:

10.9.0.111

ip route show cache 可能出现类似:

192.168.60.5 via 10.9.0.111 dev eth0
cache <redirected>

6.4 如果没有成功,这在当前环境是正常的

我在当前环境里实际验证过:

  • victim 能收到大量 ICMP Redirect
  • 但路由没有真正切换到 10.9.0.111

原因不是脚本完全没工作,而是当前容器共享宿主机较新的 Linux 内核,对 redirect 的接受条件比实验 PDF 对应的旧环境更严格。

你可以在 victim 容器里用下面命令说明“包确实收到了”:

nstat -az | grep Redirect

如果 IcmpInRedirects 持续增加,就说明 redirect 已到达 victim 内核。

6.5 关于 task1_sniff_and_redirect.py

这个脚本只在攻击者能嗅探到 victim 发往 router 的单播 ICMP 时才适合使用:

python3 /volumes/task1_sniff_and_redirect.py

在当前 Docker bridge 拓扑里,attacker 通常看不到 victim -> router 的单播流量,所以这个脚本经常抓不到包。这不是代码语法问题,而是网络可见性问题。


7. 第二阶段: MITM 篡改展示

因为第一阶段在当前环境下可能不会真的完成“自动改路由”,所以演示时推荐手工把 victim 的目标网段路由改到恶意路由器。这一步相当于“模拟第一阶段已经成功”。

这能稳定完成第二阶段展示,而且可以清楚证明 MITM 篡改逻辑是正确的。

7.1 在 victim 容器执行

先把发往目标网段的路由改到恶意路由器:

ip route replace 192.168.60.0/24 via 10.9.0.111

验证:

ip route
mtr -n -r -c 2 192.168.60.5

此时 mtr 应该看到类似三跳:

10.9.0.111
10.9.0.11
192.168.60.5

说明流量已经先进入恶意路由器,再被转发到真实路由器和目标主机。

7.2 在 malicious-router 容器执行

关闭内核自动转发:

sysctl -w net.ipv4.ip_forward=0

然后启动 MITM 脚本:

python3 /volumes/mitm_attack.py

这个脚本只拦截:

  • 源 IP 是 10.9.0.5
  • 目的 IP 是 192.168.60.5
  • 二层目的 MAC 真正发给恶意路由器本机

因此不会再把自己重发的包抓回来无限循环。

7.3 在 target host 容器执行

启动 netcat 监听:

nc -lp 9090

这个终端要保持打开。

7.4 在 victim 容器执行

发起 TCP 连接并发送测试字符串:

printf 'hello seedlabs\n' | nc -N 192.168.60.5 9090

7.5 在 target host 容器观察结果

如果 MITM 成功,目标主机终端不会看到:

hello seedlabs

而是会看到:

hello AAAAAAAA

7.6 在 malicious-router 容器观察结果

MITM 脚本终端会打印出它截获的原始载荷,例如:

Original data: b'hello seedlabs\n'

如果脚本是错误的,常见现象是会重复打印多次同一条已经修改过的数据,说明它抓到了自己重发的包。当前仓库中的 mitm_attack.py 已修复这个问题。


8. 一次完整展示时,各容器该执行什么命令

下面是一套可以直接照着走的顺序。

宿主机执行

cd /home/gh0s7/project/netsecurity2026/ICMP_Directing/Labsetup
docker-compose up -d

victim 容器执行

ip route
ip route flush cache
sysctl net.ipv4.conf.all.accept_redirects
sysctl net.ipv4.conf.eth0.accept_redirects
ping -c 3 192.168.60.5
ip route show cache
ip route get 192.168.60.5
mtr -n -r -c 2 192.168.60.5

如果第一阶段未成功,继续执行:

ip route replace 192.168.60.0/24 via 10.9.0.111
mtr -n -r -c 2 192.168.60.5
printf 'hello seedlabs\n' | nc -N 192.168.60.5 9090

attacker 容器执行

python3 /volumes/task1.py --count 50 --interval 0.2

可选:

python3 /volumes/task1_sniff_and_redirect.py

malicious-router 容器执行

先在第一阶段前可只查看路由:

ip route

第二阶段执行:

sysctl -w net.ipv4.ip_forward=0
python3 /volumes/mitm_attack.py

target host 容器执行

nc -lp 9090

router 容器可选执行

如果老师想看正常路由器是否还在链路中,可以执行:

ip route
ip neigh

9. 现场讲解时可以这样解释

Q1: 为什么第一阶段可能失败,但第二阶段还能演示成功?

答:

  • 第一阶段依赖受害者内核真正接受 ICMP Redirect
  • 当前环境下 victim 容器共享宿主机较新的 Linux 内核,检查更严格
  • Redirect 包能到达 victim但内核未安装重定向缓存
  • 为了继续展示 MITM 的核心思想,可以手工把 victim 的路由改到恶意路由器,相当于模拟第一阶段已经成功

Q2: 为什么 task1_sniff_and_redirect.py 在当前环境未必好用?

答:

  • 它要求 attacker 能看见 victim 发往 router 的单播包
  • 当前 Docker bridge 网络通常不会把这类单播复制给 attacker
  • 所以这个脚本在当前环境里常常抓不到包

Q3: 为什么 mitm_attack.py 之前会重复打印很多次?

答:

  • 因为原脚本只按 IP 层过滤
  • 它把自己重发出去的包又抓回来处理了
  • 现在脚本额外检查二层目的 MAC 是否真的是恶意路由器本机,从而避免死循环

Q4: 为什么要关闭 ip_forward

答:

  • 如果不关,内核会直接把原始包转发出去
  • 应用层脚本来不及修改内容
  • 关闭后,脚本才能接管“抓包、改包、重发”的过程

10. 恢复环境

展示完成后,建议把 victim 的路由恢复,避免后续混淆。

在 victim 容器执行

ip route replace 192.168.60.0/24 via 10.9.0.11
ip route flush cache

在 malicious-router 容器执行

sysctl -w net.ipv4.ip_forward=1

11. 最终建议

如果你要“稳定展示给老师看”,推荐这样安排:

  1. 先演示第一阶段理论流程attacker 发 redirectvictim ping检查路径
  2. 如果当前环境没有真的安装 redirect就用 nstat -az | grep Redirect 证明 victim 已收到 redirect
  3. 然后说明由于当前内核更严格,手工把 victim 路由切到 10.9.0.111
  4. 继续演示第二阶段 MITMhello seedlabs 成功改成 hello AAAAAAAA

这样展示是完整的,逻辑也是自洽的。