[轉載]Python教程網路安全篇

作者:烏雲drops - 永久存檔vuln.cn/6447

鏈接:Python教程網路安全篇 - lxj616

來源:drops.wooyun.org/tips/2

著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

本文從實例代碼出發,講解了Python在網路安全分析中的作用,以最基礎的示例向讀者展示了Python如何解析、發送、以及嗅探網路中的數據包 系統環境:kali 並且具備了scapy,由於涉及底層網路操作,文中的示例代碼均為linux下可用,無法直接複製到windows下使用

0x01:利用Python解析TCP數據包

以下面代碼為例進行說明:

首先導入socket(用於網路編程)、struct(用於拆包解析數據包結構)、binascii(方便格式的轉化)

創建socket時指定socket.SOCK_RAW以接收原始數據包

Pkt為獲取到的數據包

Eth_hdr 為拆包得到的乙太網頭部,使用unpack解出(請見下圖乙太網幀格式)

乙太網幀結構:

我們可以看到解出的第一部分(目的地址)為080027bc6ecc 我們可以看到解出的第二部分(源地址)為525400123502 我們可以看到解出的第三部分(長度類型)為0800 圖片來自網路,注意圖中說的4位元組VLAN是不存在的 - -

下面看看自己的mac(eth1) 為080027bc6ecc,與上文結論相符

同理解出IP包頭裡的源IP和目的IP,如第一張圖所示

IP包頭結構:

本節所用代碼如下:

#!/usr/bin/pythonnimport socketnimport structnimport binasciins=socket.socket(socket.PF_PACKET,socket.SOCK_RAW,socket.htons(0x0800))npkt = s.recvfrom(2048);nethernetHeader=pkt[0][0:14]neth_hdr = struct.unpack("!6s6s2s",ethernetHeader)nbinascii.hexlify(eth_hdr[0])nbinascii.hexlify(eth_hdr[1])nbinascii.hexlify(eth_hdr[2])nipHeader = pkt[0][14:34]nip_hdr = struct.unpack("!12s4s4s",ipHeader)nprint "Source IP address:"+socket.inet_ntoa(ip_hdr[1])nprint "Destination IP address:"+socket.inet_ntoa(ip_hdr[2])ntcpHeader = pkt[0][34:54]ntcp_hdr = struct.unpack("!HH16s",tcpHeader)n

本節示例輸出如下:

root@kali:~/Desktop/wooyunPython# ./0x01.pynSource IP address:123.125.125.99nDestination IP address:10.0.3.15n

root@kali:~/Desktop/wooyunPython# pythonnPython 2.7.3 (default, Jan 2 2013, 13:56:14)n[GCC 4.7.2] on linux2nType "help", "copyright", "credits" or "license" for more information.n>>> import socketn>>> import structn>>> import binasciin>>> s=socket.socket(socket.PF_PACKET,socket.SOCK_RAW,socket.htons(0x0800))n>>> pkt = s.recvfrom(2048);n>>> ethernetHeader=pkt[0][0:14]n>>> eth_hdr = struct.unpack("!6s6s2s",ethernetHeader)n>>> binascii.hexlify(eth_hdr[0])n080027bc6eccn>>> binascii.hexlify(eth_hdr[1])n525400123502n>>> binascii.hexlify(eth_hdr[2])n0800n>>> ipHeader = pkt[0][14:34]n>>> ip_hdr = struct.unpack("!12s4s4s",ipHeader)n>>> print "Source IP address:"+socket.inet_ntoa(ip_hdr[1])nSource IP address:123.125.125.99n>>> print "Destination IP address:"+socket.inet_ntoa(ip_hdr[2])nDestination IP address:10.0.3.15n>>> tcpHeader = pkt[0][34:54]n>>> tcp_hdr = struct.unpack("!HH16s",tcpHeader)n

0x02:利用Python發送TCP數據包

本文所用代碼如下:

#!/usr/bin/pythonnimport socketnimport structnrawSocket = socket.socket(socket.PF_PACKET,socket.SOCK_RAW,socket.htons(0x0800))nrawSocket.bind(("eth0",socket.htons(0x0800)))npacket = struct.pack("!6s6s2s",xaaxaaxaaxaaxaaxaa,xbbxbbxbbxbbxbbxbb,x08x00)nrawSocket.send(packet+"Hello there")n

首先socket類型選擇raw,然後bind一個interface就可以發包了,由於發送的是原始的數據包,因此數據包需要自己通過struct.pack包裝好

0x03:利用Python+Scapy嗅探數據包

root@kali:~# scapynINFO: Cant import python gnuplot wrapper . Wont be able to plot.nWARNING: No route found for IPv6 destination :: (no default route?)nWelcome to Scapy (2.2.0)n>>> ls()nARP : ARPn

這裡還列出了一大堆的介紹,就不列出了

>>> pkts = sniff(iface="eth1",count=3)n

使用sniff監聽eth1介面的3個數據包

>>> pktsn<Sniffed: TCP:3 UDP:0 ICMP:0 Other:0>n

直接輸入pkts會顯示嗅探的概況

