磨針記1——從*外殺馬說起

wyzsk發表於2020-08-19
作者: 路人甲 · 2015/10/15 14:57

(本文純屬虛構,如有雷同,實屬巧合)

大名鼎鼎的AspxSpy,罹患間歇性木馬病而被白道追殺。大權在握的系統管理員,冷笑著把這位老兄打入了十八層地獄。拒絕訪問,元件錯誤……連最寶貴的命令執行都要封殺。是可忍孰不可忍!拿上小饅頭,我閉關數月。

國慶悄然而至,滿街地小姐們穿著爆乳裝,齊P小短裙(學名硬得快)擠來擠去,中國首位本土科學家獲得了諾貝爾獎,我靜靜地呆在家中,把這漫長的歷練一一道來,以饗讀者。

0x00 詞彙約定


非專業術語,僅供娛樂:

Shell:這裡指類似於命令提示符的,一個用於執行可執行檔案的C#頁面。

本機程式碼:與託管程式碼對應。

0x01 *外殺馬


和* 外真是有緣,這不,最近又偶遇* 外的伺服器,規模約莫二十上下。向來伺服器的安全檢測,也有不少無法獲得最高許可權的情形,但這次最令人困惑的,是無論如何也無法在Shell中執行命令。管理員,你在挑逗我麼?不想讓我知道其中的奧妙,為何又留下了一個漏洞?給管理員戴好可愛的綠帽後,我搜遍系統,終於發現裝神弄鬼的,是一個小小驅動——*外殺馬。

圖1 *外殺馬

圖2 IDA中的*外殺馬

一個名為NotifyRoutine的函式引起了我的興趣。這是一個回撥函式,它的虛擬碼如下:

