python數據包之利器scapy用法!

 

scapy介紹:python

 在python中能夠經過scapy這個庫輕鬆實現構造數據包、發送數據包、分析數據包,爲網絡編程之利器!編程

 

 

scapy安裝:網絡

pip install scapy   ======> scapy不是內置模塊,故須要額外安裝tcp

 

導入scapy方式:函數

from scapy.all import *spa

 

  

構造包:code

a = Ether()/IP(dst='114.114.114.114')/TCP(dport=80)/應用層數據對象

print(a.show())  ======> 能夠先經過a.show()函數查看數據包的構成部分,而後在構造包時就知道有哪些參數能夠填了ip

 

 

發送包:字符串

sr(IP(dst='192.168.1.0/24')/TCP(dport=(1,65535)), timeout=2)  =====>發送三層數據包,等待接收一個或多個數據包的響應(注意:當依次向每一個IP65535個端口發送完纔算執行完這個函數,而不是調用一次只發一個包,如下全部發包方式都與之同樣)

sr1()  ======> 發送三層數據包,並僅僅只等待接收一個數據包的響應

srp(Ether(dst='11:11:11:11:11:11')/IP(dst='1.1.1.1')/ICMP())   ======> 發送二層數據包,而且等待迴應(這個函數能夠編輯二層頭部,sr()不能編輯二層頭部)

send()   =======> 僅僅發送三層數據包,不等待回包(發完就拉倒了)

sendp()   =======> 僅僅發送二層數據包,不等待回包

 

  

解析回包:

一、sr

reply_packet = sr(IP(dst='114.114.114.114')/ICMP(), timeout=2)

print(reply_packet)

(<Results: TCP:0 UDP:0 ICMP:1 Other:0>, <Unanswered: TCP:0 UDP:0 ICMP:0 Other:0>)       ====>第一個元素爲接收到的包,第二個元素爲沒有收到的包

print(reply_packet[0].res)

