日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

交互式数据包处理程序 Scapy 入门指南

發布時間:2025/3/20 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 交互式数据包处理程序 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的對應關系

>>> arping("172.16.2.79/80") Begin emission: Finished to send 1 packets. * Received 1 packets, got 1 answers, remaining 0 packets30:5a:3a:45:1a:28 172.16.2.79 (<ARPing: TCP:0 UDP:0 ICMP:0 Other:1>, <Unanswered: TCP:0 UDP:0 ICMP:0 Other:0>)

查看 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.
測試的結果如下:

>>> receive = sniff(filter="tcp and host 172.16.2.79", count=2) >>> receive <Sniffed: TCP:2 UDP:0 ICMP:0 Other:0> >>> receive.show() 0000 Ether / IP / TCP 172.16.2.79:58081 > 172.16.2.91:ssh A / Padding 0001 Ether / IP / TCP 172.16.2.79:61186 > 172.16.2.91:ssh PA / Raw >>> receive[0] <Ether dst=08:00:27:24:b8:a3 src=30:5a:3a:45:1a:28 type=0x800 |<IP version=4L ihl=5L tos=0x0 len=40 id=20835 flags=DF frag=0L ttl=64 proto=tcp chksum=0x8ca2 src=172.16.2.79 dst=172.16.2.91 options=[] |<TCP sport=58081 dport=ssh seq=2977133173 ack=3389913828 dataofs=5L reserved=0L flags=A window=16249 chksum=0x47bd urgptr=0 |<Padding load='\x00\x00\x00\x00\x00\x00' |>>>> >>> receive[1] <Ether dst=08:00:27:24:b8:a3 src=30:5a:3a:45:1a:28 type=0x800 |<IP version=4L ihl=5L tos=0x0 len=104 id=20838 flags=DF frag=0L ttl=64 proto=tcp chksum=0x8c5f src=172.16.2.79 dst=172.16.2.91 options=[] |<TCP sport=61186 dport=ssh seq=3311241534 ack=3819002209 dataofs=5L reserved=0L flags=PA window=16277 chksum=0x4540 urgptr=0 options=[] |<Raw load='\xc0\xday\xa2X\xe5\'=QS\xf9\x1e\xe2|\xa0\xb4\xb5Y\r\xb0e\x86\x02\x13x\x19E[\x94\x0c\xff\xec#\x1c?;W\xab\x18\xf6"\x90\'\xd9\x94\x01G\xb0\xc6\x07\x08\xc3\'\r\x7f\xa9jo\xa1\x04\xc1\\\x13y' |>>>>

更多詳細過程,請參見下面的數據嗅探及過濾章節。


細說數據發送

在上面的基本測試階段,對發送數據進行一些常規測試。本節會是對發送數據的一個全面解析。

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

import struct from scapy.all import *# data = struct.pack('=BHI', 0x12, 20, 1000) data = struct.pack('=BHI', 0x12, 0x4EF3, 0x76) pkt = IP(src='172.16.2.91', dst='172.16.2.79')/UDP(sport=12345,dport=5555)/data send(pkt, inter=1, count=5)

上面的 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 / Padding

sr1

在第三層發送數據包,有接收功能,但只接收第一個包。以上面的發送四個包為例

>>> 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= 0x0

srloop

在第三層工作

>>> 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 Open

TCP 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 Open

TCP 圣誕樹(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 Closed

TCP 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 Closed

TCP 空掃描(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 。
這里的源碼已經給出。可以直接復制使用,使用的命令行格式如下:

$ python multiport.py 180.97.33.107 -p 80

結果

+----------+------------------+--------------+---------------+---------------+---------------+---------------------------+-------------+---------------+ | 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 文件解析工具來讀取并解析結果。

>>> read_pkts = rdpcap("demo.pcap") >>> read_pkts[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=18563 flags=DF frag=0L ttl=64 proto=tcp chksum=0x9532 src=172.16.2.91 dst=172.16.2.79 options=[] |<TCP sport=ssh dport=58081 seq=3389821892 ack=2977085813 dataofs=5L reserved=0L flags=PA window=1002 chksum=0x5d25 urgptr=0 options=[] |<Raw load='\xca\xa6D\xf6w\xfdc\x0c\x814\xe9\xf1\x9e~;E\x0bm\xed\x99\x1b\xc5\xaf\xb5S\xfe\x8f\xdc\xf1\xe7Bu\x88dVM\x13\xb4Y\x0eT\xc6\xc6\x87\xc1E#\x124}\xad\xe2H\xbf\xbe\xe4\xf6\x96,\x0b\xf5\x050c' |>>>>

數據過濾

然而在實際應用中,我們還需要在數據嗅探的時候進行過濾操作。就在抓包工具 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 協議的。因為這里對數據進行了過濾操作。
現在我們來對每個數據包進行詳細解析。

>>> receive[0] <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=0xb671 src=172.16.2.91 dst=180.97.33.107 options=[] |<ICMP type=echo-request code=0 chksum=0x69d9 id=0x4e1b seq=0x1 |<Raw load='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' |>>>>

在第 0 個數據包中,我們可以分析獲得以下幾點信息:

  • 數據鏈路層:源主機的 MAC 地址為 08:00:27:24:b8:a3,而 目標主機的 MAC 地址為 5c:dd:70:97:4a:a8。且類型為 0x800(IPv4);
  • 網絡層:網絡協議的版本為 4L、IP報文頭部長度 = IHL * 4、IP數據包在計算機網絡中可以轉發的最大跳數為64、使用的網絡協議為 ICMP等等;
  • 傳輸的數據為: 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
    其他兩個數據包可以做相同的分析。
  • 現在進行一個實時處理捕獲的數據信息。實驗的過程是開啟兩個窗口,一個是用來顯示捕獲的數據包,一個是用來處理 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。
    按照常規的操作,可以使用如下指令向本地主機發送數據包:

    >>> send(IP(dst="172.16.2.79")/TCP(dport=80, flags="S"))

    如果只是單純的這樣進行發送數據包,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"))

    對于以上的這個實驗,有兩個疑問:

  • 這里無法判斷數據包在傳輸的什么位置出現問題,而致使 WireShark 無法捕獲到數據包信息。也就是說無法獲知,這是被發送端丟棄,還是被接收端拒絕;
  • 如果要說偽造網絡數據包的話,測試的結果也應該是在本地主機上捕獲到一個條記錄,這條記錄的內容是被修改之后的內容;

  • 數據包攔截

    上面的偽造網絡數據包中,需要 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 入门指南的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。