0. 前言
CVE-2023-21752 是 2023 年開年微軟第一個有 exploit 的漏洞,原本以為有利用代碼會很好分析,但是結(jié)果花費了很長時間,難點主要了兩個:漏洞點定位和漏洞利用代碼分析,歡迎指正。
1. 漏洞簡介
根據(jù)官方信息,該漏洞是 Windows Backup Service 中的權(quán)限提升漏洞,經(jīng)過身份認證的攻擊者可利用此漏洞提升至 SYSTEM 權(quán)限。成功利用此漏洞需要攻擊者贏得競爭條件。
EXP 代碼位于 Github,提供了兩個版本,版本 1 可以實現(xiàn)任意文件刪除,可穩(wěn)定復現(xiàn);版本 2 嘗試利用任意刪除實現(xiàn)本地提權(quán),但是復現(xiàn)不穩(wěn)定。
2. 漏洞點定位的曲折之路
這部分內(nèi)容是一些失敗的過程記錄,防止自己之后犯同樣的錯誤,只對漏洞分析感興趣的可以略過 2.1 和 2.3 小節(jié)。
【一一幫助安全學習一一】
①網(wǎng)絡(luò)安全學習路線
②20 份滲透測試電子書
③安全攻防 357 頁筆記
④50 份安全攻防面試指南
⑤安全紅隊滲透工具包
⑥網(wǎng)絡(luò)安全必備書籍
⑦100 個漏洞實戰(zhàn)案例
⑧安全大廠內(nèi)部視頻資源
⑨歷年 CTF 奪旗賽題解析
2.1 失敗的過程
首先嘗試復現(xiàn),提權(quán)版本的利用程序在虛擬機上沒有復現(xiàn)成功,任意文件刪除版本的利用程序由于沒有使用完整路徑,也沒有復現(xiàn)成功。
之后嘗試進行補丁對比,但是想要進行補丁對比首先要確定漏洞位于哪個文件中,根據(jù)漏洞利用程序的文件命名 SDRsvcEop
,找到了文件 sdrsvc.dll,但是補丁對比后并沒有發(fā)現(xiàn)差異。
搜索了關(guān)于這個漏洞的信息,但是除了漏洞通告和 GitHub 的 exp 代碼外,沒有找到其他內(nèi)容。
這個時候已經(jīng)開始對漏洞利用代碼進行分析了,一方面通過微軟的文檔,了解代碼中一些函數(shù)和參數(shù)的使用,一方面開始在 Windbg 上進行調(diào)試,并由此找到了 rpcrt4.dll、combase.dll 這些和漏洞無關(guān)的文件。
在調(diào)試過程中,花費了很多時間在 DeviceIoControl
這個函數(shù)上,因為之前看的很多漏洞最終定位的文件都是 sys 驅(qū)動文件,因此為 dll 文件留了一些位置,但是在方法選擇上,仍舊趨向去尋找某個 sys 文件。
在這個時候才想起來要把利用程序參數(shù)的相對路徑改成絕對路徑,并且成功復現(xiàn)了任意文件刪除。
之前學習病毒分析的時候,有一個算是標準的流程,就是要先執(zhí)行病毒,看一下它的動態(tài)特征,以此方便后面的動態(tài)分析。之前看的很多漏洞分析文章,也都是要執(zhí)行一下 poc 或者 exp,進行進程監(jiān)控,雖然想到了這個方法,但是并沒有十分重視。
繼續(xù)分析漏洞利用代碼,在此期間看了一些關(guān)于 DCOM 的資料,確定 sdrsvc.dll 是依賴 rpcss.dll 文件功能的(明明可以通過 process hacker 直接確定的……),通過補丁對比發(fā)現(xiàn)函數(shù) CServerSet::RemoveObject
被修改,嘗試在 Windbg 中在這個函數(shù)設(shè)置斷點,但是利用程序沒有執(zhí)行到這里,所以漏洞點不在這個文件。
2.2 轉(zhuǎn)入正軌
此時我仍舊沒有使用 procmon 對利用程序進行監(jiān)控,我選擇在安裝補丁前后的系統(tǒng)上執(zhí)行利用程序,并檢查輸出(輸出內(nèi)容做了一些修改),得到以下結(jié)果(因為只是測試功能,并沒有選擇對高權(quán)限文件進行刪除):
補丁修復前
PS C:\Users\exp\Desktop> C:\Users\exp\Desktop\SDRsvcEop.exe C:\Users\exp\Desktop\test.txt
[wmain] Directory: C:\users\exp\appdata\local\temp\23980418-9164-497e-8ce7-930949d1af55
[Trigger] Path: \\127.0.0.1\c$\Users\exp\AppData\Local\Temp\23980418-9164-497e-8ce7-930949d1af55
[FindFile] Catch FILE_ACTION_ADDED of C:\users\exp\appdata\local\temp\23980418-9164-497e-8ce7-930949d1af55\SDT2C35.tmp
[FindFile] Start to CreateLock...
[cb] Oplock!
[CreateJunction] Junction \\?\C:\Users\exp\AppData\Local\Temp\23980418-9164-497e-8ce7-930949d1af55 -> \RPC Control created!
[DosDeviceSymLink] Symlink Global\GLOBALROOT\RPC Control\SDT2C35.tmp -> \??\C:\Users\exp\Desktop\test.txt created!
[Trigger] Finish sdc->proc7
[wmain] Exploit successful!
[DeleteJunction] Junction \\?\C:\Users\exp\AppData\Local\Temp\23980418-9164-497e-8ce7-930949d1af55 deleted!
[DelDosDeviceSymLink] Symlink Global\GLOBALROOT\RPC Control\SDT2C35.tmp -> \??\C:\Users\exp\Desktop\test.txt deleted!
復制代碼
補丁修復后
PS C:\Users\exp\Desktop> C:\Users\exp\Desktop\SDRsvcEop.exe C:\Users\exp\Desktop\test.txt
[wmain] Directory: C:\users\exp\appdata\local\temp\183c772e-f444-4aec-a489-7d9f734ee719
[Trigger] Path: \\127.0.0.1\c$\Users\exp\AppData\Local\Temp\183c772e-f444-4aec-a489-7d9f734ee719
[FindFile] Catch FILE_ACTION_ADDED of C:\users\exp\appdata\local\temp\183c772e-f444-4aec-a489-7d9f734ee719\SDT1F8A.tmp
[Trigger] Finish sdc->proc7
_
復制代碼
由此可知修復后利用程序無法再獲取一個 tmp 文件的句柄,我猜測應(yīng)該是補丁修復之前,漏洞文件創(chuàng)建了這個 tmp 文件,并且創(chuàng)建的權(quán)限有問題(這個猜測不一定準確),但是這個猜測目前沒什么用,還是沒辦法定位漏洞文件。
終于想起來要用 procmon 了。
根據(jù)上面利用程序輸出結(jié)果的對比,確定漏洞修復的位置和創(chuàng)建的 tmp 文件有關(guān),因此格外注意 procmon 中該文件的創(chuàng)建操作:
并在 Stack 選項卡中,定位到 sdrsvc.dll 調(diào)用的功能位于 sdengin2.dll 中:
根據(jù) SdCheck + 0x490c2
,在 IDA 中定位到函數(shù) CSdCommonImpl::QueryStorageDevice
,該地址為這個函數(shù)調(diào)用 QueryStorageDevice
的位置。
經(jīng)過補丁對比,發(fā)現(xiàn)了函數(shù) IsWritable
,這個函數(shù)進行了修改,并且被 QueryStorageDevice
所調(diào)用。
【一一幫助安全學習一一】
①網(wǎng)絡(luò)安全學習路線
②20 份滲透測試電子書
③安全攻防 357 頁筆記
④50 份安全攻防面試指南
⑤安全紅隊滲透工具包
⑥網(wǎng)絡(luò)安全必備書籍
⑦100 個漏洞實戰(zhàn)案例
⑧安全大廠內(nèi)部視頻資源
⑨歷年 CTF 奪旗賽題解析
2.3 反思
這次漏洞分析遇到了幾個障礙:
-
無法通過漏洞名稱直接確認漏洞文件,導致無法使用常用的補丁對比的分析方法;
-
exp 一開始未成功復現(xiàn),這種情況對我來說很常見,但是由于不清楚原因,我以為是對備份服務(wù)的功能以及 exp 代碼不熟悉導致;
-
由于不熟悉利用代碼:
-
花費很多時間查找相關(guān)資料;
-
需要對輔助功能代碼和直接漏洞利用代碼進行區(qū)分。
除此之外,之前極少分析帶有 exp 且 exp 可以正常復現(xiàn)的漏洞,習慣從靜態(tài)分析入手,再使用 windbg 動態(tài)輔助分析。一般遇到可以使用的 poc,我也是直接觸發(fā)崩潰,然后使用 windbg 從崩潰開始進行調(diào)試分析,從沒有使用過 procmon 進行動態(tài)監(jiān)控,并且這樣的方法也都成功對漏洞進行了分析,因此輕視了 procmon 動態(tài)監(jiān)控方法的有效性。
不過 procmon 也不是萬能的,目前看來,這個方法在漏洞點定位上十分有效,但是如果通過其他信息已經(jīng)能夠?qū)β┒袋c進行定位,那么 procmon 提供的幫助就不那么顯著了,而且通過其他方法也能夠完成漏洞分析。
3. 漏洞原理
3.1 補丁對比
漏洞修復前:
__int64 __fastcall IsWritable(unsigned __int16 *a1, int a2, int *a3)
{
...
v7 = -1;
if ( a2 == 7 )
{
if ( !GetTempFileNameW(a1, L"SDT", 0, TempFileName) )// 如果獲取 temp 文件名失敗,進入 if 語句
{
rtnValue = v17;
LABEL_28:
*a3 = v6;
toend2:
if ( v7 != -1 )
{
CloseHandle(v7);
rtnValue = v17;
}
goto end;
}
rtnValue = SxDeleteFile(TempFileName); // 刪除之前可能存在的 tmp 文件
v17 = rtnValue;
v8 = 0x148;
if ( rtnValue >= 0 ) // 刪除成功
{
v18 = 0x148;
LABEL_27:
v6 = 1;
goto LABEL_28;
}
toend:
v19 = v8;
goto end;
}
...
}
復制代碼
上述代碼中的 a2 和傳入的路徑類型有關(guān),由于利用程序傳入的是 UNC 路徑,因此最終程序執(zhí)行流程到達此處。
根據(jù) GetTempFileNameW
函數(shù)的文檔說明,當其第三個參數(shù)為數(shù)值 0 時,該函數(shù)會嘗試使用系統(tǒng)時間生成一個唯一數(shù)字文件名,如果該文件已存在,數(shù)字遞增直至文件名唯一,在這種情況下,該函數(shù)會創(chuàng)建一個該文件名的空文件并釋放其句柄。因此在漏洞修復之前,系統(tǒng)通過 GetTempFileNameW
創(chuàng)建臨時文件是否成功的方式檢查傳入的 unc 路徑是否可以寫入,如果可以寫入,再刪除創(chuàng)建的這個臨時文件。
漏洞修復后:
__int64 __fastcall IsWritable(unsigned __int16 *a1, int a2, int *a3)
{
...
v7 = -1;
if ( a2 == 7 )
{
if ( CheckDevicePathIsWritable(a1) < 0 )
{
LABEL_10:
rtnValue = v16;
*a3 = v6;
toend2:
if ( v7 != -1 )
{
CloseHandle(v7);
rtnValue = v16;
}
goto end;
}
LABEL_9:
v6 = 1;
goto LABEL_10;
}
復制代碼
漏洞修復后,原本 GetTempFileNameW
函數(shù)的位置變成了 CheckDevicePathIsWritable
,GetTempFileNameW
函數(shù)的實現(xiàn)位于 kernelbase.dll 文件中,如果你仔細對比,會發(fā)現(xiàn)這兩個函數(shù)中的大部分代碼相同,只有一處差異點需要注意,就是在創(chuàng)建臨時文件的時候,兩者的代碼如下:
// GetTempFileNameW
v24 = CreateFileW(lpTempFileName, GENERIC_READ, 0, 0i64, 1u, 0x80u, 0i64);
// CheckDevicePathIsWritable
v22 = CreateFileW(FileName, GENERIC_READ, 0, 0i64, 1u, 0x4000080u, 0i64);
復制代碼
可以看到在 CheckDevicePathIsWritable
函數(shù)中,CreateFileW
函數(shù)的第六個參數(shù) dwFlagsAndAttributes
數(shù)值由 0x80
變成了 0x4000080
,即從 FILE_ATTRIBUTE_NORMAL
變成了 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE
。
根據(jù)文檔說明,FILE_FLAG_DELETE_ON_CLOSE
表示文件會在所有句柄關(guān)閉時直接刪除,并且之后打開該文件的請求必須包含 FILE_SHARE_DELETE
共享模式,否則會失敗。
簡單來說,修復后的代碼將臨時文件的創(chuàng)建和刪除操作整合成為了一個元操作。
3.2 漏洞原理分析
上面補丁對比的結(jié)果可以確定這是一個條件競爭漏洞,由于臨時文件的創(chuàng)建操作和刪除操作接次發(fā)生,并且在兩個操作之間沒有對文件進行限制,這就導致攻擊者可以創(chuàng)建另一線程,在臨時文件創(chuàng)建之后,刪除之前,獲取文件句柄并創(chuàng)建機會鎖阻止其他線程操作,同時將文件刪除,并設(shè)置原文件路徑指向其他文件,當機會鎖釋放后,指向的其他文件就會被刪除。
4. 漏洞利用
4.1 文件刪除漏洞利用代碼流程總結(jié)
-
在臨時文件夾下,使用
FULL_SHARING
模式創(chuàng)建目錄 dir ,作為上述臨時文件的保存位置; -
創(chuàng)建線程 FindFile,監(jiān)控 dir 目錄下的文件創(chuàng)建操作:
-
獲取創(chuàng)建文件句柄并創(chuàng)建機會鎖;
-
將創(chuàng)建的文件移動到其他目錄下;
-
創(chuàng)建符號鏈接,將原文件路徑指向要刪除的目標文件;
-
釋放機會鎖;
-
主線程將目錄 dir 的路徑轉(zhuǎn)換為 unc 格式,并通過
CoCreateInstance
的方式調(diào)用 sdrsvc 服務(wù)的CSdCommonImpl::QueryStorageDevice
接口; -
sdrsvc 服務(wù)在 unc 格式目錄下創(chuàng)建臨時文件,之后刪除文件。
如下圖所示:
4.2 提權(quán)漏洞利用
4.2.1 原理分析
這部分內(nèi)容基本上看 ZDI 的文章就可以,這里做一下介紹。
簡單來說,從 任意文件刪除 到本地提權(quán),需要與 MSI installer 文件運行過程進行條件競爭。
Windows Installer 服務(wù)負責應(yīng)用程序的安裝,而 msi 文件定義了安裝過程中會發(fā)生的變化,例如創(chuàng)建了哪些文件夾、復制了哪些文件、修改了哪些注冊表等等。因為程序安裝過程中會對系統(tǒng)進行修改,為了避免安裝出錯導致系統(tǒng)無法恢復,msi 會在運行時創(chuàng)建文件夾 C:/Config.msi
,將安裝過程中做的所有更改記錄到 .rbs 后綴的文件中,同時將被替換的系統(tǒng)文件存儲為 .rbf 格式放入該文件夾。所以如果可以替換其中的 rbf 文件,就能將系統(tǒng)文件替換為任意惡意文件。正是因為有文件替換的風險,所以 C:/Config.msi
及其中的文件默認具有強 DACL。
但是如果攻擊者能做到 任意目錄刪除,就可以將 C:/Config.msi
刪除,重新創(chuàng)建一個弱 DACL 的 C:/Config.msi
目錄,并在 msi 程序創(chuàng)建完 rbs 和 rbf 文件之后,對其進行替換,使用惡意 rbf 文件實現(xiàn)提權(quán)。
具體來看,msi 在運行時經(jīng)歷了 創(chuàng)建->刪除->再創(chuàng)建 的過程,之后才會開始創(chuàng)建 rbs 文件,因此 任意目錄刪除 需要在 再創(chuàng)建 之后,rbs 文件創(chuàng)建之前刪除 C:/Config.msi
目錄,并監(jiān)控 rbs 文件的產(chǎn)生,對文件進行替換,條件競爭就發(fā)生在這里。
上面提到的漏洞是 任意目錄刪除,如果發(fā)現(xiàn)的是 任意文件刪除,可以刪除 C:/Config.msi::$INDEX_ALLOCATION
數(shù)據(jù)流,同樣可以實現(xiàn)目錄的刪除。
利用任意文件刪除漏洞實現(xiàn)提權(quán)的流程如下圖所示:
4.2.2 失敗原因分析
上面介紹的流程把 Config.msi 的刪除 當作一個元操作,但在 CVE-2023-21752 這個漏洞中,文件刪除同樣需要條件競爭才能實現(xiàn),具有相對繁瑣的步驟。也就是說想要利用這個漏洞實現(xiàn)本地提權(quán),需要同時實現(xiàn)贏得兩個條件競爭,這也是一開始復現(xiàn)總是失敗的原因。
為了方便了解利用代碼的執(zhí)行流程,對代碼中的注釋進行了添加和修改,得到了如下的執(zhí)行結(jié)果:
PS C:\Users\exp\Desktop> C:\Users\exp\Desktop\SDRsvcEop.exe
[wmain] Config.msi directory created!
[wmain] Directory: C:\users\exp\appdata\local\temp\3bbbd2cf-7baf-42b7-98ea-242f703b08f8
[wmain] Got handle of uuid directory
[wmain] Finish create oplock for config.msi
[Trigger] Path: \\127.0.0.1\c$\Users\exp\AppData\Local\Temp\3bbbd2cf-7baf-42b7-98ea-242f703b08f8
[FindFile] Found added file C:\users\exp\appdata\local\temp\3bbbd2cf-7baf-42b7-98ea-242f703b08f8\SDT73B.tmp
[FindFile] Got handle of C:\users\exp\appdata\local\temp\3bbbd2cf-7baf-42b7-98ea-242f703b08f8\SDT73B.tmp
[cb] Oplock!
[Move] Finish moving to \??\C:\windows\temp\c5b82788-8133-4971-b351-38f58233ced1
[CreateJunction] Junction \\?\C:\Users\exp\AppData\Local\Temp\3bbbd2cf-7baf-42b7-98ea-242f703b08f8 -> \RPC Control created!
[DosDeviceSymLink] Symlink Global\GLOBALROOT\RPC Control\SDT73B.tmp -> \??\C:\Config.msi::$INDEX_ALLOCATION created!
[FindFile] End
[Move] Finish moving to \??\C:\windows\temp\0f1161f2-a8c5-4798-a71d-f32ebba87125
[install] MSI file: C:\windows\temp\MSI72F.tmp
[install] Start ACTION=INSTALL
[cb1] Detect first create
[cb1] Detect first delete
[install] Start REMOVE=ALL
[install] Start delete msi file
[Fail] Race condtion failed!
[DeleteJunction] Junction \\?\C:\Users\exp\AppData\Local\Temp\3bbbd2cf-7baf-42b7-98ea-242f703b08f8 deleted!
[DelDosDeviceSymLink] Symlink Global\GLOBALROOT\RPC Control\SDT73B.tmp -> \??\C:\Config.msi::$INDEX_ALLOCATION deleted!
復制代碼
在不同流程的結(jié)果之間添加了回車,方便觀察,可以看到在 刪除文件 流程中,程序監(jiān)控到了臨時文件的生成,也創(chuàng)建了符號鏈接,但是由于符號鏈接將臨時文件鏈接到了 C:/Config.msi::$INDEX_ALLOCATION
上,而 C:/Config.msi
的機會鎖又掌握在 msi 線程上,因此刪除操作停滯了。
于此同時 msi 線程上只監(jiān)測到了 C:\\Config.msi
的第一次創(chuàng)建和刪除,并沒有監(jiān)測到第二次創(chuàng)建,因為這里使用了循環(huán)對創(chuàng)建行為進行檢測,因此該線程也陷入了無限循環(huán)。
與 msi 的條件競爭失敗,導致兩個線程發(fā)生死鎖,漏洞利用失敗。
4.2.3 問題解決
首先,將利用代碼的整個流程畫成了如下的流程圖:
紅框部分就是條件競爭失敗的地點。
嘗試增加虛擬機的 CPU 數(shù)量,對監(jiān)控 Config.msi 創(chuàng)建的代碼進行優(yōu)化,但是都沒有成功。同時也單獨使用 procmon 監(jiān)控了 msi 文件的運行過程,確定 Config.msi 目錄確實發(fā)生了二次創(chuàng)建。
所以結(jié)論只有一個,Config.msi 目錄的二次創(chuàng)建發(fā)生的太快了。但是既然 Config.msi 目錄的二次創(chuàng)建是確實發(fā)生的,同時利用代碼已經(jīng)監(jiān)測到了第一次刪除的行為,那么如果這個時候就釋放機會鎖 2,又會如何呢?
如果不對 Config.msi 目錄的二次創(chuàng)建進行監(jiān)控,直接釋放機會鎖 2,因為 Config.msi 目錄的二次創(chuàng)建時間間隔非常短,等待良久的 sdrsvc 就有機會成功刪除 Config.msi。此時漏洞利用流程可以繼續(xù)進行下去,并成功實現(xiàn)漏洞利用!
3.2 符號鏈接的問題
之前對利用代碼中如何鏈接向待刪除文件存在疑問,實際上這種利用手法來自 James Forshaw,參考鏈接 5 和 6 對其進行了介紹。
重分析點/Junction 是一種 NTFS 文件系統(tǒng)中文件夾的屬性,NTFS 驅(qū)動在打開文件夾的時候會對它進行讀取??梢允褂盟鼘δ夸浿g進行鏈接,假設(shè)要建立目錄 A 向目錄 B 的重分析點,只要普通用戶對目錄 A 具有可寫權(quán)限就能夠進行,而對目錄 B 的權(quán)限沒有任何要求。
在 Windows 系統(tǒng)中,我們常提到的 C 盤目錄并不是一個真的文件夾,它實際上是一個指向設(shè)備物理地址的符號鏈接對象,你可以使用 WinObj 在 \GLOBAL??
中看到 C:
項是一個 SymbolicLink
。當我們訪問 C 盤中的某個文件時,系統(tǒng)會對訪問路徑進行轉(zhuǎn)換,轉(zhuǎn)換成真正的設(shè)備物理地址。普通用戶也可以在對象管理器中添加或刪除符號鏈接,但是該行為只能在有限的目錄下進行,例如 \RPC Control
.
在上面利用代碼執(zhí)行結(jié)果中,有下面兩行輸出:
[CreateJunction] Junction \\?\C:\Users\exp\AppData\Local\Temp\3bbbd2cf-7baf-42b7-98ea-242f703b08f8 -> \RPC Control created!
[DosDeviceSymLink] Symlink Global\GLOBALROOT\RPC Control\SDT73B.tmp -> \??\C:\Config.msi::$INDEX_ALLOCATION created!
復制代碼文章來源:http://www.zghlxwxcb.cn/news/detail-429788.html
首先創(chuàng)建了攻擊者可控的目錄 3bbbd2cf-7baf-42b7-98ea-242f703b08f8
指向 \RPC Control
的重分析點,這樣訪問 \RPC Control
就相當于訪問這個可控目錄;之后在 \RPC Control
下面創(chuàng)建了一個由 SDT73B.tmp
指向待刪除文件的符號鏈接,這一步就相當于將可控目錄下的 SDT73B.tmp
指向了待刪除文件,刪除 SDT73B.tmp
就相當于刪除了目標文件文章來源地址http://www.zghlxwxcb.cn/news/detail-429788.html
到了這里,關(guān)于【網(wǎng)絡(luò)安全】本地提權(quán)漏洞分析的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!