10 KiB
ICMP Redirect 与 MITM 实验演示手册
本文档按“实际演示”来写,不只解释原理,还给出每个容器要执行的具体命令。
当前仓库已经包含可用脚本:
Labsetup/volumes/task1.pyLabsetup/volumes/task1_improved.pyLabsetup/volumes/task1_sniff_and_redirect.pyLabsetup/volumes/mitm_attack.py
其中:
task1.py是当前更适合展示的 ICMP Redirect 发送脚本task1_sniff_and_redirect.py只在攻击者容器能看到 victim 单播流量时才适用mitm_attack.py已修复死循环重发问题,可以直接用于 MITM 展示
1. 实验目标
本实验分两部分:
- 演示 ICMP Redirect 攻击,尝试让
victim把发往192.168.60.5的流量改走恶意路由器10.9.0.111 - 演示 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 展示
这一阶段分为两种情况:
- 理想情况:当前内核接受 redirect,victim 会真的改路由
- 当前环境常见情况: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. 最终建议
如果你要“稳定展示给老师看”,推荐这样安排:
- 先演示第一阶段理论流程:attacker 发 redirect,victim ping,检查路径
- 如果当前环境没有真的安装 redirect,就用
nstat -az | grep Redirect证明 victim 已收到 redirect - 然后说明由于当前内核更严格,手工把 victim 路由切到
10.9.0.111 - 继续演示第二阶段 MITM,把
hello seedlabs成功改成hello AAAAAAAA
这样展示是完整的,逻辑也是自洽的。