Python教程網路安全篇

wyzsk發表於2020-08-19
作者: lxj616 · 2014/07/17 14:07

0x00:概述


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

0x01:利用Python解析TCP資料包


以下面程式碼為例進行說明

enter image description here

首先匯入socket(用於網路程式設計)、struct(用於拆包解析資料包結構)、binascii(方便格式的轉化)

建立socket時指定socket.SOCK_RAW以接收原始資料包

Pkt為獲取到的資料包

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

乙太網幀結構:

enter image description here

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

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

enter image description here

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

IP包頭結構:

enter image description here

本節所用程式碼如下:

#!python
#!/usr/bin/python

import socket
import struct
import binascii

s=socket.socket(socket.PF_PACKET,socket.SOCK_RAW,socket.htons(0x0800))

pkt = s.recvfrom(2048);

ethernetHeader=pkt[0][0:14]

eth_hdr = struct.unpack("!6s6s2s",ethernetHeader)

binascii.hexlify(eth_hdr[0])

binascii.hexlify(eth_hdr[1])

binascii.hexlify(eth_hdr[2])

ipHeader = pkt[0][14:34]

ip_hdr = struct.unpack("!12s4s4s",ipHeader)

print "Source IP address:"+socket.inet_ntoa(ip_hdr[1])

print "Destination IP address:"+socket.inet_ntoa(ip_hdr[2])

tcpHeader = pkt[0][34:54]

tcp_hdr = struct.unpack("!HH16s",tcpHeader)

本節示例輸出如下:

#!bash
[email protected]:~/Desktop/wooyunPython# ./0x01.py
Source IP address:123.125.125.99
Destination IP address:10.0.3.15
[email protected]:~/Desktop/wooyunPython# python
Python 2.7.3 (default, Jan  2 2013, 13:56:14) 
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import socket
>>> import struct
>>> import binascii
>>> s=socket.socket(socket.PF_PACKET,socket.SOCK_RAW,socket.htons(0x0800))
>>> pkt = s.recvfrom(2048);
>>> ethernetHeader=pkt[0][0:14]
>>> eth_hdr = struct.unpack("!6s6s2s",ethernetHeader)
>>> binascii.hexlify(eth_hdr[0])
'080027bc6ecc'
>>> binascii.hexlify(eth_hdr[1])
'525400123502'
>>> binascii.hexlify(eth_hdr[2])
'0800'
>>> ipHeader = pkt[0][14:34]
>>> ip_hdr = struct.unpack("!12s4s4s",ipHeader)
>>> print "Source IP address:"+socket.inet_ntoa(ip_hdr[1])
Source IP address:123.125.125.99
>>> print "Destination IP address:"+socket.inet_ntoa(ip_hdr[2])
Destination IP address:10.0.3.15
>>> tcpHeader = pkt[0][34:54]
>>> tcp_hdr = struct.unpack("!HH16s",tcpHeader)

0x02:利用Python傳送TCP資料包


本文所用程式碼如下:

#!python
#!/usr/bin/python

import socket
import struct

rawSocket = socket.socket(socket.PF_PACKET,socket.SOCK_RAW,socket.htons(0x0800))

rawSocket.bind(("eth0",socket.htons(0x0800)))

packet = struct.pack("!6s6s2s",'\xaa\xaa\xaa\xaa\xaa\xaa','\xbb\xbb\xbb\xbb\xbb\xbb','\x08\x00')

rawSocket.send(packet+"Hello there")

enter image description here

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

0x03:利用Python+Scapy嗅探資料包


#!bash
[email protected]:~# scapy
INFO: Can't import python gnuplot wrapper . Won't be able to plot.
WARNING: No route found for IPv6 destination :: (no default route?)
Welcome to Scapy (2.2.0)
>>> ls()
ARP        : ARP

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

#!bash
>>> pkts = sniff(iface="eth1",count=3)

使用sniff監聽eth1介面的3個資料包

#!bash
>>> pkts
<Sniffed: TCP:3 UDP:0 ICMP:0 Other:0>

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

#!bash
>>> pkts[0]
<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=http seq=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.1\r\nHost: web.pinyin.sogou.com\r\nAccept: */*\r\n\r\n' |>>>>
>>> pkts[0].show()

使用show顯示更詳細

#!bash
###[ Ethernet ]###
  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= http
        seq= 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.1\r\nHost: web.pinyin.sogou.com\r\nAccept: */*\r\n\r\n'
>>> 
>>> hexdump(pkts[1])

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

#!bash
0000   08 00 27 BC 6E CC 52 54  00 12 35 02 08 00 45 00   ..'.n.RT..5...E.
0010   00 28 82 39 00 00 40 06  F2 A7 7B 7D 7D 63 0A 00   .(.9..@...{}}c..
0020   03 0F 00 50 C0 05 3E 44  78 E8 8C 8C D3 96 50 10   ...P..>Dx.....P.
0030   FF FF D2 3F 00 00 00 00  00 00 00 00               ...?........
>>> 

>>> wrpcap("demo.pcap",pkts)

寫出到pcap檔案

#!bash
>>> read_pkts=rdpcap("demo.pcap")

從pcap檔案中讀取

