發表文章

精選

幫 VMware Client 虛擬機啟用 VBS 防護(Virtualization Based Security)

圖片
前言 因為演講需求要展示怎打穿 Virtualization 防護,洞都串好了結果發現 VMware 虛擬機 Windows 11 最新版下的 Defender 防毒惡意探索功能的 Hypervisor Code Integrity (HVCI) 怎樣都不給開。然後花了一段時間爬網路上文都沒人撰文解釋,這邊寫一篇文給有需要的人參考XD 有此需求在虛擬機內啟用 VBS 防護的朋友,應該都有嘗試過至配置中「Virtual Machine Settings → Processors → 勾選 Virtualize Intel VT-x/EPT or AMD-V/RVI」並且就能在「Options → Advanced → 勾選 Enable VBS (Virtualization Based Security) support」後,理論上啟動虛擬機後就能使用虛擬機中的 HVCI 防護... 然後這時候你一把 VMware 虛擬機開機,就會彈出一堆 Hyper-V 或 Virtualization 相關的不支援訊息(上圖)怎樣都不給你開機 Orz 好的那怎解決呢?有三大條件必須在 VMware Host 滿足缺一不可、即可讓 VMware Client 可以啟用 HVCI 囉。 關閉 Windows 原生 Hyper-V 虛擬機功能 首先是 Windows 功能(Windows Feature)相關 Hyper-V 與 Hypervisor 平台系列相關功能用於支援 Windows 原生虛擬機功能若啟用狀態下,都會導致 VMware Host 搶占走 Intel EPT 使用權限所致 Client 無法取用 Hypervisor 相關功能,囧。如上圖所示,將上述所有黃框處勾選起來。 系統配置中 Hyper-V / Hypervisor 功能 Intel CPU 所提供的 Hypervisor 系列指令集 HyperCall 被 Windows 重新封裝並以系統角色封裝成 Hyper-V 平台導出之系列 API,因此前面關掉 Windows 功能不代表系統自身的 Hyper-V 平台已經被註記為不得占用 Hypervisor 的狀態;所以需要按上圖所示,以系統管理員身分開啟 PowerShell 並輸入上述兩條指令用以關閉系統原生的 Hyper-V 平台。 Host 端的 H

重建天堂之門:從 32 位元地獄一路打回天堂聖地(下)攻擊篇:x96 Shellcode、天堂聖杯 & 天堂注入器

圖片
 WOW64逆向工程 在前一篇部落格文  重建天堂之門:從 32 位元地獄一路打回天堂聖地(上)深度逆向工程 WOW64 設計  筆者已經以逆向工程角度完整解釋了微軟這套幫助 32-bit 在原生 64-bit Windows 執行之架構的設計 若讀者尚未有研究過天堂之門相關基礎、建議先回到上一篇文通讀後再回來本文閱讀。而接下來我們會把焦點圍繞在接續著如何將上一篇的背景知識組合出一些有趣的利用手法 :) x96 Shellcode 這是我覺得最有趣的一個玩法XD 通過逆向工程 WOW64 架構後,發現了通過 cs segment 區段暫存器值 23h 或 33h、得以確認當下 Intel 晶片正在將 program counter 上的程式碼以 32-bit 或 64-bit 指令集解析。 因此藉由此區段暫存器值,我們也能創建出一個 x96 shellcode、亦即同時可當作 32-bit 也可當作 64-bit 的 shellcode!設計概念相當簡單,便是在 shellcode 開頭處 設計一個彈頭 :判斷當前 cs segment 值若為 23h 則跳去 32-bit shellcode 執行、反之是 33h 則跳去 64-bit shellcode 接續著執行。 講得簡單,設計起來實務麻煩點其實是確保 x96 彈頭 payload 在 32/64-bit 下解析起來的邏輯是一致的,比方 shellcode 相對偏移定址問題、32/64-bit 的指令 alignment 不對稱,或者連 branch jump 指令 offset 在兩指令集上算法超過 2 bytes 也會有問題 等。 所以在上面 PoC 中可以看到,彈頭中所有的指令 opcode 都特別挑選過是在兩種架構上皆相同的、才可確保在兩指令集上邏輯按照預期執行,舉例: call $+5 同樣是 \xE8\x00\x00\x00\x00 其在 64-bit 下會以 8 bytes 長度推入 return address 上堆疊,而在 32-bit 下僅推入 4 bytes 長度上堆疊 \x81\x04\x24 其在 32-bit 下被視作 add ds: [esp], xxxx。而在 64-bit 下會被自動擴展為 add ds: [rsp], xxxx 而挑選使用 call $+5; ad

重建天堂之門:從 32 位元地獄一路打回天堂聖地(上)深度逆向工程 WOW64 設計

