mirror of
https://github.com/rapid7/metasploit-payloads
synced 2025-03-24 18:16:24 +01:00
Fix stageless config block memory protection
I found an edge case where stageless payloads did not work when they were embedded in .NET applications. The reason for this is because the configuration block is stored alongside the code in stageless payloads and hence is loaded into memory as part of the section when it's mapped. This section, in native world, remains RWX, and hence we don't have a problem reading from and writing to it. We write to it for various reasons, such as when the session guid changes. In .NET land, this section is mapped as RX instead of RWX. This means that when we try to write to it, the program segfaults due to an access violation. This code modifies the loading of the configuration so that instead of maintaining a pointer to the original configuration, it instead creates a copy of it on the heap. I preferred this fix over marking the memory as RWX, which obviously stands out a bit more.
This commit is contained in:
parent
162e769464
commit
8b4d65de47
c/meterpreter/source
@ -73,6 +73,11 @@ VOID remote_deallocate(Remote * remote)
|
||||
lock_destroy(remote->lock);
|
||||
}
|
||||
|
||||
if (remote->orig_config)
|
||||
{
|
||||
free(remote->orig_config);
|
||||
}
|
||||
|
||||
// Wipe our structure from memory
|
||||
memset(remote, 0, sizeof(Remote));
|
||||
|
||||
|
@ -68,9 +68,10 @@ DWORD server_sessionid()
|
||||
/*!
|
||||
* @brief Load any stageless extensions that might be present in the current payload.
|
||||
* @param remote Pointer to the remote instance.
|
||||
* @param fd The socket descriptor passed to metsrv during intialisation.
|
||||
* @param fd The socket descriptor passed to metsrv during intialisation.
|
||||
* @return Pointer to the end of the configuration.
|
||||
*/
|
||||
VOID load_stageless_extensions(Remote* remote, MetsrvExtension* stagelessExtensions)
|
||||
LPBYTE load_stageless_extensions(Remote* remote, MetsrvExtension* stagelessExtensions)
|
||||
{
|
||||
while (stagelessExtensions->size > 0)
|
||||
{
|
||||
@ -85,7 +86,7 @@ VOID load_stageless_extensions(Remote* remote, MetsrvExtension* stagelessExtensi
|
||||
// once we have reached the end, we may have extension initializers
|
||||
LPBYTE initData = (LPBYTE)(&stagelessExtensions->size) + sizeof(stagelessExtensions->size);
|
||||
|
||||
while (initData != NULL && *initData != '\0')
|
||||
while (*initData != '\0')
|
||||
{
|
||||
const char* extensionName = (const char*)initData;
|
||||
LPBYTE data = initData + strlen(extensionName) + 1 + sizeof(DWORD);
|
||||
@ -96,6 +97,7 @@ VOID load_stageless_extensions(Remote* remote, MetsrvExtension* stagelessExtensi
|
||||
}
|
||||
|
||||
dprintf("[SERVER] All stageless extensions initialised");
|
||||
return initData;
|
||||
}
|
||||
|
||||
static Transport* create_transport(Remote* remote, MetsrvTransportCommon* transportCommon, LPDWORD size)
|
||||
@ -347,7 +349,6 @@ DWORD server_setup(MetsrvConfig* config)
|
||||
break;
|
||||
}
|
||||
|
||||
remote->orig_config = config;
|
||||
remote->sess_expiry_time = config->session.expiry;
|
||||
remote->sess_start_time = current_unix_timestamp();
|
||||
remote->sess_expiry_end = remote->sess_start_time + config->session.expiry;
|
||||
@ -382,7 +383,16 @@ DWORD server_setup(MetsrvConfig* config)
|
||||
register_dispatch_routines();
|
||||
|
||||
// this has to be done after dispatch routine are registered
|
||||
load_stageless_extensions(remote, (MetsrvExtension*)((LPBYTE)config->transports + transportSize));
|
||||
LPBYTE configEnd = load_stageless_extensions(remote, (MetsrvExtension*)((LPBYTE)config->transports + transportSize));
|
||||
|
||||
// the original config can actually be mapped as RX in cases such as when stageless payloads
|
||||
// are baked directly into .NET assemblies. We need to make sure that this area of memory includes
|
||||
// The writable flag as well otherwise we get access violations when we're interacting with the
|
||||
// configuration block down the track. So instead of marking the original configuration as RWX (to cover
|
||||
// all cases) we will instead just muck with a copy of it on the heap.
|
||||
DWORD_PTR configSize = (DWORD_PTR)configEnd - (DWORD_PTR)config;
|
||||
remote->orig_config = (MetsrvConfig*)malloc(configSize);
|
||||
memcpy_s(remote->orig_config, configSize, config, configSize);
|
||||
|
||||
// Store our process token
|
||||
if (!OpenThreadToken(remote->server_thread, TOKEN_ALL_ACCESS, TRUE, &remote->server_token))
|
||||
|
@ -296,7 +296,7 @@ DWORD request_core_set_session_guid(Remote* remote, Packet* packet)
|
||||
|
||||
if (sessionGuid != NULL)
|
||||
{
|
||||
memcpy(&remote->orig_config->session.session_guid, sessionGuid, sizeof(GUID));
|
||||
memcpy(remote->orig_config->session.session_guid, sessionGuid, sizeof(GUID));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user