Python基于Scapy实现内网ARP扫描的完整流程
本文详细介绍如何使用Python的Scapy模块进行内网ARP扫描。文章从构造单个ARP请求包开始,演示如何发送广播包并接收响应以获取目标IP对应的MAC地址。随后,通过引入队列机制和多进程处理,实现了高效的全网段IP存活检测与MAC地址采集,并提供了基于optparse参数解析的完整可执行代码示例。
前言
在前一篇文章中,我们探讨了利用Scapy实现Ping扫描的方法。本文将重点转向另一个常见场景:使用Scapy模块进行内网ARP扫描,以探测局域网内存活的主机及其硬件地址。
实现过程
在之前的文章中,我们已经介绍了如何通过Scapy伪造数据包。关于ARP包的构造细节在此不再赘述,这里主要梳理该工具的整体工作流程。
第一步,实现单个IP地址的ARP包发送与接收逻辑。
第二步,在此基础上实现多进程并发发送和接收多个ARP包,以提高扫描效率。
整体实现流程与之前的脚本逻辑较为相似,核心在于数据包的构造与响应处理。
单进程ARP包处理
数据包构造部分:
def scapy_arp_one(ip_address, queue=None):
Packet = Ether(dst='FF:FF:FF:FF:FF:FF') / ARP(op=1, hwdst='00:00:00:00:00:00:', pdst=ip_address)
请求包的发送环节:
arp = srp(Packet, timeout=0.2, verbose=False)
返回包的接收处理:
try:
reply_list = arp[0].res
if queue is None:
return reply_list[0][1].getlayer(ARP).fields['hwsrc']
else:
queue.out((ip_address, reply_list[0][1].getlayer(ARP).fields['hwsrc']))
except:
return
这里采用队列模式,主要目的是为后续多进程并发发送做准备,并妥善处理ARP包的接收逻辑。简要说明如下:当发送ARP广播包后,我们会收到一个返回包。理想情况下,应遵循“一个发送包对应一个接收包”的原则。因此,这里采用队列方式,逐个IP地址进行接收处理,并使用列表存储结果,过滤出ARP包中的硬件MAC地址信息。
完整代码示例:
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# Author:Ameng, jlx-love.com
from scapy.all import *
import sys
def scapy_arp_one(ip_address, queue=None):
Packet = Ether(dst='FF:FF:FF:FF:FF:FF') / ARP(op=1, hwdst='00:00:00:00:00:00:', pdst=ip_address)
arp = srp(Packet, timeout=0.2, verbose=False)
try:
reply_list = arp[0].res
if queue is None:
return reply_list[0][1].getlayer(ARP).fields['hwsrc']
else:
queue.out((ip_address, reply_list[0][1].getlayer(ARP).fields['hwsrc']))
except:
return
if __name__ == '__main__':
scapy_arp_one(sys.argv[1])
进一步完善与优化
既然已经掌握了使用ARP进行基本发包和收包的方法,接下来我们将编写一个能够扫描整个网段的ARP检测工具。
梳理思路:首先,需要将IP地址转换为网段内的所有IP列表,这可以借助ipaddress模块实现。其次,我们知道接收响应包是一对一的,因此可以从成对的响应包中提取所需的目标IP和源MAC地址。最后,优化代码并输出结果。在此版本中,我不再使用sys模块进行传参,而是采用一个新的模块optparse,具体使用方法可参考相关文档。
完整代码示例:
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# Author:Ameng, jlx-love.com
import time
from scapy.all import *
import ipaddress
import optparse
def scapy_arp_scan(network, ifname):
net = ipaddress.ip_network(network)
ip_addr = []
for ip in net:
ip = str(ip)
ip_addr.append(ip)
time.sleep(1)
Packet = Ether(dst='FF:FF:FF:FF:FF:FF')/ARP(op=1, hwdst='00:00:00:00:00:00', pdst=ip_addr)
arp = srp(Packet, iface = ifname, timeout = 1, verbose = False)
arp_list = arp[0].res
IP_MAC_LIST = []
for n in range(len(arp_list)):
IP = arp_list[n][1][1].fields['psrc']
MAC = arp_list[n][1][1].fields['hwsrc']
IP_MAC = [IP, MAC]
IP_MAC_LIST.append(IP_MAC)
return IP_MAC_LIST
if __name__ == '__main__':
t1 = time.time()
parser = optparse.OptionParser('用法:\n python3 scapy_arp_scan.py --network 扫描网段 --ifname 网卡名称')
parser.add_option('--network', dest = 'network', type = 'string', help = '扫描网段')
parser.add_option('--ifname', dest = 'ifname', type = 'string', help = '网卡名称')
(options, args) = parser.parse_args()
network = options.network
ifname = options.ifname
if network == None or ifname == None:
print(parser.usage)
else:
active_ip_mac = scapy_arp_scan(network, ifname)
print('存活的IP地址及对应MAC:')
for ip, mac in active_ip_mac:
print(ip, mac)
t2 = time.time()
print('所用时间为:{}'.format(int(t2 - t1)))
运行结果展示

到此,关于Python使用Scapy模块实现ARP扫描的过程介绍完毕。更多相关Python实现ARP扫描的内容,请搜索本站以前的文章或继续浏览下面的相关文章。希望大家以后多多支持本站!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













