不知道為何,網上有些把scapy跟scrapy搞混的。scapy是一個操作網絡數據包的工具(Packet crafting),scrapy是一個屏幕抓取和web抓取框架(A Fast and Powerful Scraping and Web Crawling)...
scapy的基本用法還是參照scapy官網上的來做吧。翻譯對我來說是一件困難的事,幸虧有人已經做過類似的工作,如這篇博客Scapy使用文檔中文版。那對於一些我不確定的翻譯,我就直接使用這篇博客的。我的文章也可以看作是對於Scapy使用文檔中文版的轉載;不過我會根據自己的理解,以及結合不同網絡協議的學習,加一些注解。測試平台是linux centos7。
安裝
python3 -m pip install scapy
或者嘗試
python3
pip3 install scapy
開始使用scapy
scapy的交互式shell在終端會話中,發送數據包需要root權限,所以普通用戶需要使用sudo命令
sudo ./scapy
我這root用戶,直接使用scapy命令就好
配置終端顯示顏色
將conf.color_theme設置為下列樣式中的一種:
DefaultTheme, BrightTheme, RastaTheme, ColorOnBlackTheme, BlackAndWhite, HTMLTheme, LatexTheme
如:
conf.color_theme = BrightTheme()
交互式教程
新建一個包(packet),測一測以下代碼
此處IP創建了一個默認的數據包,使用ls(IP())可以查看IP數據包的參數
疊層(Stacking layers)
“/”操作符在兩個層之間起到一個組合的作用。當使用該操作符時,下層可以根據其上層,使它的一個或多個默認字段被重載。(您仍可以賦予您想要的值)一個字符串也可以被用作原始層。
每一個數據包都可以被建立或分解(注意:在Python中“_”(下划線)是上一條語句執行的結果):
被拆分的包保留了所有字段,如果這樣顯得太啰嗦,可以通過hide_defaults()方法刪除重復的字段
讀取PCAP文件
a=rdpcap("/spare/captures/isakmp.cap")
圖形轉儲(PDF,PS)
如果你安裝了PyX,你可以將一個包或者一系列包圖形轉儲為PostScript/PDF文件(下面是比較丑的PNG圖片,如果是PostScript/PDF格式的話質量要更好)
未安裝pyx提示:ImportError: PyX and its dependencies must be installed
a[423].pdfdump(layer_shift=1)
a[423].psdump("/tmp/isakmp_pkt.eps",layer_shift=1)
命令 |
作用 |
raw(pkt) |
組裝數據包 |
hexdumo(pkt) |
轉換成16進制 |
ls(pkt) |
列出字段值 |
pkt.summary() |
查看數據包的一行摘要 |
pkt.show() |
包的開發視圖 |
pkt.show2() |
和show一樣,但是用於組裝包上(例如,計算校驗和(checksum)) |
pkt.sprintf() |
用包字段值填充格式化字符串 |
pkt.decode_payload_as() |
改變有效載荷的解碼方式 |
pkt.psdump() |
繪制一個解釋說明的PostScript圖表 |
pkt.pdfdump() |
繪制一個解釋說明的pdf |
ptk.command |
返回一個可以生成包的scapy命令 |
生成數據包的集合/生成一組包
目前我們只是生成一個數據包。讓我們看看如何輕易地定制一組數據包。整個數據包的每一個字段(甚至是網絡層次)都可以是一組。在這里隱含地定義了一組數據包的概念,意思是在所有字段中使用笛卡爾積來生成一組數據包。
某些操作(如修改一個數據包中的字符串)無法對一組數據包使用。在這些情況下,如果您忘記展開您的數據包集合,只有您忘記生成的列表中的第一個元素會被用於組裝數據包。
(這里其實就是利用python的list生成一組數據包sets of packets)
命令 |
集合 |
summary() |
顯示每個包的摘要列表 |
nsummary() |
跟前面的一樣,並且帶有包數量 |
conversations() |
顯示會話的圖標 |
show() |
displays the preferred representation (通常用nsummary()) |
filter() |
返回一個由lambda函數過濾的包列表 |
hexdump() |
返回所有包的一個hexdump數據 |
haxraw() |
返回所有包的Raw layer 的一個hexdump數據 |
padding() |
返回一個帶有填充的包的hexdump |
nzpadding() |
返回一個非0填充的包的hexdump |
plot() |
繪制應用於數據包列表的lambda函數 |
make table() |
根據lambda函數顯示一個表格 |