>>> pkts[0]n<Ether dst=52:54:00:12:35:02 src=08:00:27:bc:6e:cc type=0x800 |<IP version=4L ihl=5L tos=0x0 len=116 id=30377 flags=DF frag=0L ttl=64 proto=tcp chksum=0xbdeb src=10.0.3.15 dst=123.125.125.99 options=[] |<TCP sport=49157 dport=httpseq=2358039370 ack=1044674792 dataofs=5L reserved=0L flags=PA window=24120 chksum=0x656 urgptr=0 options=[] |<Raw load=GET /web_ime/patch.php HTTP/1.1rnHost: web.pinyin.sogou.comrnAccept: */*rnrn |>>>>n>>> pkts[0].show()n

使用show顯示更詳細

###[ Ethernet ]###ndst= 52:54:00:12:35:02nsrc= 08:00:27:bc:6e:ccntype= 0x800n###[ IP ]###nversion= 4Lnihl= 5Lntos= 0x0nlen= 116nid= 30377nflags= DFnfrag= 0Lnttl= 64nproto= tcpnchksum= 0xbdebnsrc= 10.0.3.15ndst= 123.125.125.99noptionsn###[ TCP ]###nsport= 49157ndport= httpnseq= 2358039370nack= 1044674792ndataofs= 5Lnreserved= 0Lnflags= PAnwindow= 24120nchksum= 0x656nurgptr= 0noptions= []n###[ Raw ]###nload= GET /web_ime/patch.php HTTP/1.1rnHost: web.pinyin.sogou.comrnAccept: */*rnrnn>>>n>>> hexdump(pkts[1])n

轉成十六進位形式更加親切

000 08 00 27 BC 6E CC 52 54 00 12 35 02 08 00 45 00 ...n.RT..5...E.n0010 00 28 82 39 00 00 40 06 F2 A7 7B 7D 7D 63 0A 00 .(.9..@...{}}c..n0020 03 0F 00 50 C0 05 3E 44 78 E8 8C 8C D3 96 50 10 ...P..>Dx.....P.n0030 FF FF D2 3F 00 00 00 00 00 00 00 00 ...?........n>>>n>>> wrpcap("demo.pcap",pkts)n

寫出到pcap文件

>>> read_pkts=rdpcap("demo.pcap")n

從pcap文件中讀取

>>> read_pktsn<demo.pcap: TCP:3 UDP:0 ICMP:0 Other:0>n

檢查發現讀出與寫入是一致的

>>>n>>> pkts=sniff(iface="eth1",filter="icmp",count=3)n

使用filter來過濾想要捕獲的數據包類型

注意同時我另開一個shell做了一個ping來發送icmp包

root@kali:~# ping www.wooyun.orgnPING wooyun.sinaapp.com (220.181.136.24) 56(84) bytes of data.n64 bytes from 220.181.136.24: icmp_req=1 ttl=54 time=17.1 msn64 bytes from 220.181.136.24: icmp_req=3 ttl=54 time=11.8 msn64 bytes from 220.181.136.24: icmp_req=4 ttl=54 time=23.8 msn64 bytes from 220.181.136.24: icmp_req=5 ttl=54 time=17.1 msn64 bytes from 220.181.136.24: icmp_req=6 ttl=54 time=5.63 msn^Cn--- wooyun.sinaapp.com ping statistics ---n6 packets transmitted, 5 received, 16% packet loss, time 5013msnrtt min/avg/max/mdev = 5.636/15.135/23.824/6.086 msn>>> pktsn<Sniffed: TCP:0 UDP:0 ICMP:3 Other:0>n

發現截獲的通過filter果然都是icmp包

>>>n>>> pkts[0]n<Ether dst=52:54:00:12:35:02 src=08:00:27:bc:6e:cc type=0x800 |<IP version=4L ihl=5L tos=0x0 len=84 id=0 flags=DF frag=0L ttl=64 proto=icmp chksum=0xc8cc src=10.0.3.15 dst=220.181.136.24 options=[] |<ICMP type=echo-request code=0 chksum=0xd856 id=0x218e seq=0x1 |<Raw load=xccxa7xc3Sx00x00x00x00xa2Krx00x00x00x00x00x10x11x12x13x14x15x16x17x18x19x1ax1bx1cx1dx1ex1f !"#$%&()*+,-./01234567 |>>>>n>>> pkts[1]n<Ether dst=08:00:27:bc:6e:cc src=52:54:00:12:35:02 type=0x800 |<IP version=4L ihl=5L tos=0x1 len=84 id=33433 flags= frag=0L ttl=54 proto=icmp chksum=0x9032 src=220.181.136.24 dst=10.0.3.15 options=[] |<ICMP type=echo-reply code=0 chksum=0xe056 id=0x218e seq=0x1 |<Raw load=xccxa7xc3Sx00x00x00x00xa2Krx00x00x00x00x00x10x11x12x13x14x15x16x17x18x19x1ax1bx1cx1dx1ex1f !"#$%&()*+,-./01234567 |>>>>n>>>n>>> icmp_str=str(pkts[0])n

