iT邦幫忙

2023 iThome 鐵人賽

DAY 27
0
Security

Windows Security 101系列 第 27

[Day27] Introduction to Logical Privilege Escalation on Windows (Part 4): RPC

  • 分享至 

  • xImage
  •  

今天要介紹的是 Remote Procedure Call (RPC),也是 Windows 中常見的 Inter Process Communication (IPC) 機制之一。

RPC Server

在註冊 PRC Server 的階段可以用下圖表示

https://ithelp.ithome.com.tw/upload/images/20231011/20120098E3svaYZDwh.png

接下來,透過介紹上述的 API,分享有哪些設定是非常重要,一旦設定錯誤很有可能被攻擊者濫用。

RpcServerUserProtseq*

這邊以 RpcServerUserProtseqEp 為例

RPC_STATUS RpcServerUseProtseqEp(
  RPC_CSTR     Protseq,
  unsigned int MaxCalls,
  RPC_CSTR     Endpoint,
  void         *SecurityDescriptor
);

Protseq 用來指定 RPC 的連線模式。根據 csandker 的文章,可以以前綴作為 protocol 的區分:

  • Network Computing Architecture connection-oriented protocol (NCACN)
  • Network Computing Architecture datagram protocol (NCADG)
  • Network Computing Architecture local remote procedure call (NCALRPC)

只有 NCACN 可以接受 remote 連接,其他都是 local

比較常見的 protocol 有以下幾種:

  • ncacn_ip_tcp
    • TCP
  • ncacn_http
    • HTTP
  • ncacn_np
    • Named Pipe (SMB)
  • ncadg_ip_udp
    • UDP
  • ncalrpc
    • ALPC

SecurityDescriptor 只適用於 ncalrpcncacn_np,其他 protocol 則不適用。 (不確定像是 ncacn_ip_tcp 是不是因為 TCP socket 沒有辦法綁定 SecurityDescriptor)

另外,MSDN 也特別說明不推薦在 endpoint 綁定 SecurityDescriptor 。但是這點在 James Forshaw 的文章有不同的看法。

除了 RpcServerUserProtseqEp ,也可以使用 RpcServerUserProtseq 指定 Dynamic Endpoints,也就是由系統指派。

由 RPC Endpoint Mapper service 負責管理 Dynamic Endpoints。

使用 Dynamic Endpoints 時, server 還需要使用 RpcServerInqBindingsRpcEpRegister 向 RPC Endpoint Mapper 註冊。

RpcServerRegisterIf*

這邊以 RpcServerRegisterIf3 為例

RPC_STATUS RpcServerRegisterIf3(
  [in]           RPC_IF_HANDLE      IfSpec,
  [in, optional] UUID               *MgrTypeUuid,
  [in, optional] RPC_MGR_EPV        *MgrEpv,
  [in]           unsigned int       Flags,
  [in]           unsigned int       MaxCalls,
  [in]           unsigned int       MaxRpcSize,
  [in, optional] RPC_IF_CALLBACK_FN *IfCallback,
  [in, optional] void               *SecurityDescriptor
);

RPC Interface 設定檔 IDL 在經過 midl.exe 編譯後,會生成 MIDL 結構,註冊時需要將 MIDL 結構放在參數 IfSpec

MIDL 結構是基於 RPC NDR Engine。在 client 使用 RPC call 的時候,會將參數 marshalling 傳遞。

根據 csandker 的 example,下面是個簡單的 IDL:

[
// UUID: A unique identifier that distinguishes this
	// interface from other interfaces.
	uuid(9510b60a-2eac-43fc-8077-aaefbdf3752b),

	// This is version 1.0 of this interface.
	version(1.0),

	
	// Using an implicit handle here named hImplicitBinding:
	implicit_handle(handle_t hImplicitBinding)
	
]
interface Example1 // The interface is named Example1
{
	// A function that takes a zero-terminated string.
	int Output(
		[in, string] const char* pszOutput);

	void Shutdown();
}

RPC server 和 client 雙方都必須知道這個 IDL,client 才能夠以這個 IDL 和 server 互動。

SecurityDescriptor 是用來指定 RPC Interface 的 Security Descriptor。預設會是

Flags

  • RPC_IF_ALLOW_CALLBACKS_WITH_NO_AUTH
    • 所有的連接都會觸發 Security Callback。
    • 如果有註冊 Security Callback,但卻沒有啟用此 flag,那麼任何未通過驗證的 client 會被拒絕連接
  • RPC_IF_ALLOW_LOCAL_ONLY
    • 只允許 Local RPC call
    • 只有當 RPC 不是由 SRV 呼叫時, ncacn_np 才可以使用
    • ncalrpc 可以使用
  • RPC_IF_AUTOLISTEN
    • RPC server 註冊後就會 listen,直到 RPC server 被註銷
  • RPC_IF_OLE
    • Reserved for OLE. Do not use this flag.
  • RPC_IF_ALLOW_UNKNOWN_AUTHORITY
    • Currently not implemented.
  • RPC_IF_ALLOW_SECURE_ONLY
    • Client 必須的驗證必須高於 RPC_C_AUTHN_LEVEL_NONE
    • 低權限用戶有合法身分也可以連接
  • RPC_IF_SEC_NO_CACHE
    • 停止 security callback caching
    • 每次 RPC 呼叫都會觸發 security callback