void __stdcall NotifyRoutine(HANDLE ParentId, HANDLE ProcessId, BOOLEAN Create)
{
// …
  ProcessHandle = ProcessId;
  v66 = ProcessId;
  if ( Create && PsLookupProcessByProcessId(ParentId, &Object) >= 0 )
  {
    v3 = (const char *)PsGetProcessImageFileName(Object);
    if ( !stricmp(v3, "w3wp.exe") || (v4 = (const char *)PsGetProcessImageFileName(Object), !stricmp(v4, "php-cgi.exe")) )
    {
      v5 = 1;
      PsLookupProcessByProcessId(ProcessId, &TokenHandle);
// …

圖3 NotifyRoutine

DriverEntry註冊NotifyRoutine的虛擬碼如下:

int __stdcall sub_407000(int a1, int a2)
{
// …
  DbgPrint("載入*外驅動.\n");
  PsSetCreateProcessNotifyRoutine(NotifyRoutine, 0);
// …
  return dword_405248(dword_4056BC, a1, a2, &v3, &v7, 0); 
}

圖4 PsSetCreateProcessNotifyRoutine

NotifyRoutine的流程很簡單,最重要的分支如下:

(1) 判斷是否建立了程式

(2) 是,則判斷是否由w3wp.exe所建立

(3) 是,則與白名單比較。

(4) 中止所有不在白名單上的程式

(5) 給使用者返回“拒絕訪問”的提示

白名單為硬編碼,主要放行了.Net編譯器的命令,否則原始碼就無法線上編譯執行了。它允許的命令:

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\csc.exe
C:\\WINDOWS\\Microsoft.NET\\Framework\\v4.0.30319\\csc.exe”
……

它還允許System使用者(SID為S-1-5-18)執行C:\WINDOWS\system32\cmd.exe等命令。

所有命令都帶有完整路徑,如果擁有足夠的許可權(如提權成功後),可將存在於白名單且系統中一般不存在的命令替換為你的工具,如:

C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\csc.exe
C:\\WINDOWS\\Microsoft.NET\\Framework\\v3.5\\csc.ex
…

替換後的命令在Shell中可正常執行,僅會在C盤根目錄下的日誌中留下一條NotKill記錄。

判斷系統中是否存在*外殺馬,一看C盤根目錄是否存在 7i24_com_FreeHostKill_vxxx.txt的日誌檔案,二看system32\drivers下是否存在FreeHostKill.sys,三看登錄檔。

總之,*外殺馬不僅僅殺馬,它是什麼人都殺。它只是一個極其原始的防火牆,透過監控所有程式的建立,在白名單的控制之下,哪怕位高權重的Administrators組使用者也無法在Shell中執行命令。

0x02 光明而曲折的破解之路


道高一尺,魔高一丈,既然明白了原理,就來嘗試如何破解吧。

我不知道是否有人在低許可權的指令碼環境中有辦法躲過驅動的監控,如果有,那真要頂禮膜拜了。

我不是聖人,還是按照通常的思路來完成我的Shell:

(1) 不建立程式

(2) 不建立執行緒

(3) 直接使用Shell程式碼將使用者提升至最高許可權

前途是光明的,道路是曲折的。只要有人嘗試了這條路,很快就會出現更多的探索者,期待更多的奇思妙想的出現。

許多漏洞Exploit都採用了vc++編寫,因此最初的做法是弄清漏洞的原理後,使用C#語法逐行重寫這些原始碼。十多天磨練下來,唯一的感受就是——痛苦,九九八十一重的煉獄也不過如此。

重寫內容 對人的摧殘度 說明
API DllImport API、結構、常數,PInvoke站點提供查詢
C++指標 IntPtr
託管記憶體與非託管記憶體的資料交換 Marshal類支援
內嵌彙編 ShellCode,召喚請叫我雷鋒的人

好想開個遵義會議,讓人指出一條明路。日夜google中,終於一個傢伙說,使用dll封裝你的程式碼吧。神啊,如此有創意的點子,為何不是我想出來的呢?

醍醐灌頂之後,本人的血壓暫時飆升到160,刷刷刷地把main函式改名匯出,兩分鐘內dll封裝完畢,真是無本生意的典範。看導演的安排,接下的劇情無非就是千里狙敵,褲襠藏雷,開著21世紀的R2概念車去欺負剛擺脫叢林文化的小膏藥旗了。

可惜天亮了,美夢成空,為了讓大夥不再走我的老路,我把那些令人慾仙欲死的問題總結如下:

(1) Wow64麻煩

省略幾千字,我把它放到了本系列篇(三)中加以詳述。

(2) LoadLibrary載入DLL提示無法找到模組

在本機上正常載入的DLL,天殺的虛擬機器卻提示無法找到模組。這是因為作業系統缺少DLL所依賴的執行庫檔案。若不想把自己的寶貝工具弄得像超生游擊隊,只有想辦法把庫程式碼直接封裝進DLL中。我使用兩種方式來解決:

(1)右鍵開啟專案的屬性,C/C++ - 程式碼生成 – 執行庫 – 將/MD選項改為/MT(或/MTd)選項。再次編譯,立刻發現生成的dll臃腫了不少,問題解決。

(2)把原始碼放到vc6下編譯。我首先嚐試利用vs2015環境來輔助vc6的編譯。不曾想捅了一個危險的馬蜂窩,彈出了一大串與標頭檔案有關的警告和錯誤,想來微軟也懶得保持那代價高昂的相容性了。前後折騰了半小時,乖乖放棄。接著切換到vs2010環境,無須任何的修改,vc6順利完成編譯,問題解決。

在vc6中如何編譯64位程式?山寨某前輩的經驗給懶漢們參考一下:(以vs2010為例)

分為3個步驟:

建立64位環境

在開始選單下點選“Visual Studio 2010 – Visual Studio Tools – Visual Studio x64 相容工具命令提示(2010)”,然後在此命令提示符中執行VC6:

D:\vc\vc6common\MSDev98\Bin\MSDEV.EXE /useenv

圖5 x64 相容工具命令提示

修改配置

複製Release或Debug的配置,起名xx64,啟用該配置。(1、Build – Configurations – Add…;2、Build – Set Active Configuration…)

圖6 新建Win32 Debug64配置

修改專案配置

1、在“Project Settings”對話方塊中, 點選“General”標籤. 在“Output directories”, 在“Intermediate files” 和“Output files”輸入框中, 鍵入“Debug64”(無引號)

圖7 設定輸出路徑

2、在“C/C++”標籤上, “Debug info”下拉選單中, 選擇“Program database”(引數選項對應是 /Zi)

圖8 設定除錯資訊

3、在“Link”標籤上, “Project options”的輸入框中, 將“/machine:I386”改為“/machine:AMD64”(命令中將出現兩個不同的/machine)

圖9 設定編譯指令

編譯後成功得到大腹便便的64位dll。

(3) w3wp.exe遇到無法處理的異常,網站崩潰

我的破壞力還蠻大的。把本機除錯透過的程式放到伺服器上執行,瞬間弄崩了網站,重啟IIS後再執行幾次,伺服器藍色畫面當機。

程式碼基本未變,我只是把它封裝在DLL中,由w3wp.exe載入執行,怎麼就崩潰了呢。長夜漫漫,無心睡眠,在迷糊中把IIS 7應用程式池從整合模式調整為經典模式後,異常莫明地消失了。比爾,你想玩死人麼 ?整合與經典模式到底是怎麼一回事?

圖10 整合模式處理管道

八股文常常引用上圖說明IIS7的整合模式。IIS 7整合了ASP.NET執行庫,使用統一的管道來處理請求。經典模式相容了IIS 6,如下圖所示,處理ASP.NET動態請求的只是IIS的一個外掛——ISAPI模組。同理,PHP外掛只處理PHP請求,它們各司其職,互不干涉。兩種模式的差別涇渭分明。

圖11 經典模式處理流程

還有一些值得閱讀的入門文件,如《ASP.NET Application Life Cycle Overview for IIS 7.0》,概述了ASP.NET應用程式在生命週期裡發生了什麼事情。《IIS Modules Overview》主要說明模式及其配置方式。從IIS 7的模組介面可以看到,整合模式使用託管程式碼模組來處理.aspx頁面的請求,而經典模式使用本機程式碼模組。

圖12 請求處理模組

書讀了不少,按流行俚語,“然而這並沒有什麼ruan用”,還缺少某種催化劑,看來我只能再次求助於Windbg了。

使用kp命令檢視異常發生時的呼叫棧,前後幾十個呼叫,秘密就隱藏在它們中間。仔細觀察兩種模式,為了執行我的程式碼,最後都從託管環境轉入了非託管環境,非託管環境下的呼叫完全相同。完蛋了,究竟要從哪裡下手哇。咬咬牙,開始跟吧,十多天下來,人比黃花瘦。

今天是個好日子,我升級了。我察覺自己又犯了老毛病,沒有認真檢查關鍵語句的執行結果。

if (x)
{
    // y
}

經典模式下x為真,這符合預期,然而在操蛋的整合模式下為假,稍不留神就忽略了。再追溯x的來源,終於發現整合模式似乎由於快取的影響,對本機DLL的變化不能做出實時的更新。

解決起來簡單而粗暴,加個else直接返回錯誤提示。我並不介意多執行三兩次,誰讓它們不是我的機子呢,等整合模式睡醒了,更新了它的快取,許可權也到手了。

(4) w3wp.exe已提升為System許可權,但Shell許可權不變。

經過第三階段的苦戰,我的程式碼終於可以穩定地執行了,但又出現了一個奇怪的現象。

在提升許可權之前,查詢應用程式池的使用者:

圖13 提權前使用者

此時,75804號程式,即w3wp.exe擁有IIS_IUSRS使用者許可權。緊接著提升許可權,頁面顯示了執行結果:

圖14 Shell程式碼提權

請忽略若干無用的除錯資訊,我們需要關注的是最後三行。w3wp.exe的程式號仍為75804(也可能會建立新的w3wp.exe),使用者許可權已提升為SYSTEM。

讓我們再次檢視此時應用程式池的使用者:

圖15 提權成功後使用者未變

怪哉?應用程式池的使用者為何沒有改變呢?

晚飯時間到了,補充足夠的能量後,我已經想到了一種可能。IIS啟用了模擬功能後,即使w3wp.exe以SYSTEM許可權執行,應用程式池使用者仍保持不變。

為了驗證這種可能性,讓我們亮劍,它就是用來中斷模擬的API——RevertToSelf。美女現身,Beautiful!

圖16 強制中斷IIS模擬恢復使用者身份

0x03 勝利的號角

西元201x年,001號大殺器研製成功,為紀念cctv,我把它命名為cv51。

圖17 未能進入核心無權讀寫致出錯

首次執行出錯,不必理會,再次嘗試執行。

圖18 提權成功

cv51的兄弟cvbb此時執行在SYSTEM許可權下,順利新增使用者tingting。

圖19 其他工具共享同一個w3wp.exe的許可權

登入伺服器。工作管理員中,w3wp.exe(PID:22324)在提升許可權後的身份可能顯示為SYSTEM,也可能保持不變。

圖20 模擬使工作管理員不能真實顯示Shell的許可權

檢視管理員的密碼,統計是否有使用強密碼的習慣,獲得的密碼僅用於學習與研究,將在24小時內刪除。上傳mimikatz,在命令提示符下執行如下命令,所有登入使用者盡在日誌中:(mimikatz是開源工具,請到官方站點下載,不吃毒蘋果)

mimikatz log privilege::debug sekurlsa::logonpasswords

圖21 mimikatz破解曾經登入的使用者資訊

以上測試在Windows 2003、2008及R2版本中透過。

本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!

相關文章