轉成str

>>> icmp_strnRTx00x125x02x08x00xbcnxccx08x00Ex00x00Tx00x00@x00@x01xc8xccnx00x03x0fxdcxb5x88x18x08x00xd8V!x8ex00x01xccxa7xc3Sx00x00x00x00xa2Krx00x00x00x00x00x10x11x12x13x14x15x16x17x18x19x1ax1bx1cx1dx1ex1f !"#$%&()*+,-./01234567n>>> recon=Ether(icmp_str)n

從str重構數據包

>>> reconn<Ether dst=52:54:00:12:35:02 src=08:00:27:bc:6e:cc type=0x800 |<IP version=4L ihl=5L tos=0x0 len=84 id=0 flags=DF frag=0L ttl=64 proto=icmp chksum=0xc8cc src=10.0.3.15 dst=220.181.136.24 options=[] |<ICMP type=echo-request code=0 chksum=0xd856 id=0x218e seq=0x1 |<Raw load=xccxa7xc3Sx00x00x00x00xa2Krx00x00x00x00x00x10x11x12x13x14x15x16x17x18x19x1ax1bx1cx1dx1ex1f !"#$%&()*+,-./01234567 |>>>>n>>> export_object(icmp_str)neNprYApNCgphEDJl4mBQ35N3hoPBlYEhhIHBgcGB8cQZLgZm/jtbOyQ4GG6EKfYxMJ5ZfjiYAQgWnefOCKAYBQSFhEVExcQlJKWkZWTl5BUUlZRVVNXUNTS1tHV09fQNDI2MTUzPzQkY9AMQIFOY=n

導出可讀base64對象

>>> newPkt=import_object()neNprYApNCgphEDJl4mBQ35N3hoPBlYEhhIHBgcGB8cQZLgZm/jtbOyQ4GG6EKfYxMJ5ZfjiYAQgWnefOCKAYBQSFhEVExcQlJKWkZWTl5BUUlZRVVNXUNTS1tHV09fQNDI2MTUzPzQkY9AMQIFOY=n

輸入完成後按(ctrl+D)結束輸入 從base64中讀回對象

>>> newPktnRTx00x125x02x08x00xbcnxccx08x00Ex00x00Tx00x00@x00@x01xc8xccnx00x03x0fxdcxb5x88x18x08x00xd8V!x8ex00x01xccxa7xc3Sx00x00x00x00xa2Krx00x00x00x00x00x10x11x12x13x14x15x16x17x18x19x1ax1bx1cx1dx1ex1f !"#$%&()*+,-./01234567n>>> Ether(newPkt)n<Ether dst=52:54:00:12:35:02 src=08:00:27:bc:6e:cc type=0x800 |<IP version=4L ihl=5L tos=0x0 len=84 id=0 flags=DF frag=0L ttl=64 proto=icmp chksum=0xc8cc src=10.0.3.15 dst=220.181.136.24 options=[] |<ICMP type=echo-request code=0 chksum=0xd856 id=0x218e seq=0x1 |<Raw load=xccxa7xc3Sx00x00x00x00xa2Krx00x00x00x00x00x10x11x12x13x14x15x16x17x18x19x1ax1bx1cx1dx1ex1f !"#$%&()*+,-./01234567 |>>>>n

到此我們成功原路返回了導出的數據包

>>>n

接下來就是利用scapy發送數據包了

首先Ether/ARP構造一個ARP數據包,之後srp1發送出去,從wireshark中看發現數據包已經成功發送了,不過在這裡理論上是可以收到response的,測試時由於不明原因沒有收到

root@kali:~# scapynINFO: Cant import python gnuplot wrapper . Wont be able to plot.nWARNING: No route found for IPv6 destination :: (no default route?)nWelcome to Scapy (2.2.0)n>>> from scapy.all import *n>>> pkt=Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst=192.168.1.3,hwdst="ff:ff:ff:ff:ff:ff")n>>> pktn<Ether dst=ff:ff:ff:ff:ff:ff type=0x806 |<ARP hwdst=ff:ff:ff:ff:ff:ff pdst=192.168.1.3 |>>n>>> pkt.show()n###[ Ethernet ]###ndst= ff:ff:ff:ff:ff:ffnsrc= 00:00:00:00:00:00ntype= 0x806n###[ ARP ]###nhwtype= 0x1nptype= 0x800nhwlen= 6nplen= 4nop= who-hasnhwsrc= 00:00:00:00:00:00npsrc= 192.168.1.3nhwdst= ff:ff:ff:ff:ff:ffnpdst= 192.168.1.3n>>> srp1(pkt)nBegin emission:nFinished to send 1 packets.n..............................................................................^CnReceived 78 packets, got 0 answers, remaining 1 packetsn>>>n

推薦閱讀:

未來互聯網安全的攻防趨勢在哪裡?
花無涯帶你走進黑客之 小白入門 第一彈
白宮特供通信軟體Confide被發現存在漏洞,可查看特朗普聊天記錄
學術沙龍分享 · 論文回顧 - Week 8
2345

TAG:Python | 网络安全 |