[(<IP  frag=0 proto=icmp dst=114.114.114.114 |<ICMP  |>>, <IP  version=4 ihl=5 tos=0x0 len=28 id=32921 flags= frag=0 ttl=75 proto=icmp chksum=0xbb37 src=114.114.114.114 dst=172.20.163.23options=[] |<ICMP type=echo-reply code=0 chksum=0xffff id=0x0 seq=0x0 |<Padding  load='\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |>>>)]     ====>列表裏面爲全部回包狀況,一個元素(元組)爲一個回包. 其元組中第一個元素爲發送的包,第二個元素爲返回的包

 

查看回包各項屬性:

print(reply_packet[0].res[0][1].fields)

{'version': 4, 'ihl': 5, 'tos': 0, 'len': 28, 'id': 56445, 'flags': <Flag 0 ()>, 'frag': 0, 'ttl': 75, 'proto': 1, 'chksum': 24403, 'src': '114.114.114.114', 'dst': '172.20.163.23','options': []}

注意:這裏默認只給出了三層頭部,其實'reply_packet[0].res[0][1].fields' == 'reply_packet[0].res[0][1][0].fields',res的第三位[0]表示精確到第幾層,這裏[0]表明IP,[1]進一層到傳輸層,[2]進一步到應用層。例:

print(reply_packet[0].res[0][1][1].fields)

{'type': 0, 'code': 0, 'chksum': 65535, 'id': 0, 'seq': 0}

 

print(reply_packet[0].res[0][1][2].fields)

{'load': b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'}

 

同時也能夠直接用show方法查看包體內容,例:

print(reply_packet[0].res[0][1].show())

###[ IP ]###

  version   = 4

  ihl       = 5

  tos       = 0x0

  len       = 28

  id        = 34404

  flags     =

  frag      = 0

  ttl       = 79

  proto     = icmp

  chksum    = 0xb16c

  src       = 114.114.114.114

  dst       = 172.20.163.23

  \options   \

###[ ICMP ]###

     type      = echo-reply

     code      = 0

     chksum    = 0xffff

     id        = 0x0

     seq       = 0x0

###[ Padding ]###

        load      = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

 

總結: 到reply_packet[0].res[0][1]這一層就至關因而真正的回包包體了,包體能夠用fields屬性(返回字典)show方法(返回字符串)來查看其內容. 而前面幾層都是對數據包的一些統計描述.

 

 

2sr1

reply_packet = sr1(IP(dst='114.114.114.114')/ICMP(), timeout=2)

print(reply_packet)   =====>    b'E\x00\x00\x1c\xe0\xd8\x00\x00H\x01]\xf8rrrr\xac\x14\xa3\x17\x00\x00\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

sr1返回的對象沒有太多複雜東西,直接至關於sr返回對象的reply_packet[0].res[0][1],能夠理解爲sr1返回的對象是sr返回對象的一個子集.

 

print(reply_packet.fields)   ====>    {'version': 4, 'ihl': 5, 'tos': 0, 'len': 28, 'id': 19164, 'flags': <Flag 0 ()>, 'frag': 0, 'ttl': 66, 'proto': 1, 'chksum': 63988, 'src': '114.114.114.114', 'dst': '172.20.163.23', 'options': []}

sr1reply_packet == srreply_packet[0].res[0][1], 因此能夠和sr同樣直接用fields來讀取其內容.

 

 

3srp

reply_packet = srp(Ether(dst='00:23:89:bb:c7:85')/IP(dst='114.114.114.114')/ICMP())

print(reply_packet[0].res[0][1].fields)    =====>   {'dst': '00:0c:29:d9:3f:63', 'src': '00:23:89:bb:c7:85', 'type': 2048}

注意:這裏默認只給出了二層頭部,能夠經過調節res後第三位的值來選擇性查看每層信息,res的第三位[0]表示精確到第幾層,[0]表明二層,[1]進一層到IP,[2]進一步到傳輸層,[3]進一步到應用層

例:

print(reply_packet[0].res[0][1][1].fields)   =====> {'version': 4, 'ihl': 5, 'tos': 0, 'len': 28, 'id': 62339, 'flags': <Flag 0 ()>, 'frag': 0, 'ttl': 67, 'proto': 1, 'chksum': 20557, 'src': '114.114.114.114', 'dst': '172.20.163.23', 'options': []}

 

print(reply_packet[0].res[0][1][2].fields)       =====> {'type': 0, 'code': 0, 'chksum': 65535, 'id': 0, 'seq': 0}

 

print(reply_packet[0].res[0][1][3].fields)        ======> {'load': b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'}

 

 

 

抓包、分析包:

# prn指向一個回調函數,意爲將收到的包丟給prn指向的函數處理(注意:回調的意義!每收到一個包就丟到回調函數裏執行一下,執行完了纔再跑回來繼續抓包)

# filter爲包過濾規則(語法參照tcpdump過濾規則)

# store爲是否要存儲抓到的包(注意,若是沒有存儲則不會將抓到的包賦值給a,由於沒有存下就沒有東西能夠賦,此參數默認開啓)

# timeout爲抓包時長,好比抓30秒就結束(注意:若是沒有指定抓包時長則會一直抓下去,程序會一直卡在這裏)

# iface爲指定抓包的網卡

 

a = sniff(prn=abc, filter='tcp port 80 and ip 192.168.1.1', store=1, timeout=30, iface='eth0')   

wrpcap('packet.cap', a)    ======> 此函數能夠將抓到的包存到本地(注意:將包寫入本地不能使用open'packet.cap', 'r',由於open函數只能寫入字符串)。

  

bbb = rdpcap('/root/桌面/ftp_pcapng.cap')  =======> 此函數能夠將本地存儲的數據包讀取出來

for i in bbb: =======> 讀取出來的對象是由N個數據包組成的可迭代對象,每次迭代一個包

    try: ======> 有些包可能沒有要提取的對象,當提取包裏沒有的屬性時則會報錯,因此捕獲異常好讓程序繼續往下執行

        print(i.getlayer('Raw').fields['load'].decode().strip())     ======> 輸出數據包的應用層負載

    except :

        continue

相關文章
相關標籤/搜索