M08 · CTF
Mach port rights 與 bootstrap 查名
在 IPC 連線圖裡,一個 daemon 已向 launchd(PID 1,bootstrap server)註冊了 service 名與它的 receive right。 讓一個 client 用 service 名做 bootstrap_look_up,觀察它拿回的是一份 send right(而非 receive right), 再用這個 send right 送一條 Mach 訊息建立連線。接著指出:為什麼同一個 kernel port 在 client 與 daemon 手上的 port name 不同(handle 是 per-task 的),以及為什麼一個 port 同時只能有一個 receive right 持有者。
XPC 呼叫方驗證(confused-deputy 根因 vs 防禦)
- 高權 service 收到請求,需決定「該不該為這個呼叫方做事」。
- 用 PID 識別呼叫方 → 再拿 PID 去查身分/entitlement。
- PID 在 check 後、use 前被回收給另一個(低權)進程(TOCTOU 窗口)。
- service 對「原本那個 PID 的身分」放行,實際服務的卻是新進程 → 身分對錯對象。
根因:用 PID 認呼叫方(check 與 use 之間 PID 可被回收 → 身分對錯對象)。防禦一句話:驗 audit token,不驗 PID(含 pidversion,kernel 擔保)。本實驗室只示範類別與防禦,不含提權步驟。
過關目標
- 讓 bootstrap.lookUp.com_apple_example_helper.returnedRight 達到 "send"
- 讓 connection.client_to_daemon.established 達到 true
- 讓 port.helperService.receiveRightHolders 達到 1
- 用自己的話解釋:client 用 service 名 bootstrap_look_up 之後,為什麼拿到的是 send right 而不是 receive right?又:為什麼同一個 kernel port 在 client 與 daemon 手上的 port name(handle)不一樣?
解答是「操作模擬器到對的狀態 + 能說出原理」,非提交 flag 字串。互動式自動評分為 roadmap 項目;目前以自我檢核完成。
提示
卡住時
client 查名拿到的是 send right(能送訊息的能力);receive right(收訊息的伺服端)一直在 daemon/交由 launchd 管理,不會發給 client。
走錯方向時
port name 是 per-task 的不透明 handle——同一個 kernel port 物件在不同進程手上是不同的數字,不能拿一個進程的 name 去另一個進程用。
想更深入
一個 port 同時只能有一個 receive right 持有者(單一伺服端),但 send right 可有多份並隨訊息傳遞——這是能力導向 IPC 的底層。