IfCallback 也就是所謂的 Security Callback,每當 client 連接時,在檢查完 Security Descriptor 後會先觸發 Security Callback。如果需要身分驗證,通常會在 Security Callback 中實作身分驗證的檢查,因為 RPC server 沒辦法指定驗證的 level。

Security Callback 回傳 RPC_S_OK 表示可以執行後續的操作。

RpcBindingInqAuthClient

RPC_STATUS RpcBindingInqAuthClient(
  RPC_BINDING_HANDLE ClientBinding,
  RPC_AUTHZ_HANDLE   *Privs,
  RPC_WSTR           *ServerPrincName,
  unsigned long      *AuthnLevel,
  unsigned long      *AuthnSvc,
  unsigned long      *AuthzSvc
);

在 Security Callback 中 RpcBindingInqAuthClient 使用 xxx 可以依據 Authenticaiton level 有不同的要求:

  • RPC_C_AUTHN_LEVEL_NONE
    • 沒有驗證身分
  • RPC_C_AUTHN_LEVEL_CONNECT
    • 只有在連接時驗證身分
  • RPC_C_AUTHN_LEVEL_PKT_INTEGRITY
    • 在連接時驗證身分,每次呼叫都有完整性校驗
  • RPC_C_AUTHN_LEVEL_PKT_PRIVACY
    • 在連接時驗證身分,每次呼叫都有完整性校驗和加密

RpcServerRegisterAuthInfo

RPC_STATUS RpcServerRegisterAuthInfo(
  RPC_CSTR                  ServerPrincName,
  unsigned long             AuthnSvc,
  RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn,
  void                      *Arg
);

和 Named Pipe 不同,RPC 可以額外設定 AuthnSvc 選擇 Authentication Service Provider 進行身分驗證:

  • RPC_C_AUTHN_WINNT
    • NTLM
  • RPC_C_AUTHN_GSS_KERBEROS
    • Kerberos

其他的 Auth Service Provider 可以參考 MSDN,基本上和 SSPI 是一樣的,

RpcServerInqBindings

RPC_STATUS RpcServerInqBindings(
  RPC_BINDING_VECTOR **BindingVector
);

回傳 binding handle

RpcEpRegister

RPC_STATUS RpcEpRegister(
  RPC_IF_HANDLE      IfSpec,
  RPC_BINDING_VECTOR *BindingVector,
  UUID_VECTOR        *UuidVector,
  RPC_CSTR           Annotation
);

使用 Dynamic Endpoints 時,使用此 API 向 RPC Endpoint Mapper 註冊。

RpcServerListen

RPC_STATUS RpcServerListen(
  unsigned int MinimumCallThreads,
  unsigned int MaxCalls,
  unsigned int DontWait
);

RPC Server 開始 Listen。

RPC Client

在看別人的 writeups 都覺得 RPC Client 好像很簡單,實際寫的時候會發現超多坑,但時間不夠就不贅述了。

RpcStringBindingCompose

RPC_STATUS RpcStringBindingCompose(
  RPC_CSTR ObjUuid,
  RPC_CSTR ProtSeq,
  RPC_CSTR NetworkAddr,
  RPC_CSTR Endpoint,
  RPC_CSTR Options,
  RPC_CSTR *StringBinding
);

建立 string binding handle

RpcBindingFromStringBinding

RPC_STATUS RpcBindingFromStringBinding(
  RPC_CSTR           StringBinding,
  RPC_BINDING_HANDLE *Binding
);

回傳 binding handle

RpcBindingSetAuthInfoEx

RPC_STATUS RpcBindingSetAuthInfo(
  RPC_BINDING_HANDLE       Binding,
  RPC_CSTR                 ServerPrincName,
  unsigned long            AuthnLevel,
  unsigned long            AuthnSvc,
  RPC_AUTH_IDENTITY_HANDLE AuthIdentity,
  unsigned long            AuthzSvc
);

Client 未必要使用此 API 進行 Authentication Binding,即使 Server 有設定 Authentication Binding,也有可能成功連接 RPC Interface。以下有兩種情境:

  • RPC_IF_ALLOW_CALLBACKS_WITH_NO_AUTH
    • 未驗證的 client 可以連接
  • RPC_IF_ALLOW_SECURE_ONLY
    • 未驗證的 client 驗證等級必須高於 RPC_C_AUTHN_LEVEL_NONE

另外在 IDL 當中還分為 implicit binding, explicit binding 和 automatic binding 3種:

  • implicit binding
    • client 只會和在 IDL 中指定的 RPC server 連線
    • 不是 thread safe
  • explicit binding
    • 允許 client 連接多個 RPC server
    • thread safe
  • automatic binding

最後,Client 在完成 RPC 連接後,就可以根據 IDL 發起 RPC call。

References


上一篇
[Day26] Introduction to Logical Privilege Escalation on Windows (Part 3): Named Pipe
下一篇
[Day28] Introduction to Logical Privilege Escalation on Windows (Part 5): COM
系列文
Windows Security 10130
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言