利用Python3的dpkt库进行ARP扫描

背景

正在学习网络协议,用Python写起来方便点,可以快速熟悉协议本身,也给自己补充一些Python库。

偶然看到这篇文章,讲的是Python发ARP包,发现是Python2的,这里改了一下,用Python3实现。

  

环境

Ubuntu 18.04 + Python 3.6.5 + dpkt 1.9.1

网络相关信息见代码部分。 

 

代码

#!/usr/bin/python
# -*- coding:utf-8 -*-

import dpkt
import socket
import sys
import signal
import ipaddress
import struct

my_iface = "ens33" my_mac = "00:0c:29:6a:f9:7e" my_ip = "192.168.93.151" sniff_network = "192.168.93.0/24" debug = False ETH_ADDR_BROADCAST = "ff:ff:ff:ff:ff:ff" ETH_ADDR_UNSPEC = "00:00:00:00:00:00" def eth_ntoa(buffer): mac_addr = '' for intval in struct.unpack("!BBBBBB", buffer): if intval > 15: replace_str = '0x' else: replace_str = 'x' # pythonic! mac_addr = ''.join([mac_addr, hex(intval).replace(replace_str, '')]) return mac_addr def eth_aton(buffer): intvals = buffer.split(':') rv = b'' for iv in intvals: rv += struct.pack("!B", int(iv, 16)) # 下面这种也行 # rv += bytes.fromhex(iv) return rv def build_arp(addr): arp_p = dpkt.arp.ARP() arp_p.sha = eth_aton(my_mac) arp_p.spa = socket.inet_aton(my_ip) arp_p.tha = eth_aton(ETH_ADDR_UNSPEC) arp_p.tpa = socket.inet_aton(addr) arp_p.op = dpkt.arp.ARP_OP_REQUEST packet = dpkt.ethernet.Ethernet() packet.src = eth_aton(my_mac) packet.dst = eth_aton(ETH_ADDR_BROADCAST) packet.type = dpkt.ethernet.ETH_TYPE_ARP packet.data = arp_p if debug: print(dpkt.hexdump(bytes(packet))) return packet # exits after 2 seconds def quit(sig_num, frame): print("Scan ended.") sys.exit(0) signal.alarm(2) signal.signal(signal.SIGALRM, quit) # build arp packet and send it one by one s = socket.socket(socket.PF_PACKET, socket.SOCK_RAW) s.bind((my_iface, dpkt.ethernet.ETH_TYPE_ARP)) for host in ipaddress.ip_network(sniff_network).hosts(): packet = build_arp(host.compressed) s.send(bytes(packet)) print('sniff host: ', host.compressed) # receive arp answer packets while True: data = s.recv(1024) if debug: print(dpkt.hexdump(data)) sys.stdout.flush() answer = dpkt.ethernet.Ethernet(data) answer_arp_p = answer.data answer_src_ip = socket.inet_ntoa(answer_arp_p.spa) answer_src_mac = eth_ntoa(answer_arp_p.sha) answer_dst_ip = socket.inet_ntoa(answer_arp_p.tpa) if debug: print(dpkt.hexdump(data)) if answer_arp_p.op != dpkt.arp.ARP_OP_REQUEST: if answer_dst_ip == my_ip: print("Answer: {0} is at {1}".format(answer_src_ip, my_mac))

 

测试

......
sniff host: 192.168.93.251 sniff host: 192.168.93.252 sniff host: 192.168.93.253 sniff host: 192.168.93.254 Answer: 192.168.93.2 is at 00:0c:29:6a:f9:7e Answer: 192.168.93.1 is at 00:0c:29:6a:f9:7e Answer: 192.168.93.160 is at 00:0c:29:6a:f9:7e Answer: 192.168.93.254 is at 00:0c:29:6a:f9:7e Scan ended.

 

引用

一篇讲解dpkt库和网络协议的文章,很不错,只是例子是Python2的。

DPKT CheatSheet

 

TODO

一开始用struct的pack/unpack实现,比较底层,可以熟悉协议首部的构成和位、字节,无符号等概念。

高级点的,用dpkt,里面把常见的协议都封装成了对象,用起来也很方便。

打算下一步再熟悉scapy,然后是Trex。

posted @ 2018-06-20 16:51  nidey  阅读(801)  评论(0编辑  收藏  举报