介绍
最近发现火绒的IP黑名单功能不能防护ARP攻击,只能防护二层以上的网络行为,就花了点时间开发了一个自动化工具,用来检测自己是否遭受了ARP欺骗攻击。我这里开发了2个脚本,普通版和plus版,两者的区别就是后者支持了取证功能。
普通版
代码
脚本介绍:
- 脚本每隔一段时间(这里我是设置为30分钟)检查一次ARP表,如果发现存在相同的MAC地址,就意味着极有可能发生了ARP欺骗攻击
- 一旦检测到MAC地址重复,脚本就会查询重复mac地址对应的网卡名称,以弹窗的方式展示给用户
- 当用户关闭了弹窗,脚本会把可疑的ARP记录和所有的ARP记录,都存放到用户的桌面上,方便用户查看
- 我是使用了pyinstaller打包脚本来演示的:
pyinstaller.exe -F .\反ARP欺骗.py -w
import re
from subprocess import PIPE, Popen
import tkinter.messagebox
import os
import time
# 根据获取到的IP网卡地址,获知对应的网卡名字
def ip_to_name(ip):
command1 = r'ipconfig'
interface_name1 = '' # 获取到网卡的名字
p = Popen(command1, stdout=PIPE, stderr=PIPE)
stdout1, stderr1 = p.communicate()
ipconfig = stdout1.decode('gbk')
a = ipconfig.split('网适配器')
del (a[0])
for i1 in a:
if '断开连接' not in i1 and ip in i1:
interface_msg = i1.split('子网掩码')[0] # 获取每个网卡的网络信息,断开连接的网卡不予展示
interface_name1 = interface_msg.split('连接特定的 DNS 后缀')[0].replace(':', '').strip() # 获取到网卡的名字
return interface_name1
def work():
desktop_path = os.path.join(os.path.expanduser("~"), 'Desktop') # 获取桌面路径
path_result = os.path.join(desktop_path, 'evil_arp.txt') # 用来存储终端中输出的内容到一个文本中,方便用户使用数据,此为文本路径
path_result1 = os.path.join(desktop_path, 'arp.txt') # 用来存储终端中输出的内容到一个文本中,方便用户使用数据,此为文本路径
evil_arp = '' # 用来记录所有的可疑arp表项
flag = 0
command = r'arp -a'
p = Popen(command, stdout=PIPE, stderr=PIPE)
stdout, stderr = p.communicate()
arp_form = stdout.decode('gbk')
arp_list = arp_form.split('接口:')
for i2 in arp_list: # 把ARP表按照网卡进行切分
ip_and_mac = {} # 用来存放arp小表中的IP和MAC地址
mac_list = [] # 用来存储一个ARP小表中的所有mac,借此检查有无重复的mac,进而得知ARP攻击
interface_arp = i2.split('---')[0].strip() # 获取每个ARP小表的网卡地址
# 从每一个ARP小表中提取出IP地址和MAC地址,将其绑定为字典
obj = re.compile(r"(?P<ip>(\d+\x2e){3}\d+)\s+(?P<mac>(\w\w-){5}\w\w)", re.S)
result = obj.finditer(i2)
for i3 in result:
# print(i3.group('ip'), i3.group('mac'), sep=' ')
ip_and_mac[i3.group('ip')] = i3.group('mac')
# 判断有误重复的MAC地址
for i4 in ip_and_mac.values():
if i4 == 'ff-ff-ff-ff-ff-ff':
pass
else:
if i4 not in mac_list:
mac_list.append(i4)
else:
flag = 1
interface_name = ip_to_name(interface_arp) # 获知网卡名字
repeat_ip = [k for k, v in ip_and_mac.items() if v == i4] # 获知重复MAC对应的IP
msg = ''
for ri in repeat_ip:
msg += ri + '\t' + i4 + '\n'
alert_msg = interface_name + '网卡 发现ARP攻击!\n' + msg
evil_arp += alert_msg + '\n'
tkinter.messagebox.showerror('ARP攻击!ARP记录已存放至桌面!', alert_msg)
# 导出结果
if flag:
# 导出所有的ARP记录
a = open(path_result, 'w', encoding='utf8')
for r in evil_arp:
a.write(r)
a.close()
# 导出可疑的ARP记录
arp_record = r'arp -a > ' + path_result1
os.system(arp_record)
if __name__ == '__main__':
'''
脚本功能:每隔一段时间查询一次ARP表,一旦发现ARP异常,就会导出结果到桌面
'''
while True:
work()
time.sleep(30*60) # 每隔30分钟运行一次
GIF演示
plus版
代码
脚本介绍:这个脚本相较于普通版,就是添加了一个取证的功能,一旦检测到ARP欺骗,脚本会调用tshark开启抓包20秒,数据包的名字就是出现ARP欺骗的网卡的名字。(tshark在我之前的文章中已经多次运用介绍过,这里不再赘述)
打包成exe的命令:pyinstaller.exe -F .\反ARP欺骗PLUS版.py -w
import re
from subprocess import PIPE, Popen
import tkinter.messagebox
import os
import time
# 根据获取到的IP网卡地址,获知对应的网卡名字
def ip_to_name(ip):
command1 = r'ipconfig'
interface_name1 = '' # 获取到网卡的名字
p = Popen(command1, stdout=PIPE, stderr=PIPE)
stdout1, stderr1 = p.communicate()
ipconfig = stdout1.decode('gbk')
a = ipconfig.split('网适配器')
del (a[0])
for i1 in a:
if '断开连接' not in i1 and ip in i1:
interface_msg = i1.split('子网掩码')[0] # 获取每个网卡的网络信息,断开连接的网卡不予展示
interface_name1 = interface_msg.split('连接特定的 DNS 后缀')[0].replace(':', '').strip() # 获取到网卡的名字
return interface_name1
# 开启取证抓包
def qu_zheng(interface_name):
desktop_path = os.path.join(os.path.expanduser("~"), 'Desktop') # 获取桌面路径
pcap_name = interface_name + '.pcap'
path_pcap = os.path.join(desktop_path, pcap_name)
path_pcap = '"' + path_pcap + '"'
command = r'tshark.exe -D'
p = Popen(command, stdout=PIPE, stderr=PIPE)
stdout, stderr = p.communicate()
tshark = stdout.decode('utf-8')
tshark = tshark.split(')')
for i in tshark:
if interface_name in i:
interface_code = i.split('(')[0].split('.')[-1].strip() # 网卡对应的接口名称
os.system('tshark.exe -i ' + interface_code + ' -f arp -a duration:20 -w ' + path_pcap) # 抓包20秒
# 检测ARP攻击
def work():
desktop_path = os.path.join(os.path.expanduser("~"), 'Desktop') # 获取桌面路径
path_result = os.path.join(desktop_path, 'evil_arp.txt') # 用来存储终端中输出的内容到一个文本中,方便用户使用数据,此为文本路径
path_result1 = os.path.join(desktop_path, 'arp.txt') # 用来存储终端中输出的内容到一个文本中,方便用户使用数据,此为文本路径
evil_arp = '' # 用来记录所有的可疑arp表项
flag = 0
interface_name = '' # 网卡的名字
evil_interface_name = [] # 用来存储所有出现ARP欺骗问题的网卡
command = r'arp -a'
p = Popen(command, stdout=PIPE, stderr=PIPE)
stdout, stderr = p.communicate()
arp_form = stdout.decode('gbk')
arp_list = arp_form.split('接口:')
for i2 in arp_list: # 把ARP表按照网卡进行切分
ip_and_mac = {} # 用来存放arp小表中的IP和MAC地址
mac_list = [] # 用来存储一个ARP小表中的所有mac,借此检查有无重复的mac,进而得知ARP攻击
interface_arp = i2.split('---')[0].strip() # 获取每个ARP小表的网卡地址
# 从每一个ARP小表中提取出IP地址和MAC地址,将其绑定为字典
obj = re.compile(r"(?P<ip>(\d+\x2e){3}\d+)\s+(?P<mac>(\w\w-){5}\w\w)", re.S)
result = obj.finditer(i2)
for i3 in result:
# print(i3.group('ip'), i3.group('mac'), sep=' ')
ip_and_mac[i3.group('ip')] = i3.group('mac')
# 判断有误重复的MAC地址
for i4 in ip_and_mac.values():
if i4 == 'ff-ff-ff-ff-ff-ff':
pass
else:
if i4 not in mac_list:
mac_list.append(i4)
else:
flag = 1
interface_name = ip_to_name(interface_arp) # 获知网卡名字
evil_interface_name.append(interface_name)
repeat_ip = [k for k, v in ip_and_mac.items() if v == i4] # 获知重复MAC对应的IP
msg = ''
for ri in repeat_ip:
msg += ri + '\t' + i4 + '\n'
alert_msg = interface_name + '网卡 发现ARP攻击!\n' + msg
evil_arp += alert_msg + '\n'
tkinter.messagebox.showerror('ARP攻击!ARP记录已存放至桌面!', alert_msg)
# 导出结果
if flag:
# 导出所有的ARP记录
a = open(path_result, 'w', encoding='utf8')
for r in evil_arp:
a.write(r)
a.close()
# 导出可疑的ARP记录
arp_record = r'arp -a > ' + path_result1
os.system(arp_record)
# 这里走个形式,网络上一般就一个网卡会存在ARP欺骗,为了满足实验的需求,这里检查所有的网卡
for i in evil_interface_name:
qu_zheng(i)
if __name__ == '__main__':
'''
脚本功能:每隔一段时间查询一次ARP表,一旦发现ARP异常,就会导出结果到桌面,并且抓包取证
'''
while True:
work()
time.sleep(30*60)
GIF演示
更多
由于打包成exe的时候,使用了-w
,因此工具会一直运行在后台,打开任务管理器才能关闭工具。
防御
在开发脚本的时候我想了很多防御的姿势,但最终结果证明,个人电脑最好的防御措施,要么是采用"ARP双向绑定"的方法,要么是使用电脑管家(自带ARP防火墙的那种),别的找到什么好的办法。如果读者有好的思路的话,欢迎交流分享。
电脑管家
测试发现电脑管家的能力也各不相同,如下图
腾讯电脑管家
360