面向監獄程式設計,就靠它了
網路程式設計大家都學過吧?
socket -> bind -> listen -> accept-> recv/recvfrom -> send/sendto
一氣呵成,什麼select、poll、epoll多路複用模型信手拈來。
但這一套東西,只是開發建立在傳輸層TCP、UDP之上的應用程式。
你有沒有想過,如何程式設計批量傳送一批 TCP SYN 握手包,來進行埠掃描?
如何程式設計來發送一個偽造了IP地址的ARP資料包和IP資料報文?
甚至,如何程式設計來發送一個偽造了MAC地址的乙太網資料幀?
一旦你掌握了上面幾招,玩轉資料包不是問題,開發各種神器不在話下。但一定要用在正途上,不要面向監獄程式設計哦~
![](http://mdimg.wxwenku.com/getimg/6b990ce30fa9193e296dd37902816f4bec31fae9a1ff75b1ab0df23ac151fcee217947f58cba1eb31b7210d5f6ca6d68.jpg)
那到底如何構造傳送各種各樣的資料包呢?今天給大家介紹一個強大的玩意: scapy
這是一個強大的資料包構造工具,你可以在Python中使用它,是時候喊一聲:Python大法好了!
ARP
我們拿ARP開刀,ARP是地址解析協議,區域網中通訊需要使用網絡卡的MAC地址,而網路層通訊使用的是IP地址,在應用程式的資料包被髮送出去之前,在IP報文前面新增乙太網幀頭時,需要填寫收件人的MAC地址,如果是區域網內部通訊,這個收件人地址就是目的電腦的網絡卡MAC地址,而如果是網際網路上的公網IP地址,這個收件人地址就是閘道器的MAC地址。
無論怎樣,總得有個MAC地址才行,那怎麼來呢?這就是ARP協議要乾的事,它能將一個IP地址轉換成一個MAC地址。
ARP解析的過程這裡就不詳述了,簡單來說,比如要查詢192.168.1.100的MAC地址,主機使用ARP協議在區域網中發出一聲廣播:192.168.1.100,我叫你一聲你敢答應嗎?
區域網中所有人都能收到這個廣播(因為它的收件人MAC地址是FF-FF-FF-FF-FF-FF),但只有IP地址是192.168.1.100的這個傢伙會回一句:爺爺在此!我的MAC地址是xxxxxx。
注意,在我們平時應用程式通訊時,以上過程都是作業系統底層協議棧自動完成的,我們的應用程式感知不到這些。
我們可以使用Scapy這個庫,來發起一次ARP解析。
from scapy.all import *
def arp_scan(ip):
answer, uanswer = srp(Ether(dst="ff:ff:ff:ff:ff:ff") / ARP(pdst=ip), inter=0.1, timeout=2, verbose=False)
mac_list = []
for send, recv in answer:
if recv[ARP].op == 2:
mac_list.append((recv[ARP].psrc, recv[Ether].hwsrc))
return mac_list
上面這段程式碼, 通過scapy庫中的srp函式傳送了一個乙太網幀,收件人是ff:ff:ff:ff:ff:ff,表明這是個廣播包,鏈路層之上是ARP協議,需要解析的IP是傳入待解析的IP地址引數。
上面的函式一執行,你就能在wireshark中抓到資料包了:
上面說過,正常情況下,只有目標地址是我查的那個主機才會回覆我。
但假如你的區域網中有人不懷好意,搶在真正的主機之前回答我:爺爺在此!我的MAC地址是yyyyyy。
那事情就糟了,後面的的通訊報文都發給這個假冒的傢伙那裡去了,這就是大名鼎鼎的 ARP欺騙攻擊 !
再試想一下,如果查詢的IP地址是閘道器的IP地址,那後果更嚴重,所有的網路通訊都發到這傢伙來了。
既然能傳送ARP查詢報文,你把上面的程式碼改一下,自然也能傳送ARP應答報文···
ARP的故事先說到這裡,咱們再來看一下,用scapy做一個埠掃描器。
埠掃描
TCP埠掃描,通過傳送三次握手的第一次SYN資料包,根據返回的結果來判斷埠的開啟情況:
如果返回ACK+SYN,也就是flags欄位是18,則說明埠開啟:
![](http://mdimg.wxwenku.com/getimg/356ed03bdc643f9448b3f6485edc229b13c10e47440e71f0f558e3248e4faea613e3312b7b8fa54e8f3f199b21c97fbd.jpg)
如果返回ACK+RST,也就是flags欄位是20,則說明埠關閉:
![](http://mdimg.wxwenku.com/getimg/6b990ce30fa9193e296dd37902816f4b3f81dbf0f092d714c87235f2d114523f2383ab82bb9ac9cb404013dc5930e312.jpg)
下面的函式就能實現:
from scapy.all import *
def port_scan(port):
answer, uanswer = sr(IP(dst="192.168.1.1") / fuzz(TCP(dport=int(port), flags="S")))
for s, r in ans:
if r[TCP].flags == 18:
print("port is Open")
if r[TCP].flags == 20:
print("port is Closed")
抓包來看:
握手包和伺服器的返回包都能清楚看到,如果在迴圈中不斷呼叫該函式,傳入不同的埠,則可以實現批量埠掃描。
scapy構造資料包的能力這只是冰山一角,更多強大的功能等著你去研究。
學習計算機網路,不要只停留在看書和看博文的基礎上,如果能自己程式設計收發資料包,去實現ARP、ICMP、DHCP、DNS的功能,或者開發一些簡單的網路工具,絕對比別人掌握的更加深刻。
最後,給大家留一個思考題,如何通過構造IP報文實現 traceroute 的路由跟蹤功能呢,想一想,這該如何實現?
- EOF -
推薦閱讀 點選標題可跳轉
伯樂線上
分享IT網際網路職場和精選乾貨文章(原域名已不再維護)。組織 維護10萬+star的開源技術資源庫,包括:Python, Java, C/C++, Go, JS, CSS, Node.js, PHP, .NET 等。
回覆 資源 獲取10萬+star開源資源