圖片
前言 這份研究是從去年底開始摸的,主因是一直對 Windows 如何實作 WOW64 兼容架構覺得有意思,並且坊間蠻多開源的天堂之門專案都死掉了 QQ 所以才打算自己完全重新逆向工程分析過一次。 逆向整個 WOW64 架構可以發現很多蠻有意思的問題,比方說 Intel 晶片指令集模式切換、記憶體模擬分配、WOW64 偽造的原生 32-bit 環境,例如 System32 在 32-bit 下會被重導向至 SysWOW64 到底在哪一層實作重導向的呢 ;)  此研究也運氣不錯分別被國內研討會 CYBERSEC 收錄為 《重建天堂之門:從 32bit 地獄一路打回天堂聖地》 與 HITB(Hack In The Box Security Conference)收錄為  《WoW Hell: Rebuilding Heavens Gate》 若對線上演講內容有興趣可以參考 Youtube 上 HITB 的直撥串流  HITB2021AMS D1T2 - WoW Hell: Rebuilding Heavens Gate - ShengHao Ma   不過我英文很破能不看就不看啦 由於整份演講內容想提的細節太多了,所以本部落格文拆成上下兩集。 當前本文是上集,會講述完整逆向工程整套微軟設計的 WOW64 架構怎麼設計的 。而下集《 重建天堂之門:從 32 位元地獄一路打回天堂聖地(下)攻擊篇:x96 Shellcode、天堂聖杯 & 天堂注入器 》會著重在我今年發表出來的幾個有趣的攻擊點 :) 如果對天堂之門技術已經很熟的大佬,可以跳過本文看下一集了 <(_ _)> *注意* 本份研究在 2021/06/11 是基於 Windows 10 Enterprise 最新版本逆向工程結果所紀錄, 可能與讀者電腦中反編譯出來的結果有所出入是正常的 。筆者實測了同樣是 Windows 10 但不同組建版本在組合語言層級皆有些許差異,不過各個函數設計用途是固定且規律的、不會因版本而有所差異。 而整份研究不限但至少涉及了以下已知文獻,蠻值得一看的 2011 -  Mixing x86 with x64 code by ReWolf 2012 -  Knockin’ on Heaven’s Gate by george_nicolaou 2012 -  KERNEL: Cr

[Windows] 惡意利用配置錯誤資訊清單(manifest)達成劫持與特權提升

圖片
 前言 這篇技巧是我在校稿最近剛出版的書 《Windows APT Warfare:惡意程式前線戰術指南》 正好看到  github.com/L3cr0f/DccwBypassUAC  這份 PoC 提及的 WinSxS 配置錯誤允許駭客劫持達成 UAC 特權提升看到比較有意思的事情所以寫一篇作為筆記。 不過這篇技巧目前在 Windows 10 上除非出現了配置錯誤的 DACL 可被寫入、否則新型的作業系統利用的可能性比較小XD 如果對 UAC 特權提升有興趣的讀者可以參考對岸這篇 BypassUAC原理及方法汇总  我覺得寫得還不錯、或者是看看我的書(?)  WinSxS  Windows 為了原生支援 WinSxS 多重系統模組功能——即同一個系統中可能會有 新舊程式使用到同個系統模組但不同版本號 的狀況。因此可以見到 C:\Windows\WinSxS\ 下有很多不同版本的資源包: 開發者能在編譯時期在純文字的資訊清單 *.manifest 記錄特定系統模組要從特定系統路徑、版本來裝載使用。而這邊引自上述對岸文章一段描述,其中提及了在資訊清單中還有一個特性可以使用: 在Windows中有些可执行程序没有内置的manifest,假设这个程序叫test.exe,如果攻击者在该可执行程序目录下新建一个test.exe.manifest并在manifest文件中指定file元素,则test.exe执行时会加载file元素中loadFrom属性指定的DLL(loadFrom的dll不能在KnownDlls中) 這是一個我覺得蠻有趣的特性,可以解釋為什麼系統槽下會有那麼多純文字保存的資訊清單 *.manifest 文件(我以前一直誤以為是開發者編譯完忘記刪掉XD)這描述說明了兩點: 除了開發者相當熟悉的嵌入式資訊清單,還有導出式資訊清單——在 同層資料夾中保存與程式名同名的 *.manifest 文件 即可被程式裝載器正確識別 無論嵌入或導出式資訊清單:使用 loadFrom  標籤可以指示程式裝載器在「裝載特定 DLL 模組」時便會被 redirect 去裝載另一個特定的 DLL 模組 總而言之當程式裝載器正在初始化一支靜態程式文件、發現其不具嵌入式資訊清單時,那麼就會同層目錄確認是否有同名的 *.manifest 清單文件進行解析並初始化,以下做個舉例: 桌面上現在有

[Windows] 逆向工程 C++ 中入口函數參數 main(argc, argv) 與如何正確的進行參數劫持