ttl,即Time To Live的縮寫,該字段指定IP包被路由器丟棄之前允許通過的最大網段數量,TTL是IPv4報頭的一個8bit字段。雖然TTL從字面上翻譯,是可以存活的時間,但實際上TTL是IP數據包在計算機網絡中可以轉發的最大跳數。TTL字段由IP數據包的發送者設置,在IP數據包從源到目的的整個轉發路徑上,每經過一個路由器,路由器都會修改這個TTL字段值,具體的做法是把該TTL的值減1,然后再將IP包轉發出去。如果在IP包到達目的IP之前,TTL減少為0,路由器將會丟棄收到的TTL=0的IP包並向IP包的發送者發送 ICMP time exceeded消息。(百度百科)
錯誤提示:WARNING: Mac address to reach destination not found. Using broadcast.這個錯誤是因為應該用sendp發送而用了send
關於返回值的測試
Fuzzing
fuzz()函數可以通過一個具有隨機值、數據類型合適的對象,來改變任何默認值,但該值是不能被計算的(像校驗和那樣)。這使得可以快速建立循環模糊化測試模板。在下面的例子中,IP層是正常的,UDP層和NTP層被fuzz。UDP的校驗和是正確的,UDP的目的端口被NTP重載為123,而且NTP的版本被更變為4.其他所有的端口將被隨機分組:
備注:Fuzzing是模糊測試,通過函數隨機生成大量測試用例來測試程序。
發送並且接收包
現在,我們來做一些有趣的事,src()函數用來發送包並且接收響應。這個函數返回包及其響應,以及沒有響應的包。函數sr1()是一個變體,它只返回一個響應包(不管是發送一個包還是一組包)。這些包必須是第三層的包(IP包,ARP包等)。函數srp()做類似的事,不過它是發送第二層包(如以太包,802.3等),如果沒有應答,或者超時,會返回一個空值(比如,構建包字段填寫錯誤,返回空值)。
一個DNS查詢(rd=recursion desired)。主機192.168.5.1是我的DNS服務器。注意從我Linksys來的非空填充具有Etherleak缺陷:
>>> sr1(IP(dst="192.168.5.1")/UDP()/DNS(rd=1,qd=DNSQR(qname="www.slashdot.org"))) Begin emission: Finished to send 1 packets. ..* Received 3 packets, got 1 answers, remaining 0 packets <IP version=4L ihl=5L tos=0x0 len=78 id=0 flags=DF frag=0L ttl=64 proto=UDP chksum=0xaf38 src=192.168.5.1 dst=192.168.5.21 options='' |<UDP sport=53 dport=53 len=58 chksum=0xd55d |<DNS id=0 qr=1L opcode=QUERY aa=0L tc=0L rd=1L ra=1L z=0L rcode=ok qdcount=1 ancount=1 nscount=0 arcount=0 qd=<DNSQR qname='www.slashdot.org.' qtype=A qclass=IN |> an=<DNSRR rrname='www.slashdot.org.' type=A rclass=IN ttl=3560L rdata='66.35.250.151' |> ns=0 ar=0 |<Padding load='\xc6\x94\xc7\xeb' |>>>>
發送和接受函數族(function family)是scapy的核心。它們返回兩個列表。第一個就是發送的數據包及其應答組成的列表,第二個是無應答數據包組成的列表。為了更好地呈現它們,它們被封裝成一個對象,並且提供了一些便於操作的方法:
>>> sr(IP(dst="192.168.8.1")/TCP(dport=[21,22,23])) Received 6 packets, got 3 answers, remaining 0 packets (<Results: UDP:0 TCP:3 ICMP:0 Other:0>, <Unanswered: UDP:0 TCP:0 ICMP:0 Other:0>) >>> ans, unans = _ >>> ans.summary() IP / TCP 192.168.8.14:20 > 192.168.8.1:21 S ==> Ether / IP / TCP 192.168.8.1:21 > 192.168.8.14:20 RA / Padding IP / TCP 192.168.8.14:20 > 192.168.8.1:22 S ==> Ether / IP / TCP 192.168.8.1:22 > 192.168.8.14:20 RA / Padding IP / TCP 192.168.8.14:20 > 192.168.8.1:23 S ==> Ether / IP / TCP 192.168.8.1:23 > 192.168.8.14:20 RA / Padding
如果對於應答數據包有速度限制,你可以通過“inter”參數來設置兩個數據包之間等待的時間間隔。如果有些數據包丟失了,或者設置時間間隔不足以滿足要求,你可以重新發送所有無應答數據包。你可以簡單地對無應答數據包列表再調用一遍函數,或者去設置“retry”參數。如果retry設置為3,scapy會對無應答的數據包重復發送三次。如果retry設為-3,scapy則會一直發送無應答的數據包,直到“timeout”參數等待最后一個數據包已發送的時間。
SYN Scans
經典的SYN掃描可以通過執行下面的提示符命令初始化
上面向Google的80端口(我這里改成能ping通的其他主機地址了)發送單個SYN包,在接受單個響應時退出。
從上面的輸出可以看出,目標主機返回一個“SA”或者SYN-ACK標志標明端口是開放的。
使用其他標志位掃描一下系統的440到443端口:
>>> sr(IP(dst="192.168.1.1")/TCP(sport=666,dport=(440,443),flags="S"))
或者:
>>> sr(IP(dst="192.168.1.1")/TCP(sport=RandShort(),dport=[440,441,442,443],flags="S"))
可以對收集的數據包進行摘要(summary),來快速地瀏覽響應:
>>> ans, unans = _ >>> ans.summary() IP / TCP 192.168.1.100:ftp-data > 192.168.1.1:440 S ======> IP / TCP 192.168.1.1:440 > 192.168.1.100:ftp-data RA / Padding IP / TCP 192.168.1.100:ftp-data > 192.168.1.1:441 S ======> IP / TCP 192.168.1.1:441 > 192.168.1.100:ftp-data RA / Padding IP / TCP 192.168.1.100:ftp-data > 192.168.1.1:442 S ======> IP / TCP 192.168.1.1:442 > 192.168.1.100:ftp-data RA / Padding IP / TCP 192.168.1.100:ftp-data > 192.168.1.1:https S ======> IP / TCP 192.168.1.1:https > 192.168.1.100:ftp-data SA / Padding
進度......20%
參考
推薦
Fuzzing技術總結(Brief Surveys on Fuzz Testing)