交互式数据包处理程序 Scapy 入门指南
概述
Scapy 是一個強大的交互式數據包處理程序(使用python編寫)。它能夠偽造或者解碼大量的網絡協議數據包,能夠發送、捕捉、匹配請求和回復包等等。它可以很容易地處理一些典型操作,比如端口掃描,tracerouting,探測,單元測試,攻擊或網絡發現(可替代hping,NMAP,arpspoof,ARP-SK,arping,tcpdump,tethereal,P0F等)。最重要的他還有很多更優秀的特性——發送無效數據幀、注入修改的802.11數據幀、在WEP上解碼加密通道(VOIP)、ARP緩存攻擊(VLAN)等,這也是其他工具無法處理完成的。下面就先通過一些實例來學習一下 Scapy 這個強大的工具吧。
版權說明
著作權歸作者所有。
商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
本文作者:Coding-Naga
發表日期: 2016年4月13日
本文鏈接:http://blog.csdn.net/lemon_tree12138/article/details/51141440
來源:CSDN
更多內容:分類 >> 黑客的隱形衣
實驗環境
- Centos 6.5
- Python 2.6.6
- setuptools-20.7.0
- prettytable-0.7.2
- Scapy (2.3.2)
功能列表
基本測試
登入 Scapy 環境
$ scapy框架包的引入
>>> from scapy.all import *這里要注意的是不要使用右邊的這種方式導入包:*from scapy import **
查看配置信息
conf 變量保存了配置信息
>>> conf ASN1_default_codec = <ASN1Codec BER[1]> AS_resolver = <scapy.as_resolvers.AS_resolver_multi instance at 0x13c1dd0> ( 此處省略 N 行 ) verb = 2 version = '2.3.2' warning_threshold = 5 wepkey = ''查看 scapy 支持的指令集
>>> lsc() arpcachepoison : Poison target's cache with (your MAC,victim's IP) couple arping : Send ARP who-has requests to determine which hosts are up bind_layers : Bind 2 layers on some specific fields' values corrupt_bits : Flip a given percentage or number of bits from a string ( 此處省略 N 行 ) wireshark : Run wireshark on a list of packets wrpcap : Write a list of packets to a pcap file比如這里的 arping ,我們就可以這樣來使用:
arping
得到所在局域網內所有可用的ip與mac的對應關系
查看 scapy 中已實現的網絡協議
缺省參數模式
>>> ls() AH : AH ARP : ARP ASN1_Packet : None ATT_Error_Response : Error Response ATT_Exchange_MTU_Request : Exchange MTU Request ( 此處省略 N 行 ) _IPv6ExtHdr : Abstract IPV6 Option Header _MobilityHeader : Dummy IPv6 Mobility Header攜帶參數模式
>>> ls(UDP) sport : ShortEnumField = (53) dport : ShortEnumField = (53) len : ShortField = (None) chksum : XShortField = (None)ls() 中攜帶的參數可以是任何的一個具體的包,常用的有ARP、Ether、ICMP、IP、UDP、TCP,也支持SNMP、DHCP、STP等。
IP 模塊的使用
我們可以像在 python 中一樣實例化一個 IP 對象。
>>> data = IP() >>> data <IP |>也可以傳入需要自定義的參數
>>> data = IP(dst="172.16.2.79") >>> data <IP dst=172.16.2.79 |>查看 IP 模塊對象的所有信息
>>> data = IP() >>> data.show() ###[ IP ]###version= 4ihl= Nonetos= 0x0len= Noneid= 1flags=frag= 0ttl= 64proto= ipchksum= Nonesrc= 127.0.0.1dst= 127.0.0.1\options\ >>> data = IP(dst="172.16.2.79") >>> data.show() ###[ IP ]###version= 4ihl= Nonetos= 0x0len= Noneid= 1flags=frag= 0ttl= 64proto= ipchksum= Nonesrc= 172.16.2.91dst= 172.16.2.79\options\發送報文
可以將上面的 IP 對象封裝成一個數據包發送出去。
>>> send(data, iface="eth0") . Sent 1 packets.接收報文
這邊我所做的測試是,在本地開啟兩個 Putty 客戶端,遠程連接 172.16.2.91 虛擬機。 putty-1 用于 scapy 監聽接收數據包, putty-2 用于向 172.16.2.91 發送指令。這里我發送的測試指令是 ls.
測試的結果如下:
更多詳細過程,請參見下面的數據嗅探及過濾章節。
細說數據發送
在上面的基本測試階段,對發送數據進行一些常規測試。本節會是對發送數據的一個全面解析。
send
在第三層發送數據包,但沒有接收功能。
>>> send(IP(dst="www.baidu.com",ttl=1)/ICMP()) . Sent 1 packets. >>> send(IP(dst="192.168.115.188")/ICMP()) . Sent 1 packets. >>> send(IP(dst="www.baidu.com")/UDP()/NTP(version=4), loop=2) >>> send(IP(dst="www.baidu.com")/fuzz(UDP()/NTP(version=4)), loop=2)fuzz函數的作用:可以更改一些默認的不可以被計算的值(比如校驗和checksums),更改的值是隨機的,但是類型是符合字段的值的。
向某一個 IP 發送一個數據包
data_sender.py
上面的 python 代碼的功能是從 172.16.2.91/12345 每隔 1 秒就向 172.16.2.79/5555 發送 5 個相同的數據包,這個數據包中包含了三個數據,分別為:0x12, 0x4EF3, 0x76。如果在 172.16.2.79 上使用抓包工具,也是可以捕獲這個數據包的。
sendp
在第二層發送數據包,同樣沒有接收功能。
>>> sendp(Ether()/IP(dst="www.baidu.com",ttl=1)/ICMP()) . Sent 1 packets. >>> sendp(Ether()/IP(dst="192.168.115.188",ttl=(1,4)),iface="eth0") .... Sent 4 packets. >>> sendp("hello ,i am walfred ",iface="eth0",loop=1,inter=0.2)sr
在第三層發送數據包,有接收功能。
>>> sr(IP(dst="www.baidu.com")/TCP(dport=[21, 22, 23])) Begin emission: .Finished to send 3 packets. .......^C Received 8 packets, got 0 answers, remaining 3 packets (<Results: TCP:0 UDP:0 ICMP:0 Other:0>, <Unanswered: TCP:3 UDP:0 ICMP:0 Other:0>) >>> p = sr(IP(dst="www.baidu.com",ttl=1)/ICMP()) Begin emission: ....Finished to send 1 packets. ...* Received 8 packets, got 1 answers, remaining 0 packets >>> p (<Results: TCP:0 UDP:0 ICMP:1 Other:0>, <Unanswered: TCP:0 UDP:0 ICMP:0 Other:0>) >>> p[0] <Results: TCP:0 UDP:0 ICMP:1 Other:0> >>> p[0].show() 0000 IP / ICMP 172.16.2.91 > 180.97.33.108 echo-request 0 ==> IP / ICMP 172.16.2.20 > 172.16.2.91 time-exceeded ttl-zero-during-transit / IPerror / ICMPerror連續發送ttl=1,2,3,4四個包的情況
>>> p=sr(IP(dst="www.baidu.com",ttl=(1,4))/ICMP()) Begin emission: ....*.*Finished to send 4 packets. .*.* Received 11 packets, got 4 answers, remaining 0 packets >>> p (<Results: TCP:0 UDP:0 ICMP:4 Other:0>, <Unanswered: TCP:0 UDP:0 ICMP:0 Other:0>) >>> p[0].show() 0000 IP / ICMP 172.16.2.91 > 180.97.33.107 echo-request 0 ==> IP / ICMP 172.16.2.20 > 172.16.2.91 time-exceeded ttl-zero-during-transit / IPerror / ICMPerror 0001 IP / ICMP 172.16.2.91 > 180.97.33.107 echo-request 0 ==> IP / ICMP 121.225.2.1 > 172.16.2.91 time-exceeded ttl-zero-during-transit / IPerror / ICMPerror 0002 IP / ICMP 172.16.2.91 > 180.97.33.107 echo-request 0 ==> IP / ICMP 218.2.151.29 > 172.16.2.91 time-exceeded ttl-zero-during-transit / IPerror / ICMPerror / Padding 0003 IP / ICMP 172.16.2.91 > 180.97.33.107 echo-request 0 ==> IP / ICMP 202.102.69.70 > 172.16.2.91 time-exceeded ttl-zero-during-transit / IPerror / ICMPerror / Paddingsr1
在第三層發送數據包,有接收功能,但只接收第一個包。以上面的發送四個包為例
>>> q=sr1(IP(dst="www.baidu.com",ttl=(1,4))/ICMP()) Begin emission: .....*.**Finished to send 4 packets. ..* Received 12 packets, got 4 answers, remaining 0 packets >>> q <IP version=4L ihl=5L tos=0xc0 len=56 id=30311 flags= frag=0L ttl=128 proto=icmp chksum=0x670e src=172.16.2.20 dst=172.16.2.91 options=[] |<ICMP type=time-exceeded code=ttl-zero-during-transit chksum=0xf4ff reserved=0 length=0 unused=None |<IPerror version=4L ihl=5L tos=0x0 len=28 id=1 flags= frag=0L ttl=1 proto=icmp chksum=0x35a8 src=172.16.2.91 dst=180.97.33.108 options=[] |<ICMPerror type=echo-request code=0 chksum=0xf7ff id=0x0 seq=0x0 |>>>> >>> q.show(); ###[ IP ]###version= 4Lihl= 5Ltos= 0xc0len= 56id= 30311flags=frag= 0Lttl= 128proto= icmpchksum= 0x670esrc= 172.16.2.20dst= 172.16.2.91\options\ ###[ ICMP ]###type= time-exceededcode= ttl-zero-during-transitchksum= 0xf4ffreserved= 0length= 0unused= None ###[ IP in ICMP ]###version= 4Lihl= 5Ltos= 0x0len= 28id= 1flags=frag= 0Lttl= 1proto= icmpchksum= 0x35a8src= 172.16.2.91dst= 180.97.33.108\options\ ###[ ICMP in ICMP ]###type= echo-requestcode= 0chksum= 0xf7ffid= 0x0seq= 0x0srloop
在第三層工作
>>> p=srloop(IP(dst="www.baidu.com",ttl=1)/ICMP()) RECV 1: IP / ICMP 172.16.2.20 > 172.16.2.91 time-exceeded ttl-zero-during-transit / IPerror / ICMPerror RECV 1: IP / ICMP 172.16.2.20 > 172.16.2.91 time-exceeded ttl-zero-during-transit / IPerror / ICMPerror RECV 1: IP / ICMP 172.16.2.20 > 172.16.2.91 time-exceeded ttl-zero-during-transit / IPerror / ICMPerror ^C Sent 3 packets, received 3 packets. 100.0% hits. >>> p=srloop(IP(dst="www.baidu.com",ttl=1)/ICMP(),inter=3,count=2) RECV 1: IP / ICMP 172.16.2.20 > 172.16.2.91 time-exceeded ttl-zero-during-transit / IPerror / ICMPerror RECV 1: IP / ICMP 172.16.2.20 > 172.16.2.91 time-exceeded ttl-zero-during-transit / IPerror / ICMPerrorSent 2 packets, received 2 packets. 100.0% hits.這里第一條語句在執行時,將會不停的ping百度,第二條執行時每隔3秒ping一次,一共執行兩次。inter表示間隔,count記錄次數。
srp
在第二層發送數據包,有接收功能。
>>> srp(IP(dst="192.168.115.1")/TCP(dport=[21,22,23])) >>> p=srp(IP(dst="www.baidu.com",ttl=1)/ICMP())srp1
在第二層發送數據包,有接收功能,但只接收第一個包。以上面的發送四個包為例
>>> q=srp1(IP(dst="www.baidu.com",ttl=(1,4))/ICMP())srploop
在第三層工作
>>> p = srploop(IP(dst="172.16.2.79", ttl=4)/TCP()) fail 1: IP / TCP 172.16.2.91:ftp_data > 172.16.2.79:http S fail 1: IP / TCP 172.16.2.91:ftp_data > 172.16.2.79:http S fail 1: IP / TCP 172.16.2.91:ftp_data > 172.16.2.79:http S send... Sent 3 packets, received 0 packets. 0.0% hits. >>> p = srploop(IP(dst="www.baidu.com", ttl=4)/ICMP()) fail 1: IP / ICMP 172.16.2.91 > 180.97.33.107 echo-request 0 fail 1: IP / ICMP 172.16.2.91 > 180.97.33.107 echo-request 0 send... Sent 2 packets, received 0 packets. 0.0% hits.端口掃描
TCP 連接掃描
客戶端與服務器建立 TCP 連接要進行一次三次握手,如果進行了一次成功的三次握手,則說明端口開放。
# encoding=utf-8import logging logging.getLogger("scapy.runtime").setLevel(logging.ERROR) from scapy.all import *dst_ip = "180.97.33.107" # 百度 IP src_port = RandShort() dst_port = 80tcp_connect_scan_resp = sr1(IP(dst=dst_ip)/TCP(sport=src_port, dport=dst_port, flags="S"), timeout=10) if str(type(tcp_connect_scan_resp)) == "":print("Closed") elif tcp_connect_scan_resp.haslayer(TCP):if tcp_connect_scan_resp.getlayer(TCP).flags == 0x12:send_rst = sr(IP(dst=dst_ip)/TCP(sport=src_port, dport=dst_port, flags="AR"), timeout=10)print("Open") elif tcp_connect_scan_resp.getlayer(TCP).flags == 0x14:print("Closed") Begin emission: ...Finished to send 1 packets. .* Received 5 packets, got 1 answers, remaining 0 packets Begin emission: .Finished to send 1 packets. ................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................. Received 498 packets, got 0 answers, remaining 1 packets OpenTCP SYN 掃描(也稱為半開放掃描或stealth掃描)
同 TCP 連接掃描非常相似。同樣是客戶端向服務器發送一個帶有 SYN 標識和端口號的數據包,如果目標端口開發,則會返回帶有 SYN 和 ACK 標識的 TCP 數據包。但是,這時客戶端不會返回 RST+ACK 而是返回一個只帶有 RST 標識的數據包。這種技術主要用于躲避防火墻的檢測。
# encoding=utf-8import logging logging.getLogger("scapy.runtime").setLevel(logging.ERROR) from scapy.all import *dst_ip = "180.97.33.107" # 百度 IP src_port = RandShort() dst_port = 80stealth_scan_resp = sr1(IP(dst=dst_ip)/TCP(sport=src_port, dport=dst_port, flags="S"), timeout=10) if str(type(stealth_scan_resp)) == "":print("Filtered") elif stealth_scan_resp.haslayer(TCP):if stealth_scan_resp.getlayer(TCP).flags == 0x12:send_rst = sr(IP(dst=dst_ip)/TCP(sport=src_port, dport=dst_port, flags="R"), timeout=10)print("Open")elif stealth_scan_resp.getlayer(TCP).flags == 0x14:print("Closed") elif stealth_scan_resp.haslayer(ICMP):if int(stealth_scan_resp.getlayer(ICMP).type) == 3 and int(stealth_scan_resp.getlayer(ICMP).code) in [1,2,3,9,10,13]:print("Filtered") Begin emission: ...Finished to send 1 packets. ..* Received 6 packets, got 1 answers, remaining 0 packets Begin emission: Finished to send 1 packets. .......................................................................................................................................................................................................................................... Received 234 packets, got 0 answers, remaining 1 packets OpenTCP 圣誕樹(Xmas Tree)掃描
在圣誕樹掃描中,客戶端會向服務器發送帶有 PSH,FIN,URG 標識和端口號的數據包給服務器。如果目標端口是開放的,那么不會有任何來自服務器的回應。如果服務器返回了一個帶有 RST 標識的 TCP 數據包,那么說明端口處于關閉狀態。但如果服務器返回了一個 ICMP 數據包,其中包含 ICMP 目標不可達錯誤類型3以及 ICMP 狀態碼為1,2,3,9,10或13,則說明目標端口被過濾了無法確定是否處于開放狀態。
# encoding=utf-8import logging logging.getLogger("scapy.runtime").setLevel(logging.ERROR) from scapy.all import *dst_ip = "180.97.33.107" # 百度 IP src_port = RandShort() dst_port = 80xmas_scan_resp = sr1(IP(dst=dst_ip)/TCP(dport=dst_port, flags="FPU"), timeout=10) if str(type(xmas_scan_resp)) == "":print("Open|Filtered") elif xmas_scan_resp.haslayer(TCP):if xmas_scan_resp.getlayer(TCP).flags == 0x14:print("Closed") elif xmas_scan_resp.haslayer(ICMP):if int(xmas_scan_resp.getlayer(ICMP).type) == 3 and int(xmas_scan_resp.getlayer(ICMP).code) in [1,2,3,9,10,13]:print("Filtered") Begin emission: ...Finished to send 1 packets. ..................................................................................................................................................................................................................................................................................................................................................................................................................................................................... Received 456 packets, got 0 answers, remaining 1 packets Traceback (most recent call last):File "scan.py", line 12, in <module>elif(xmas_scan_resp.haslayer(TCP)): AttributeError: 'NoneType' object has no attribute 'haslayer'這里掃描百度(外網)出現異常狀況,于是將百度的 IP 地址替換成了本地的主機 IP 地址。再次執行結果如下:
Begin emission: ...Finished to send 1 packets. .* Received 5 packets, got 1 answers, remaining 0 packets ClosedTCP FIN 掃描
FIN 掃描會向服務器發送帶有 FIN 標識和端口號的 TCP 數據包。如果沒有服務器端回應則說明端口開放。如果服務器返回一個 RST 數據包,則說明目標端口是關閉的。如果服務器返回了一個 ICMP 數據包,其中包含 ICMP 目標不可達錯誤類型3以及 ICMP 代碼為1,2,3,9,10或13,則說明目標端口被過濾了無法確定端口狀態。
# encoding=utf-8import logging logging.getLogger("scapy.runtime").setLevel(logging.ERROR) from scapy.all import *dst_ip = "180.97.33.107" # 百度 IP src_port = RandShort() dst_port = 80fin_scan_resp = sr1(IP(dst=dst_ip)/TCP(dport=dst_port, flags="F"), timeout=10) if str(type(fin_scan_resp)) == "":print("Open|Filtered") elif fin_scan_resp.haslayer(TCP):if fin_scan_resp.getlayer(TCP).flags == 0x14:print("Closed") elif fin_scan_resp.haslayer(ICMP):if int(fin_scan_resp.getlayer(ICMP).type) == 3 and int(fin_scan_resp.getlayer(ICMP).code) in [1,2,3,9,10,13]:print("Filtered") Begin emission: ...Finished to send 1 packets. .......................................................................................................................................................................................................... Received 205 packets, got 0 answers, remaining 1 packets Traceback (most recent call last):File "scan.py", line 12, in <module>elif(fin_scan_resp.haslayer(TCP)): AttributeError: 'NoneType' object has no attribute 'haslayer'與 Xmas Tree 掃描類似,這里同樣切換成 172.16.2.79 的本地地址。再次測試,結果如下:
Begin emission: ...Finished to send 1 packets. .* Received 5 packets, got 1 answers, remaining 0 packets ClosedTCP 空掃描(Null)
# encoding=utf-8import logging logging.getLogger("scapy.runtime").setLevel(logging.ERROR) from scapy.all import *dst_ip = "180.97.33.107" # 百度 IP src_port = RandShort() dst_port = 80null_scan_resp = sr1(IP(dst=dst_ip)/TCP(dport=dst_port, flags=""), timeout=10) if str(type(null_scan_resp)) == "":print("Open|Filtered") elif null_scan_resp.haslayer(TCP):if null_scan_resp.getlayer(TCP).flags == 0x14:print("Closed") elif null_scan_resp.haslayer(ICMP):if int(null_scan_resp.getlayer(ICMP).type) == 3 and int(null_scan_resp.getlayer(ICMP).code) in [1,2,3,9,10,13]:print("Filtered") Begin emission: ...Finished to send 1 packets. ............................................................................................................................................................................................................. Received 208 packets, got 0 answers, remaining 1 packets Traceback (most recent call last):File "scan.py", line 12, in <module>elif(null_scan_resp.haslayer(TCP)): AttributeError: 'NoneType' object has no attribute 'haslayer'TCP ACK 掃描
import logging logging.getLogger("scapy.runtime").setLevel(logging.ERROR) from scapy.all import *dst_ip = "180.97.33.107" src_port = RandShort() dst_port=80ack_flag_scan_resp = sr1(IP(dst=dst_ip)/TCP(dport=dst_port,flags="A"),timeout=10) if (str(type(ack_flag_scan_resp))==""):print "Stateful firewall presentn(Filtered)" elif(ack_flag_scan_resp.haslayer(TCP)):if(ack_flag_scan_resp.getlayer(TCP).flags == 0x4):print "No firewalln(Unfiltered)" elif(ack_flag_scan_resp.haslayer(ICMP)):if(int(ack_flag_scan_resp.getlayer(ICMP).type)==3 and int(ack_flag_scan_resp.getlayer(ICMP).code) in [1,2,3,9,10,13]):print "Stateful firewall presentn(Filtered)" Begin emission: ...Finished to send 1 packets. .................................................................................................................................................................................................. Received 197 packets, got 0 answers, remaining 1 packets Traceback (most recent call last):File "scan.py", line 12, in <module>elif(ack_flag_scan_resp.haslayer(TCP)): AttributeError: 'NoneType' object has no attribute 'haslayer'TCP 窗口掃描
import logging logging.getLogger("scapy.runtime").setLevel(logging.ERROR) from scapy.all import *dst_ip = "180.97.33.107" src_port = RandShort() dst_port=80window_scan_resp = sr1(IP(dst=dst_ip)/TCP(dport=dst_port,flags="A"),timeout=10) if (str(type(window_scan_resp))==""):print "No response" elif(window_scan_resp.haslayer(TCP)):if(window_scan_resp.getlayer(TCP).window == 0):print "Closed"elif(window_scan_resp.getlayer(TCP).window > 0):print "Open" Begin emission: ...Finished to send 1 packets. ...................................................................................................................................................................................................................... Received 217 packets, got 0 answers, remaining 1 packets Traceback (most recent call last):File "scan.py", line 12, in <module>elif(window_scan_resp.haslayer(TCP)): AttributeError: 'NoneType' object has no attribute 'haslayer'UDP 掃描
import logging logging.getLogger("scapy.runtime").setLevel(logging.ERROR) from scapy.all import *dst_ip = "180.97.33.107" src_port = RandShort() dst_port=53 dst_timeout=10def udp_scan(dst_ip,dst_port,dst_timeout):udp_scan_resp = sr1(IP(dst=dst_ip)/UDP(dport=dst_port),timeout=dst_timeout)if (str(type(udp_scan_resp))==""):retrans = []for count in range(0,3):retrans.append(sr1(IP(dst=dst_ip)/UDP(dport=dst_port),timeout=dst_timeout))for item in retrans:if (str(type(item))!=""):udp_scan(dst_ip,dst_port,dst_timeout)return "Open|Filtered"elif (udp_scan_resp.haslayer(UDP)):return "Open"elif(udp_scan_resp.haslayer(ICMP)):if(int(udp_scan_resp.getlayer(ICMP).type)==3 and int(udp_scan_resp.getlayer(ICMP).code)==3):return "Closed"elif(int(udp_scan_resp.getlayer(ICMP).type)==3 and int(udp_scan_resp.getlayer(ICMP).code) in [1,2,9,10,13]):return "Filtered"print udp_scan(dst_ip,dst_port,dst_timeout) Begin emission: ...Finished to send 1 packets. .................................................................................................................................................................................................................................................................................................................... Received 311 packets, got 0 answers, remaining 1 packets Traceback (most recent call last):File "scan.py", line 28, in <module>print udp_scan(dst_ip,dst_port,dst_timeout)File "scan.py", line 20, in udp_scanelif (udp_scan_resp.haslayer(UDP)): AttributeError: 'NoneType' object has no attribute 'haslayer'多路掃描
這里說的多路掃描是指整合了上面所有的掃描,將這些掃描集成到一個模塊之中。使用的是網上提供的源碼 multiport.py 。
這里的源碼已經給出。可以直接復制使用,使用的命令行格式如下:
結果
+----------+------------------+--------------+---------------+---------------+---------------+---------------------------+-------------+---------------+ | Port No. | TCP Connect Scan | Stealth Scan | XMAS Scan | FIN Scan | NULL Scan | ACK Flag Scan | Window Scan | UDP Scan | +----------+------------------+--------------+---------------+---------------+---------------+---------------------------+-------------+---------------+ | 80 | Open | Open | Open|Filtered | Open|Filtered | Open|Filtered | Stateful firewall present | No response | Open|Filtered | | | | | | | | (Filtered) | | | +----------+------------------+--------------+---------------+---------------+---------------+---------------------------+-------------+---------------+TCP 路由跟蹤
route_tracking.py
# encoding=utf-8from scapy.all import *ans, unans = sr(IP(dst="www.baidu.com", ttl=(2, 25), id=RandShort())/TCP(flags=0x2)) for snd, rcv in ans:print("{0}\t{1}\t{2}".format(snd.ttl, rcv.src, isinstance(rcv.payload, TCP)))此 Demo 的功能是捕獲數據包在網絡中跳轉時的 IP 地址,以及使用的網絡協議。
[root@localhost scapy]# python route_tracking.py WARNING: No route found for IPv6 destination :: (no default route?) Begin emission: ...*.**..***.***..**.*..**..**.**.*.*.Finished to send 24 packets. *.*..*..................^C Received 62 packets, got 23 answers, remaining 1 packets 2 121.225.2.1 False 3 218.2.151.29 False 4 221.231.206.209 False 5 202.102.69.10 False 6 180.97.32.10 False 7 10.203.195.6 False 8 180.97.33.107 True 9 180.97.33.107 True 10 180.97.33.107 True 11 180.97.33.107 True 12 180.97.33.107 True 13 180.97.33.107 True 14 180.97.33.107 True 15 180.97.33.107 True 16 180.97.33.107 True 17 180.97.33.107 True 18 180.97.33.107 True 19 180.97.33.107 True 20 180.97.33.107 True 21 180.97.33.107 True 22 180.97.33.107 True 23 180.97.33.107 True 24 180.97.33.107 True數據嗅探及過濾
數據嗅探
可以使用 sniffer 函數進行嗅探流量,iface 表示使用的網卡接口,count 是嗅探包的個數。結果顯示嗅探到了 1 個 TCP 包和 2 個 UDP 包。可以輸入 pkts[i] 查看包的具體內容。
>>> receive = sniff(count=3, iface="eth0") >>> receive.show() 0000 Ether / IP / TCP 172.16.2.91:ssh > 172.16.2.79:58081 PA / Raw 0001 Ether / IP / UDP 172.16.2.52:netbios_ns > 172.16.255.255:netbios_ns / NBNSQueryRequest 0002 Ether / IP / UDP 172.16.2.60:netbios_ns > 172.16.255.255:netbios_ns / NBNSQueryRequest >>> receive[0] <Ether dst=30:5a:3a:45:1a:28 src=08:00:27:24:b8:a3 type=0x800 |<IP version=4L ihl=5L tos=0x10 len=104 id=30775 flags=DF frag=0L ttl=64 proto=tcp chksum=0x657e src=172.16.2.91 dst=172.16.2.79 options=[] |<TCP sport=ssh dport=58081 seq=3396365828 ack=2977251685 dataofs=5L reserved=0L flags=PA window=1515 chksum=0x5d25 urgptr=0 options=[] |<Raw load='$\xecruC4)\xdc\x1fY\xc1\x80\xdd\xd2\x9d\xa2"\x95\x88T\x00\x7f\xe8]\xd8\x11\xd8\x0ck,\xa2H\xd6]\xd3\xccs\x84\xef\x99p\xecl\xb2\xbft(R\xa3^\x82rS\xb7\xe0\xc8j\xad+Qh\xfc^Y' |>>>>如果這里我們不指定 count 的值,那么 scapy 將會一直處于監聽狀態,需要使用 ctrl + C 進行中斷監聽。
>>> pkts = sniff(iface="eth0") ^C>>> pkts <Sniffed: TCP:3 UDP:128 ICMP:0 Other:106>將上面嗅探到的內容寫入到一個 .pcap 數據包文件中。
>>> wrpcap("demo.pcap",pkts)現在我們做一個實驗,目的在于解析這個 demo.pcap 文件。
>>> pkts = sniff(iface="eth0",count=3) >>> pkts <Sniffed: TCP:2 UDP:0 ICMP:0 Other:1> >>> wrpcap("demo.pcap", pkts)使用 WinSCP 將 demo.pcap 文件下載到本地,再使用 WireShark 打開。如下圖:
從圖中可以看出,這與上面 sniff 嗅探到的信息一致。
這里也可以使用 scapy 內置的 pcap 文件解析工具來讀取并解析結果。
數據過濾
然而在實際應用中,我們還需要在數據嗅探的時候進行過濾操作。就在抓包工具 WireShark 中一樣。
>>> receive = sniff(iface="eth0", filter="icmp", count=3, prn=lambda x:x.sprintf("{IP:%IP.src% -> %IP.dst%\n}{Raw:%Raw.load%\n}")) >>> receive = sniff(filter="icmp", count=3, prn=lambda x:x.sprintf("{IP:%IP.src% -> %IP.dst%\n}{Raw:%Raw.load%\n}")) 172.16.2.91 -> 180.97.33.107 'd\x9a\x0cW\x00\x00\x00\x00\tF\x07\x00\x00\x00\x00\x00\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./01234567'180.97.33.107 -> 172.16.2.91 'd\x9a\x0cW\x00\x00\x00\x00\tF\x07\x00\x00\x00\x00\x00\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./01234567'172.16.2.91 -> 180.97.33.107 'e\x9a\x0cW\x00\x00\x00\x00\x97N\x07\x00\x00\x00\x00\x00\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./01234567'>>> receive <Sniffed: TCP:0 UDP:0 ICMP:3 Other:0>這里可以很明顯地看出的確是捕獲到了 3 個數據包 。而且這 3 個數據包都是基于 ICMP 協議的。因為這里對數據進行了過濾操作。
現在我們來對每個數據包進行詳細解析。
在第 0 個數據包中,我們可以分析獲得以下幾點信息:
其他兩個數據包可以做相同的分析。
現在進行一個實時處理捕獲的數據信息。實驗的過程是開啟兩個窗口,一個是用來顯示捕獲的數據包,一個是用來處理 ping 命令。如下:
>>> pkts = sniff(iface="eth0", filter="icmp", count=30, prn=lambda x: x.summary())幀與字符串的互相轉換
>>> icmp_str = str(pkts[0]) >>> icmp_str '\\\xddp\x97J\xa8\x08\x00\'$\xb8\xa3\x08\x00E\x00\x00T\x00\x00@\x00@\x01\xb6p\xac\x10\x02[\xb4a!l\x08\x00\xc4a[\x19\x00Yuo\x0cW\x00\x00\x00\x00\x8d\x92\n\x00\x00\x00\x00\x00\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./01234567' >>> recombine = Ether(icmp_str) >>> recombine <Ether dst=5c:dd:70:97:4a:a8 src=08:00:27:24:b8:a3 type=0x800 |<IP version=4L ihl=5L tos=0x0 len=84 id=0 flags=DF frag=0L ttl=64 proto=icmp chksum=0xb670 src=172.16.2.91 dst=180.97.33.108 options=[] |<ICMP type=echo-request code=0 chksum=0xc461 id=0x5b19 seq=0x59 |<Raw load='uo\x0cW\x00\x00\x00\x00\x8d\x92\n\x00\x00\x00\x00\x00\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./01234567' |>>>>偽造網絡數據包
Scapy可以對數據包進行偽造處理。下面從網上找到的一些測試方式。
在虛擬機端 172.16.2.91 上使用 Scapy 向本地主機 172.16.79 發送數據包,而本地主機則開啟一個抓包工具進行數據包的實時抓取,抓包工具這里選擇的是 WireShark。
按照常規的操作,可以使用如下指令向本地主機發送數據包:
如果只是單純的這樣進行發送數據包,WireShark 是可以捕獲到這個數據包的。結果如下:
如果將數據包的源地址修改,比如修改為如下這樣的:
>>> send(IP(src='172.16.2.90', dst="172.16.2.79")/TCP(dport=80, flags="S"))同一時間重新開啟 WireShark 捕獲,這時 WireShark 無法捕獲到與之前類似的信息了。
而如果將源地址重新修改回正確的源地址,則 WireShark 可以正常捕獲數據包信息了。
>>> send(IP(src='172.16.2.91', dst="172.16.2.79")/TCP(dport=80,flags="S"))對于以上的這個實驗,有兩個疑問:
數據包攔截
上面的偽造網絡數據包中,需要 Nfqueue 的支持。
由于對 Nfqueue 超出了本文的范圍,Nfqueue 會在下次對 Nfqueue 的研究中體現。
Ref
- http://www.cnblogs.com/xiaowuyi/p/3337189.html
- http://www.freebuf.com/sectool/94507.html
- http://www.osedu.net/article/network/2014-01-02/445.html
- http://blog.csdn.net/wang_walfred/article/details/50475912
- https://github.com/interference-security/Multiport
- http://www.secdev.org/projects/scapy/
征集
如果你也需要使用ProcessOn這款在線繪圖工具,可以使用如下邀請鏈接進行注冊:
https://www.processon.com/i/56205c2ee4b0f6ed10838a6d
總結
以上是生活随笔為你收集整理的交互式数据包处理程序 Scapy 入门指南的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 排序算法系列:Shell 排序算法
- 下一篇: LeetCode-73. Set Mat