圖片
前言 我在 Github 上三年前開源了精簡的以 C/C++ 撰寫的 Windows 執行程式裝載器: aaaddress1/RunPE-In-Memory  用以從記憶體執行以 C/C++ 開發的 *.exe 程式不必以 CreateProcess() 來叫起,算是一種概念性 PoC 啦畢竟這種手段在惡意程式和殼上經常使用,所以寫一寫就丟出來給大家玩 XD 不過有人在我的專案發起了 Issue:既然能從記憶體中執行 *.exe 那能否偽造 *.exe 取得的參數呢?嗯好問題XD 正逢去年蠻忙的所以一直懶得弄,這個月比較閒於是就決定在專案中新增 參數偽造 的功能,這邊簡單提一下 C++ 中 main() 入口所收的 argc 與 argv 來的。 [附註] 以下逆向工程內容以 MinGW 生產的程式為例, 系統逆向工程為 Win10 企業版 1809版  CRTStartup 在 Windows 下通常取得參數通常分為兩種狀況:  WINAPI GetCommandLineW() 系統函數返回字串指針指向當前完整應用程式參數 從 main(argc, argv) 拿回來的參數,那麼第二種狀況在編譯器是怎麼吐參數給開發者 main 入口的呢? 在編譯器吐出執行程式後,連結器會生產一段 CRTStartup 的函數用於做一些基礎的例如像是 Security Cookies、Control Flow Guard 保護的初始化,在一系列初始化之後 .data 段的全域變數 _argv、argc 紀錄著要傳入給開發者入口函數的 參數陣列 與 數量,就以參數形式呼叫 main() 函數 好問題,那這兩個全域變數是在哪裡被初始化的? 你會發現以 MinGW 為例的話,會去呼叫 msvcrt!__getmainargs() 來取得參數資訊保存到 .data 全域變數上,後續再傳遞給 main() 函數;如果是 VC++ 吐出來的則是直接呼叫 GetCommandLineW() 在做文字切割取出參數 MSVCRT MSVCRT.dll 有導出一系列 C 函數是引用 #include <stdio.h> 時會用到的,例如 printf, sprintf, gets 等等。我們剛剛提到了其導出函數 _

Process Hidden In Just one line code (Windows)

圖片
Hi there! It was an interesting case I found accidentally when building a C program to do self-update. For a Windows Programmer, it's nature to consider about using Win32 API -- MoveFileA to rename or move a file: And the interesting thing is, this API allowed us to use in the dynamic state. In other words, Windows kernel allows you to change your *.exe file name even when your program runs, or moves your self to the other directories. So I got curiosity what whould happen if the *.exe file name was not matched static file name (stored in PEB) First, I tried to change current file name when the program ran, and the result is as follow: In process explorer, the program name was displayed as the name written into PEB when file mapping. It can be found that process explorer shows process name by the file name recorded by PEB. But how is it in task manager? Task manager lists all process name with Win32 API -- EnumProcesses (I guess so), so the process name will be shown

[Windows] [Debug] 記憶體無痕鉤子 - 硬體斷點 (C++) 實作 Ring3 進程防殺

圖片
前言 其實三年前就土炮過調試器了,不過最近要做碩論(?)會用到動態路徑分析所以又重新回頭來玩一些以前寫外掛用到的技能,而翻了一下繁體中文的文獻好像對這部分沒什麼提及就寫了一篇做一個簡單整理(主要是方便我以後回頭拿來當工具用XD) 本文實作做一個標準調試器自動下硬體斷點、然後修改暫存器內容再恢復執行緒運作,藉此來達成記憶體程式碼不破損情況下做到修改程式邏輯,完成自我進程防殺(防止工作管理員殺除) Debugger 在 Windows 進程權級分割下如果想除錯其他進程要先用  AdjustTokenPrivileges 拿取 SE_DEBUG 令牌,有了這張令牌就可以除錯其他進程(不過拿這張令牌要先過 UAC 就是)接著可以用 DebugActiveProcess 函數 attach 上對應你想動態除錯的進程、接著你除錯的進程就會被掛起成 DEBUG_MODE 接著執行緒會被排程跳到 DbgBreakPoint 上踩到 \xCC 然後就拋出一個異常可以讓 Debugger 接收負責接下來對應處理。 (所以一些殼在處理 anti-attach 主要就是在 DbgBreakPoint 上一個 hotpatch 去自殺) 而接下來 Debugger 負責做的處理就是一個無限迴圈:以  WaitForDebugEvent 向系統拿取當前被掛載進程的異常事件(這個概念有點像 Win32 視窗程式的 GetMessage 架構拿消息)當被掛載進程拋錯時候, WaitForDebugEvent 就可以拿到異常事件、Debugger 負責接手接下來的事情。 所以講到這邊原理就很淺而易見可以知道:如果外掛要修改邏輯(以除錯器模式實作)就會有很基礎的三種方式去讓程式執行到想攔截的函數時,就必須拋錯,主流方法就三種: int 3 讓 CPU 踩上去時候自動拋出異常 記憶體改成不可執行的分頁區讓 DEP 防護拋出異常 或者本文要講的硬體斷點手段 硬體斷點(DR0 → DR4) 可以查閱 wiki 知道: wiki/X86_debug_register ,總之 x86 CPU 提供了每個 Thread 有四個「當前正在除錯的地址」可以指示當 CPU 正在對某塊地址進行 讀/寫/執行 時「就必須拋錯」。那麼這四個地址就分別放在