从Python访问802.11无线管理帧
我想在Linux上用Python抓取802.11管理的“探测请求”数据包。可以用Scapy这样做:
# -*- coding: utf-8 -*-
from scapy.all import *
def proc(p):
if ( p.haslayer(Dot11ProbeReq) ):
mac=re.sub(':','',p.addr2)
ssid=p[Dot11Elt].info
ssid=ssid.decode('utf-8','ignore')
if ssid == "":
ssid="<BROADCAST>"
print "%s:%s" %(mac,ssid)
sniff(iface="mon0",prn=proc)
也可以用tshark这样做:
tshark -n -i mon0 subtype probereq -R 'wlan.fc.type_subtype eq 4' -T fields -e wlan.sa -e wlan_mgt.ssid
我们可以把tshark的输出重定向,然后用Python来处理(虽然看起来不太好,但确实能用)。
不过,这两种方法都有GPL许可证,这让商业项目变得有点麻烦。因此,我想找一个更“底层”的解决方案,用Python来解决这个特定的问题。通过谷歌搜索,我找到两个可能的方向:
Pcap库:Python有三个可用的pcap库: pylibpcap、pypcap 和 pcapy。我不太确定如何将这些功能整合进去。如果有示例代码或解决方案就太好了。
原始套接字:PF_PACKET: “数据包套接字用于在设备驱动程序(OSI第二层)级别接收或发送原始数据包。它们允许用户在物理层之上实现协议模块。”
这听起来像是另一种选择,可以完全绕过pcap。我听说这种方法可能更好,因为它去掉了pcap库的开销。不过,我不太知道从哪里开始解决这个问题。
如果能提供帮助,我将非常感激。
1 个回答
8
我已经搞明白这个问题了。以下是我经历的过程:
捕获一些802.11管理的“探测请求”帧:
tshark -n -i mon0 subtype probereq -c 5 -w probe.pcap
理解RadioTap
在阅读RadioTap的文档时,我意识到RadioTap帧由以下几个部分组成:
it_version (2 bytes) - major version of the radiotap header is in use. Currently, this is always 0 it_pad (2 bytes) - currently unused it_len (4 bytes) - entire length of the radiotap data, including the radiotap header it_present (8 byte) - bitmask of the radiotap data fields that follows the radiotap header
因此,it_len可以帮助我们找到紧接着radiotap数据的802.11帧的开始位置。
用Python编写解决方案
我选择使用pylibpcap,这是我在之前的帖子中找到的三个pcap库选项之一,并且发现了dpkt模块来解析802.11帧。文档很少,所以我在Python解释器中尝试后,成功写出了以下代码,从我们的捕获文件中提取MAC地址、探测SSID和信号强度:
f = open('probe.pcap') pc = dpkt.pcap.Reader(f) dl=pc.datalink() if pc.datalink() == 127: #Check if RadioTap for timestamp, rawdata in pc: tap = dpkt.radiotap.Radiotap(rawdata) signal_ssi=-(256-tap.ant_sig.db) #Calculate signal strength t_len=binascii.hexlify(rawdata[2:3]) #t_len field indicates the entire length of the radiotap data, including the radiotap header. t_len=int(t_len,16) #Convert to decimal wlan = dpkt.ieee80211.IEEE80211(rawdata[t_len:]) if wlan.type == 0 and wlan.subtype == 4: # Indicates a probe request ssid = wlan.ies[0].info mac=binascii.hexlify(wlan.mgmt.src) print "%s, %s (%d dBm)"%(mac,ssid,signal_ssi)