我使用的環境為:Windows10、python3.6、scapy 2.4.0
一、基本知識
Sniff方法定義:
sniff(filter="",iface="any", prn=function, count=N)
filter的規則使用 Berkeley Packet Filter (BPF)語法
iface用來指定要在哪個網絡接口上進行抓包(通常不指定即所有網絡接口)
prn指定回調函數,每當一個符合filter的報文被探測到時,就會執行回調函數,通常使用lambda表達式來寫回調函數
count指定最多嗅探多少個報文(是指符合filter條件的報文,而非所有報文)
filter寫法舉例:
抓取源地址為 www.baidu.com 的報文:
>>> sniff(filter="ip src www.baidu.com", iface=ifs, prn=lambda x:x.summary(), count=3)
Ether / IP / TCP 14.215.177.39:https > 192.168.2.204:6593 A / Padding
Ether / IP / TCP 14.215.177.39:https > 192.168.2.204:6593 A / Padding
Ether / IP / TCP 14.215.177.39:https > 192.168.2.204:6593 A / Raw
Out[15]: <Sniffed: TCP:3 UDP:0 ICMP:0 Other:0>
抓取目的地址網段為192.168.2.204/24的報文,沒有設置count,所以會一直輸出:
>>> sniff(filter="dst net 192.168.2.204", iface=ifs, prn=lambda x:x.summary())
Ether / IP / TCP 180.97.162.191:8202 > 192.168.2.204:4963 PA / Raw
Ether / IP / TCP 180.97.162.191:8202 > 192.168.2.204:4963 PA / Raw
Ether / IP / TCP 180.97.162.191:8200 > 192.168.2.204:4967 PA / Raw / Padding
Ether / IP / TCP 180.97.162.191:8202 > 192.168.2.204:4963 PA / Raw
。。。
抓取非ICMP的報文:
>>> sniff(filter="not icmp", iface=ifs, prn=lambda x:x.summary(), count=3)
Ether / IP / TCP 192.168.2.204:4963 > 180.97.162.191:8202 A
Ether / IP / TCP 180.97.162.191:8202 > 192.168.2.204:4963 PA / Raw
Ether / IP / TCP 192.168.2.204:4962 > 180.97.162.191:8202 A
Out[9]: <Sniffed: TCP:3 UDP:0 ICMP:0 Other:0>
prn函數舉例:
將抓取到的報文的summary打印出來:
>>> sniff(filter="", iface=ifs, prn=lambda x:x.summary(), count=3)
Ether / IP / TCP 180.97.162.191:8202 > 192.168.2.204:4963 PA / Raw
Ether / IP / TCP 192.168.2.204:4963 > 180.97.162.191:8202 A
Ether / IP / TCP 180.97.162.191:8202 > 192.168.2.204:4963 PA / Raw
<Sniffed: TCP:3 UDP:0 ICMP:0 Other:0>
將所有IP報文的源地址打印出來:
>>> sniff(filter="", iface=ifs, prn=lambda x:x[IP].src, count=3)
180.97.162.191
192.168.2.204
14.215.177.39
<Sniffed: TCP:3 UDP:0 ICMP:0 Other:0>
也可使用回調函數:
def packet_callback(packet):
print packet.show()
sniff(prn=packet_callback, count=10)
二、代碼示例
import os
from scapy.all import sniff,wrpcap,Raw,IP,TCP
def get_pcap(ifs,ip=None,size=100):
''' 獲取指定 ifs(網卡), 指定數量size 的數據包;
如果有指定ip,則這里只接收tcp,80端口,指定ip的包 '''
filter = ""
if ip:
filter += "ip src %s and tcp and tcp port 80"%ip
dpkt = sniff(iface=ifs,filter=filter,count=size)
else:
dpkt = sniff(iface=ifs,count=size)
# wrpcap("pc1.pcap",dpkt) # 保存數據包到文件
return dpkt
def get_ip_pcap(ifs,sender,size=100):
''' 獲取指定 ifs(網卡), 指定發送方 sender(域名或ip) 的數據包
size:(一次獲取數據包的數量) '''
if 'www.' in sender:
v = os.popen('ping %s'%sender).read()
ip = v.split()[8]
print("准備接收IP為 %s 的數據包..."%ip)
else:
ip = sender
print("准備接收IP為 %s 的數據包..."%ip)
count = 0
while count<10:
d = get_pcap(ifs,ip=sender,size=size)
for i in d:
try:
if i[IP].src==ip: # 發送方的IP為:ip 接收方的IP:i[IP].dst==ip
print(i[Raw].load)
except:
pass
count+=1
def main():
ifs = 'Realtek PCIe GBE Family Controller' # 網卡
ip = "116.4.8.127" # ip地址,也可寫域名,如:www.baidu.com
get_ip_pcap(ifs,ip,size=1) # 一次接收一個包
if __name__ =='__main__':
main()
保存文件為:grab_unpack.py
然后打開網站頁面,是一個動態刷新的圖
執行:python grab_unpack.py
輸出結果: