二、Windows RPC Demo
三、FAX服务
四、StorSvc服务
五、总 结
- 客户端将参数和要调用的方法按约定序列化成NDR(
Network Data Representation
)格式。 - 通过网络或管道将数据发送给服务端。
- 服务端接收数据后将数据反序列化,并调用对应的接口中的方法,反序列化的数据按约定作为各参数。
- 服务端方法执行结束后,将返回结果序列化。
- 再次通过网络或管道将数据发送给客户端。
- 客户端接收数据后将数据反序列化,从而获得服务端执行结果。
- 丰富的攻击面:由于RPC是许多服务的基础,因此它提供了大量的潜在攻击点。
- 高权限运行:RPC服务通常以高权限(如
SYSTEM
权限)运行,或者至少具备SeImpersonatePrivilege
权限。这意味着一旦被利用,攻击者可以利用RPC服务进行提权操作。
- 初始化 RPC 服务
- 通过
RpcServerUseProtseqEp
指定通信协议和端点。 - 通过
RpcServerRegisterIf
注册 RPC 接口(hello_ServerIfHandle
是由 MIDL 编译器对interface hello
生成的接口句柄,表示服务端的 RPC 接口)。
- 通过
- 进入监听状态
- 调用
RpcServerListen
,服务端开始监听客户端的 RPC 调用请求。
- 调用
- 处理客户端请求
- 当客户端通过 RPC 调用服务器端的远程过程时,RPC 运行时会调用相应的服务器存根代码,进而执行实际的远程方法(
HelloProc
和Shutdown
)。
- 当客户端通过 RPC 调用服务器端的远程过程时,RPC 运行时会调用相应的服务器存根代码,进而执行实际的远程方法(
- 构造字符串信息
pszEndpoint
:端点名称,指定为pipehello
,与服务端的端点一致。
-
- 通过
RpcStringBindingCompose
将协议序列、端点等信息合并为一个字符串信息。
- 通过
- 创建绑定句柄
- 通过
RpcBindingFromStringBinding
从上述字符串信息创建一个 RPC 绑定句柄,用于与服务端进行通信。
- 通过
- 调用远程方法
- 在
RpcTryExcept
异常处理块中,客户端调用服务端的远程方法(HelloProc
和Shutdown
)。
- 在
Windows Fax Server
是Windows Server
中的一个服务器角色,可被用来远程发送和接收传真。
105
个方法可被远程调用
FAX_CreateAccount
似乎是个有趣的方法,该方法会验证客户端用户是否有权限创建账户,若验证成功,则会根据传入的参数Buffer
创建对应账户。如下是该方法声明:
Buffer
是LPBYTE
类型,大小由BufferSize
决定,而<a ""="" class="weapp_text_link js_weapp_entry" href="">文档上说Buffer
应该是FAX_ACCOUNT_INFO_0
指针类型,那么意味着在FAX_CreateAccount
内部肯定会有类型转换。
Buffer: A pointer to a FAX_ACCOUNT_INFO_0 that contains fax account information. The lpcwstrAccountName member of the FAX_ACCOUNT_INFO_0 MUST be set to the name of the operating system user account for which the new fax user account is to be created, using the same account name. The format of the user account name string is described in section 2.2.24 (FAX_ACCOUNT_INFO_0).
BufferSize: A DWORD value that indicates the return size, in bytes, of the buffer that is pointed to by the Buffer parameter. The maximum size is FAX_MAX_RPC_BUFFER(section 2.2.82).
FAX_ACCOUNT_INFO_0
类型由Fixed_Portion
和Variable_Data
两部分组成。
Fixed_Portion
由dwSizeOfStruct
字段(当前Fixed_Portion
结构大小,固定为8
)和lpcwstrAccountNameOffset
字段(Variable_Data
相对FAX_ACCOUNT_INFO_0
的偏移)组成。这里需要注意的是lpcwstrAccountNameOffset
字段后续会被转换为存放指向Variable_Data
指针,64位下指针类型占用8字节,加上dwSizeOfStruct
字段的4字节,一共是12字节,对齐后Fixed_Portion
的大小为16字节,后续也是按16字节进行处理。
Variable_Data
只有lpcwstrAccountName
字段,以0结尾的字符串。
FAX_CreateAccount
里将Buffer
转换为FAX_ACCOUNT_INFO_0
的逻辑,根据BufferSize
分配一段内存,并拷贝Buffer
内容,接着调用MarshallUpStructure
。此时只检查BufferSize
不为0。
MarshallUpStructure
调用IsBufferSizeEnough
来判断原有的Buffer
大小是否足够,值得注意的是,整个过程并没有对BufferSize
进行检查,调用IsBufferSizeEnough
也不带BufferSize
。
IsBufferSizeEnough
,发现只要lpcwstrAccountNameOffset
等于0x10
即可满足要求,使IsBufferSizeEnough
返回True
。
BufferSize
为8,lpcwstrAccountNameOffset
为0x10
时,即可在后续AjustPointersInStructuresArray
中将lpcwstrAccountNameOffset
转换成指针时触发越界写。
context_handle
类型:
context_handle
,会不会存在类型混淆问题呢?实际上微软早就考虑到了这种问题,并在一开始就规定了必须使用<a ""="" class="weapp_text_link js_weapp_entry" href="">type_strict_context_handle。
This protocol MUST specify to the RPC runtime via the type_strict_context_handle attribute, which rejects the use of context handles created by a method that creates a different type of context handle ([MS-RPCE] section 3).
FAX_StartServerNotification
之后会监听1024
端口等待服务端调用FAX_OpenConnection
回连。值得注意的是此时1024
端口是监听在0.0.0.0
上,所有人都可以访问该端口。
Context
参数是一个 ULONG64
类型的句柄,其值应与通过 FAX_StartServerNotification
发送的值保持一致。
Context: A ULONG64 ([MS-DTYP] section 2.2.51) containing a context information handle. This handle SHOULD match the one supplied to the server when using the FAX_StartServerNotification family of calls. For more information, see the following topics:
§ FAX_StartServerNotification
- FAX_StartServerNotificationEx
- FAX_StartServerNotificationEx2
FAX_OpenConnection
发现并没有对Context
做任何检查,就直接作为指针使用。
RpcServerRegisterAuthInfoW
提供了认证选项,但实际上RpcServerRegisterAuthInfoW
并不拒绝未认证的连接。
1024
端口连接,发送FAX_OpenConnection
,都可以触发任意地址解引用。
StorSvc
服务并不像传真服务一样具有完整而详细的文档说明。此时可以通过借助RpcView
来反编译其接口方法说明。
RpcServerRegisterIf3
注册了两个接口。
考虑最简单的条件竞争漏洞模式:在未加锁的情况下,存在一条路径对全局变量执行释放操作。
free
释放的全局变量。
StorageService::GetLastFailedSaveLocationPath
会导致条件竞争,全局变量Block
会被释放两次。
- 丰富的攻击面:RPC服务提供了大量的潜在攻击点,需要仔细分析每个接口方法的实现和调用过程。
- 高权限运行:RPC服务通常以高权限运行,一旦被利用,攻击者可以实现提权等恶意操作。
- 复杂的通信机制:RPC的通信机制涉及参数的序列化与反序列化、网络传输等多个环节,容易出现安全漏洞。
原文始发于微信公众号(奇安信天工实验室):Windows RPC服务漏洞挖掘之旅
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论