通過擺弄python scapy模塊 了解網路模型--Get your hands dirty!
什麼是scapy?
官方文檔
Welcome to Scapy』s documentation!
Scapy是一個強大的互動式數據包處理程序(使用python編寫)。它能夠偽造或者解碼大量的網路協議數據包,能夠發送、捕捉、匹配請求和回復包等等。它可以很容易地處理一些典型操作,比如埠掃描,tracerouting,探測,單元 測試,攻擊或網路發現(可替代hping,NMAP,arpspoof,ARP-SK,arping,tcpdump,tethereal,P0F等)。 最重要的他還有很多更優秀的特性——發送無效數據幀、注入修改的802.11數據幀、在WEP上解碼加密通道(VOIP)、ARP緩存攻擊(VLAN) 等,這也是其他工具無法處理完成的。
辨:而 scrapy 是一個快速、高層次的屏幕抓取和web抓取框架,用於抓取web站點並從頁面中提取結構化的數據。Scrapy用途廣泛,可以用於數據挖掘、監測和自動化測試。總之,我們可以用scapy做點嘿嘿嘿的事。不過這篇文章只能讓你對scapy的使用方法有一個基本的了解。下一篇文章我們就可以用這些知識來寫一個arp欺騙(arpspoofing)程序,嘿嘿嘿。
安裝scapy
pip install scapy 或者pip3 install scapy
首先你的電腦要安裝有python2,或者python3,不同的操作系統安裝可能會出現不一樣的問題。親測linux安裝過程比較順利,mac系統下無論是pip還是pip3都出現了問題,pip安裝出現了缺少依賴包,pip3安裝缺少libdnet.so,裝好了以後還出現了許可權問題,這裡就不多討論,百度不夠就谷歌吧!
好了假設你順利安裝好了scapy,也就是在python(或python3)的交互中輸入from scapy.all import *
不會報錯,那咱就繼續。
用scapy構造數據包
在 Scapy 中可以用特別簡單的方法來構造一個數據包,比如構造一個 IP 包,並傳入一些參數
>>> from scapy.all import *>>> ip_packet = IP(dst=172.20.63.254,ttl=80)<IP ttl=80 dst=172.20.63.254 |>通過ls()我們可以看到"IP"中的選項>>> ls(IP)version : BitField = (4)ihl : BitField = (None)tos : XByteField = (0)len : ShortField = (None)id : ShortField = (1)flags : FlagsField = (0)frag : BitField = (0)ttl : ByteField = (64)proto : ByteEnumField = (0)chksum : XShortField = (None)src : Emph = (None)dst : Emph = (127.0.0.1)options : PacketListField = ([])
第一個例子中,我們創建了一個ip包,定義了它的目標地址dst,存活時間ttl,可以看到還有其他的選項,這些選項可以用於定製ip頭部的一切信息。
header不管叫報文還是首部還是頭部,本文一律稱為頭部
同樣的,用scapy構造一個TCP包也非常簡單
>>> tcp_packet = TCP(sport=8888, dport=80)>>> tcp_packet<TCP sport=ddi_tcp_1 dport=http |># 同樣,TCP也可以「個性化定製」,而且非常方便!>>> ls(TCP)sport : ShortEnumField = (20)dport : ShortEnumField = (80)seq : IntField = (0)ack : IntField = (0)dataofs : BitField = (None)reserved : BitField = (0)flags : FlagsField = (2)window : ShortField = (8192)chksum : XShortField = (None)urgptr : ShortField = (0)options : TCPOptionsField = ({})
好了,看到這,我們就可以用這些工具搞點嘿嘿嘿的事了,比如,我們可以假裝是小明,給小紅髮信息
還記得在
DeepWeaver:自從學了計算機網路,室友終於不在半夜打遊戲了-- ping/ICMP學以致用
中的那個比喻了嗎?小明對小紅一片痴情,他們總是相互寫信溝通,一封信就是一個ip包裹。但是我們這次想要搞點惡作劇,比如代小明給小紅髮消息,下面的payload里裝的就是我們的消息。
ming_ip = "172.20.63.57" # 我們要代替小明發信息hong_ip = "172.20.72.23" # 收信人小紅ming_port = 9999 # source port (sport)hong_port = 80 # destination port (dport)payload = "Xiao Hong, I love you!" # packet payload 包的載荷,我們的嘿嘿嘿spoofed_packet = IP(src=ming_ip, dst=hong_ip) / TCP(sport=ming_port, dport=hong_port) / payload#我們製作了一個ip包,#這個包假冒小明的名字(源地址source/src),#發給了小紅(目的地址destination/dst)#包里裝的是我們仿造的小明的表白信>>> print(spoofed_packet)WARNING: Unless called manually, this could indicate deprecated use. Should be changed to bytes(self)b"Ex00x00>x00x01x00x00@x06x9b@xacx14?9xacx14Hx17x0fx00Px00x00x00x00x00x00x00x00Px02 x00xd4[x00x00Xiao Hong, I love you!">>> send(spoofed_packet).Sent 1 packets.#發送完畢
『/』符號被重載為「疊加」,上面我們把IP()/TCP()/payload很自然的表示這個ip包裡邊兒是個tcp,tcp裡邊裝了我們的payload內容。而這個spoofed_packet就像漢堡一樣,是一層一層累好了的IP包,非常方便。舉一反三,send(IP(dst="192.168.1.1")/ICMP())
這條程序其實就可以理解為在命令行中ping 192.168.1.1
只不過只是發送icmp,而木有接收部分罷了。
你可能現在已經開始動起了歪腦筋,如果我裝作小明給小紅髮的郵件堆積如山,是不是就能把小紅家門擠得水泄不通?傳送門在下面,走好不送。
TCP/IP攻擊_百度百科
構造ARP包
ARP(op=1, hwdst="ff:ff:ff:ff:ff:ff", pdst=ip_address)#arp類的構造函數列表:>>> ls(ARP)hwtype : XShortField = (1)ptype : XShortEnumField = (2048)hwlen : ByteField = (6) plen : ByteField = (4)op : ShortEnumField = (1) 取值為1或者2,代表ARP請求或者響應包。hwsrc : ARPSourceMACField = (None) 發送方Mac地址。psrc : SourceIPField = (None) 發送方IP地址。hwdst : MACField = (00:00:00:00:00:00) 目標Mac地址。pdst : IPField = (0.0.0.0) 目標IP地址。
構造Ether包
ether_pkt = Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(op=1, pdst=ip_address)>>> ls(Ether)dst : DestMACField = (None) 目的MACsrc : SourceMACField = (None) 源MACtype : XShortEnumField = (36864)這個op選項很重要,1為ARP請求,2為ARP應答構造一個乙太網數據包通常需要指定目標和源MAC地址,如果不指定,默認發出的就是廣播包ff:ff:ff:ff:ff:ff
乙太網目的地址:接收方設備的硬體地址(48bit,目的地址全為1的特殊地址是廣播地址)。
乙太網源地址:發送方的硬體地址幀類型:表示後面數據的類型(其中,0x0806表示後面的數據是屬於ARP包的,其他還可能屬於IP包)。硬體類型:表示硬體地址的類型(其中,值為1表示乙太網地址,其他還可能表示令牌環地址)。
協議類型:表示要映射的協議地址類型(其中,0x0800表示IP地址,其他還可能是ICMP/IGMP)。硬體地址長度:指出該報文中硬體地址的長度(ARP報文中,它的值為6)。協議地址長度:指出該報文中協議地址的長度(ARP報文中,它的值為4)。op:操作欄位,共有4種類型(1.ARP請求,2.ARP應答,3.RARP請求,4.RARP應答)。發送端乙太網地址:發送方設備的硬體地址。發送端IP地址:發送方設備的IP地址。目的乙太網地址:接收方設備的硬體地址。目的IP地址:接收方設備的IP地址。
除了以上的五種(IP,TCP,ICMP,ARP,Ether)常用的以外還有很多其他的,有好多好多這裡就不一一列舉了,大家可以一個一個的探索,用法可以用ls(...)查看。可以直接輸入ls()
來查看scapy支持的全部網路協議,括弧中為空。
忘了說了,通過show()
可以查看包內容,比如我們剛才給小紅寫的假信:
>>> spoofed_packet.show()###[ IP ]### version = 4 ihl = None tos = 0x0 len = None id = 1 flags = frag = 0 ttl = 64 proto = tcp chksum = None src = 172.20.63.57 dst = 172.20.72.23 options ###[ TCP ]### sport = distinct dport = http seq = 0 ack = 0 dataofs = None reserved = 0 flags = S window = 8192 chksum = None urgptr = 0 options = {}###[ Raw ]### load = Xiao Hong, I love you! 啥都有誒!!!!!開心??
用scapy發送與接收數據包
1. send() 與sendp()
剛才我們了解了send()可以用來直接發送我們的IP包,sendp()也可以用來發送,但是發送的東西不太一樣。我們在交互模式中通過help()查看幫助
>>>help(send)Help on function send in module scapy.sendrecv:send(x, inter=0, loop=0, count=None, verbose=None, realtime=None, *args, **kargs) Send packets at layer 3 send(packets, [inter=0], [loop=0], [verbose=conf.verb]) -> None
Send packets at layer 3
>>>help(sendp)Help on function sendp in module scapy.sendrecv:sendp(x, inter=0, loop=0, iface=None, iface_hint=None, count=None, verbose=None, realtime=None, *args, **kargs) Send packets at layer 2 sendp(packets, [inter=0], [loop=0], [verbose=conf.verb]) -> None
Send packets at layer 2
send()作用於第三層(從下往上數)網路層,所以我們可以用它來send(IP()/TCP())
,但是不能send(Ether()/IP()/TCP())
,sendp()才能發送第二層的協議,比如sendp(Ether()/IP()/TCP())
2. sr() 與srp()
你可能會想,難道只有發送這個功能嗎?是不是會對應有個receive()函數?這裡scapy提供了兩個函數,sr()和srp()顧名思義,sr的意思就是send-receive,sr對應第二層,srp對應第三層網路協議。這個函數返迴響應和未響應的數據包。返回值是一個tuple,裡邊有倆列表,result和unanswered,說實話我不知道第二個是幹嘛用的,第一個的用法如下
result, unans = sr(ARP(op=1, hwdst="ff:ff:ff:ff:ff:ff", pdst=172.20.63.57), retry=2, timeout=10)>>> result.show()0000 ARP who has 172.20.63.57 says 172.20.64.88 ==> ARP is at 78:4f:43:7a:9d:c6 says 172.20.63.57>>> for s, r in resp:... print(r[ARP].hwsrc)...78:4f:43:7a:9d:c6 # 可以通過這樣拿到想要的mac地址
sniff()嗅探抓包
>>>help(sniff)sniff(count=0, store=1, offline=None, prn=None, lfilter=None, L2socket=None, timeout=None, opened_socket=None, stop_filter=None, iface=None, *arg, **karg) Sniff packets sniff([count=0,] [prn=None,] [store=1,] [offline=None,] [lfilter=None,] + L2ListenSocket args) -> list of packets count: number of packets to capture. 0 means infinity store: wether to store sniffed packets or discard them prn: function to apply to each packet. If something is returned, it is displayed. Ex: ex: prn = lambda x: x.summary() lfilter: python function applied to each packet to determine if further action may be done ex: lfilter = lambda x: x.haslayer(Padding) offline: pcap file to read packets from, instead of sniffing them timeout: stop sniffing after a given time (default: None) L2socket: use the provided L2socket opened_socket: provide an object ready to use .recv() on stop_filter: python function applied to each packet to determine if we have to stop the capture after this packet ex: stop_filter = lambda x: x.haslayer(TCP) iface: interface or list of interfaces (default: None for sniffing on all interfaces)
sniff(count=0, store=1, offline=None, prn=None, lfilter=None, L2socket=None, timeout=None, opened_socket=None, stop_filter=None, iface=None)
>>> from scapy.all import *>>> sniff(count=20)抓20個包>>> sniff(count=0, timeout=5, iface="en0") 不限抓包個數,5秒結束, 選擇網卡en0>>> a = sniff(count=10, prn=lambda x:x.summary()) 抓10個包,通過summary函數列印出來Ether / IP / TCP 125.39.133.139:http_alt > 172.20.63.57:63392 PA / RawEther / IP / TCP 172.20.63.57:63392 > 125.39.133.139:http_alt AEther / IP / TCP 172.20.63.57:63392 > 125.39.133.139:http_alt PA / RawEther / IP / TCP 172.20.63.57:63392 > 125.39.133.139:http_alt PA / RawEther / IP / TCP 125.39.133.139:http_alt > 172.20.63.57:63392 AEther / IP / TCP 125.39.133.139:http_alt > 172.20.63.57:63392 PA / RawEther / IP / TCP 172.20.63.57:63392 > 125.39.133.139:http_alt AEther / IP / TCP 172.20.63.57:63412 > 47.104.136.229:xtgui PA / RawEther / IP / TCP 47.104.136.229:xtgui > 172.20.63.57:63412 PA / RawEther / IP / TCP 172.20.63.57:63412 > 47.104.136.229:xtgui A<Sniffed: TCP:10 UDP:0 ICMP:0 Other:0>通過wrpcap把a保存在文件demo.pcap中>>> wrpcap("demo.pcap", a)------------------------------------------------------------------------------------------------------------------------------->>> b = sniff(offline = "./demo.pcap") 通過offline參數導入文件demo.pcap保存在b中>>> b.summary() 查看b...etc.>>> b b裡面有些啥<Sniffed: TCP:10 UDP:0 ICMP:0 Other:0> # 共10個TCP包>>> b.summary() 通過summary()函數查看內容Ether / IP / TCP 172.20.63.57:64906 > 209.250.234.198:57985 PA / RawEther / IP / TCP 209.250.234.198:57985 > 172.20.63.57:64906 AEther / IP / TCP 209.250.234.198:57985 > 172.20.63.57:64906 PA / RawEther / IP / TCP 172.20.63.57:64906 > 209.250.234.198:57985 AEther / IP / TCP 209.250.234.198:57985 > 172.20.63.57:64906 A / RawEther / IP / TCP 209.250.234.198:57985 > 172.20.63.57:64906 A / RawEther / IP / TCP 172.20.63.57:64906 > 209.250.234.198:57985 AEther / IP / TCP 209.250.234.198:57985 > 172.20.63.57:64906 PA / RawEther / IP / TCP 172.20.63.57:64906 > 209.250.234.198:57985 AEther / IP / TCP 209.250.234.198:57985 > 172.20.63.57:64906 PA / Raw>>> b.show()0000 Ether / IP / TCP 172.20.63.57:64906 > 209.250.234.198:57985 PA / Raw0001 Ether / IP / TCP 209.250.234.198:57985 > 172.20.63.57:64906 A0002 Ether / IP / TCP 209.250.234.198:57985 > 172.20.63.57:64906 PA / Raw0003 Ether / IP / TCP 172.20.63.57:64906 > 209.250.234.198:57985 A0004 Ether / IP / TCP 209.250.234.198:57985 > 172.20.63.57:64906 A / Raw0005 Ether / IP / TCP 209.250.234.198:57985 > 172.20.63.57:64906 A / Raw0006 Ether / IP / TCP 172.20.63.57:64906 > 209.250.234.198:57985 A0007 Ether / IP / TCP 209.250.234.198:57985 > 172.20.63.57:64906 PA / Raw0008 Ether / IP / TCP 172.20.63.57:64906 > 209.250.234.198:57985 A0009 Ether / IP / TCP 209.250.234.198:57985 > 172.20.63.57:64906 PA / Raw查看以上信息中的第一條>>> b[0]<Ether dst=3c:08:f6:bf:be:7f src=78:4f:43:7a:9d:c6 type=0x800 |<IP version=4 ihl=5 tos=0x0 len=217 id=0 flags=DF frag=0 ttl=64 proto=tcp chksum=0x9210 src=172.20.63.57 dst=209.250.234.198 options=[] |<TCP sport=64906 dport=57985 seq=4235645629 ack=2139565768 dataofs=8 reserved=0 flags=PA window=4096 chksum=0x6c2b urgptr=0 options=[(NOP, None), (NOP, None), (Timestamp, (488571975, 484406280))] |<Raw load=b"xa6xbfxbexcax1axe3xe0xa3THyxafxfb0xdcx984yUfxf8x92gxb8xc1/04DOxe3x1cxe5xfdx92x92xbdxc9x1fx8dEx1axbaxe0xa7x1c?xb5zxdcx01xe2x1e*xe9U,?xd5xd4xf0x99xe8xc9oHWx82x9cxc7;S}x96txdc#x1egxff=x8f
ix9b
xecx83xbcxdcx0cxa2xa8xa7#xb20zxe1x17
m x03x87Lx0fxacxa16xe9Oxc7xc7x9ex88xf9x94xa7xf7xb4xdb#xb0x0exf2x04x00x1flxc7x1bx87xc9x10<
[xc4xc2xa8kK^x03xb0~xd3x91xc3xbfx1cx80,A ?Kx12x01xe4xado" |>>>>查看第一條中乙太網部分>>> b[0][Ether]<Ether dst=3c:08:f6:bf:be:7f src=78:4f:43:7a:9d:c6 type=0x800 ...>>> b[0][Ether].src 源MAC地址78:4f:43:7a:9d:c6>>> b[0][Ether].dst 目標MAC地址3c:08:f6:bf:be:7f>>> b[0][IP].src 源IP地址172.20.63.57>>> b[0][IP].dst 目標IP地址209.250.234.198>>> b[0][TCP].sport 64906>>> b[0][Raw].loadb"xa6xbfxbexcax1axe3xe0xa3THyxafxfb0xdcx984yUfxf8x92gxb8xc1/04DOxe3x1cxe5xfdx92x92xbdxc9x1fx8dEx1axbaxe0xa7x1c?xb5zxdcx01xe2x1e*xe9U,?xd5xd4xf0x99xe8xc9oHWx82x9cxc7;S}x96txdc#x1egxff=x8f
ix9b
xecx83xbcxdcx0cxa2xa8xa7#xb20zxe1x17
m x03x87Lx0fxacxa16xe9Oxc7xc7x9ex88xf9x94xa7xf7xb4xdb#xb0x0exf2x04x00x1flxc7x1bx87xc9x10<
[xc4xc2xa8kK^x03xb0~xd3x91xc3xbfx1cx80,A ?Kx12x01xe4xado"...可以通過類似的方法查看包的詳細信息
總結
好了,了解了這些基本的我們就差不多可以著手寫一個arp欺騙的程序了,等寫好了我會更新在下一篇里。??
3-24:
撻搭~
DeepWeaver:室友不敢深夜打遊戲篇二:如何用python-scapy進行arp欺騙推薦閱讀:
※拒絕壟斷,從我做起。
※多線程」一寫多讀」模式下的無鎖設計
※開始學習 Linux 用什麼發行版比較好?
※如何將Windows的C:user像Linux的/home一樣單獨掛載一塊硬碟?