#!bash
>>> read_pkts
<demo.pcap: TCP:3 UDP:0 ICMP:0 Other:0>

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

#!bash
>>> 

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

使用filter來過濾想要捕獲的資料包型別

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

#!bash
[email protected]:~# ping www.wooyun.org
PING wooyun.sinaapp.com (220.181.136.24) 56(84) bytes of data.
64 bytes from 220.181.136.24: icmp_req=1 ttl=54 time=17.1 ms
64 bytes from 220.181.136.24: icmp_req=3 ttl=54 time=11.8 ms
64 bytes from 220.181.136.24: icmp_req=4 ttl=54 time=23.8 ms
64 bytes from 220.181.136.24: icmp_req=5 ttl=54 time=17.1 ms
64 bytes from 220.181.136.24: icmp_req=6 ttl=54 time=5.63 ms
^C
--- wooyun.sinaapp.com ping statistics ---
6 packets transmitted, 5 received, 16% packet loss, time 5013ms
rtt min/avg/max/mdev = 5.636/15.135/23.824/6.086 ms

>>> pkts
<Sniffed: TCP:0 UDP:0 ICMP:3 Other:0>

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

#!bash
>>> 
>>> pkts[0]
<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='\xcc\xa7\xc3S\x00\x00\x00\x00\xa2K\r\x00\x00\x00\x00\x00\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./01234567' |>>>>
>>> pkts[1]
<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='\xcc\xa7\xc3S\x00\x00\x00\x00\xa2K\r\x00\x00\x00\x00\x00\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./01234567' |>>>>
>>> 

>>> icmp_str=str(pkts[0])

轉成str

#!bash
>>> icmp_str
'RT\x00\x125\x02\x08\x00\'\xbcn\xcc\x08\x00E\x00\x00T\x00\x00@\x00@\x01\xc8\xcc\n\x00\x03\x0f\xdc\xb5\x88\x18\x08\x00\xd8V!\x8e\x00\x01\xcc\xa7\xc3S\x00\x00\x00\x00\xa2K\r\x00\x00\x00\x00\x00\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./01234567'
>>> recon=Ether(icmp_str)

從str重構資料包

#!bash
>>> recon
<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='\xcc\xa7\xc3S\x00\x00\x00\x00\xa2K\r\x00\x00\x00\x00\x00\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./01234567' |>>>>
>>> export_object(icmp_str)
eNprYApNCgphEDJl4mBQ35N3hoPBlYEhhIHBgcGB8cQZLgZm/jtbOyQ4GG6EKfYxMJ5ZfjiYAQgW
efOCKAYBQSFhEVExcQlJKWkZWTl5BUUlZRVVNXUNTS1tHV09fQNDI2MTUzPzQkY9AMQIFOY=

匯出可讀base64物件

#!bash
>>> newPkt=import_object()
eNprYApNCgphEDJl4mBQ35N3hoPBlYEhhIHBgcGB8cQZLgZm/jtbOyQ4GG6EKfYxMJ5ZfjiYAQgW
efOCKAYBQSFhEVExcQlJKWkZWTl5BUUlZRVVNXUNTS1tHV09fQNDI2MTUzPzQkY9AMQIFOY=

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

#!bash
>>> newPkt
'RT\x00\x125\x02\x08\x00\'\xbcn\xcc\x08\x00E\x00\x00T\x00\x00@\x00@\x01\xc8\xcc\n\x00\x03\x0f\xdc\xb5\x88\x18\x08\x00\xd8V!\x8e\x00\x01\xcc\xa7\xc3S\x00\x00\x00\x00\xa2K\r\x00\x00\x00\x00\x00\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./01234567'
>>> Ether(newPkt)
<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='\xcc\xa7\xc3S\x00\x00\x00\x00\xa2K\r\x00\x00\x00\x00\x00\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./01234567' |>>>>

到此我們成功原路返回了匯出的資料包

>>>

接下來就是利用scapy傳送資料包了

enter image description here

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

#!bash
[email protected]:~# scapy
INFO: Can't import python gnuplot wrapper . Won't be able to plot.
WARNING: No route found for IPv6 destination :: (no default route?)
Welcome to Scapy (2.2.0)
>>> from scapy.all import *
>>> pkt=Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst='192.168.1.3',hwdst="ff:ff:ff:ff:ff:ff")
>>> pkt
<Ether  dst=ff:ff:ff:ff:ff:ff type=0x806 |<ARP  hwdst=ff:ff:ff:ff:ff:ff pdst=192.168.1.3 |>>
>>> pkt.show()
###[ Ethernet ]###
  dst= ff:ff:ff:ff:ff:ff
  src= 00:00:00:00:00:00
  type= 0x806
###[ ARP ]###
     hwtype= 0x1
     ptype= 0x800
     hwlen= 6
     plen= 4
     op= who-has
     hwsrc= 00:00:00:00:00:00
     psrc= 192.168.1.3
     hwdst= ff:ff:ff:ff:ff:ff
     pdst= 192.168.1.3
>>> srp1(pkt)
Begin emission:
Finished to send 1 packets.
..............................................................................^C
Received 78 packets, got 0 answers, remaining 1 packets
>>>
本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!

相關文章