Skip to content

Latest commit

 

History

History
179 lines (143 loc) · 9.79 KB

File metadata and controls

179 lines (143 loc) · 9.79 KB

sudo --chroot 옵션을 통한 NSS 라이브러리 로드 (CVE-2025-32463, "chwoot")

메타데이터

항목 내용
CVE ID CVE-2025-32463
영향 버전 sudo 1.9.14 ~ 1.9.17 (모든 p 리비전)
CVSS v3.1 9.3 (Critical) — 배포판에 따라 7.8(High)로 재평가되기도 함
공개일 2025-06-30
발견자 Rich Mirch (Stratascale Cyber Research Unit)
별칭 "chwoot"

개요

sudo--chroot(-R) 옵션으로, 명령을 실행하기 전에 프로세스의 루트 디렉터리를 사용자가 지정한 디렉터리로 바꿔주는 기능을 제공했다. CVE-2025-32463은 이 옵션을 처리하는 과정에서 아직 sudoers 정책 검사(이 사용자가 애초에 sudo를 쓸 자격이 있는지)를 마치기도 전에 루트 디렉터리 전환이 먼저 일어나 버려서, 그 직후 이어지는 사용자 정보 조회 과정이 공격자가 완전히 통제하는 디렉터리 안의 설정 파일을 읽고, 그 설정이 가리키는 임의의 공유 라이브러리를 root 권한으로 로드해버리는 취약점이다. 로그인만 되어 있으면(sudoers에 아무 권한이 없어도) 로컬 사용자가 즉시 root shell을 얻을 수 있어 CVSS 9.3으로 평가됐다.

사전 지식

sudo -R / --chroot 옵션

sudo -R <디렉터리> <명령> 은 지정한 명령을 실행하기 전에, 그 프로세스가 보는 파일시스템의 "루트(/)"를 사용자가 지정한 디렉터리로 바꿔버린다. 예를 들어 sudo -R /home/user/fakeroot id 를 실행하면, 그 안에서 실행되는 id 명령 입장에서는 /home/user/fakeroot 가 곧 / 처럼 보인다. 이 기능은 원래 "격리된 환경에서 특정 도구를 실행하고 싶을 때"를 위한 편의 기능이었다.

Name Service Switch (NSS) 와 /etc/nsswitch.conf

리눅스에서 "이 사용자 이름(uid)이 실제로 누구인가"(passwd 조회), "이 그룹은 어떤 사용자들로 구성되는가"(group 조회) 같은 질문에 답하는 방식은 하나로 고정되어 있지 않다. /etc/nsswitch.conf 파일이 "이런 종류의 조회를 할 때 어떤 방법(백엔드)을 쓸지" 를 정의한다. 일반적인 리눅스 시스템은 아래처럼 되어 있다.

passwd: files systemd
group:  files systemd

여기서 files 는 "/etc/passwd 파일을 그대로 읽어라" 라는 뜻의 백엔드 이름이다. glibc 는 이 백엔드 이름을 받아서, libnss_<백엔드 이름>.so.2 라는 이름의 공유 라이브러리를 동적으로 로드해서 실제 조회를 위임한다. 즉 nsswitch.conf 에 어떤 이름을 적느냐가, glibc 가 어떤 .so 파일을 찾아서 로드할지를 결정한다.

공유 라이브러리의 "생성자(constructor)" 함수

ELF 공유 라이브러리(.so)는 __attribute__((constructor)) 로 표시된 함수를 가질 수 있다. 이런 함수는 라이브러리가 로드되는 순간, 그 라이브러리를 로드한 프로세스와 같은 권한으로 자동 실행된다 — 그 라이브러리의 원래 목적(NSS 조회 등)과 상관없이, "로드되기만 하면" 실행된다는 것이 핵심이다.

chroot()pivot_root()의 차이, 그리고 sudo 1.9.14의 변경

전통적인 chroot() 시스템 콜은 프로세스가 보는 루트 디렉터리만 바꾼다. sudo는 버전 1.9.14부터 --chroot 처리 방식을 pivot_root() 기반으로 바꿨는데(더 견고한 격리를 의도한 것으로 보인다), 그 결과 실제로 프로세스의 루트를 사용자 지정 디렉터리로 전환하는 시점이, sudo가 sudoers 정책을 검사하기 위해 필요한 사용자/그룹 정보 조회보다 앞당겨졌다.

취약점 분석

근본 원인: 정책 검사보다 먼저 일어난 루트 전환

sudo가 sudoers 정책을 평가하려면 "이 uid가 어떤 사용자인지", "어떤 그룹에 속하는지" 같은 정보가 필요하고, 이는 내부적으로 NSS(passwd/group 조회)를 거친다. 문제는 1.9.14의 pivot_root 방식에서는 이 조회가 일어나는 시점에 프로세스가 이미 사용자 지정 디렉터리로 chroot된 상태였다는 것이다. 즉 NSS가 참고하는 /etc/nsswitch.conf 가 sudo 실행자 자신이 완전히 통제하는 파일이 되어버린다.

정상적으로 기대되는 순서

  sudo 시작 (아직 root 디렉터리는 실제 /)
       │
       ▼
  sudoers 정책 검사
   ├─ 이 사용자가 sudo 를 쓸 자격이 있는가? (passwd/group 조회)
   │    └─ /etc/nsswitch.conf 는 실제 시스템 파일 (신뢰 가능)
       │
       ▼
  자격이 확인되면 그제서야 --chroot 적용, 명령 실행


취약한 순서 (sudo 1.9.14 ~ 1.9.17, pivot_root 방식)

  sudo 시작
       │
       ▼
  --chroot 대상 디렉터리로 pivot_root() 먼저 수행   ← 여기가 너무 이르다
       │
       ▼
  sudoers 정책 검사
   ├─ passwd/group 조회
   │    └─ /etc/nsswitch.conf 가 공격자 디렉터리의 파일로 뒤바뀜   ← 오염
       │
       ▼
  NSS 가 공격자 지정 백엔드 이름으로 libnss_<이름>.so.2 로드 시도
       │
       ▼
  공격자가 그 이름의 라이브러리를 미리 그 디렉터리 안에 심어둠
       │
       ▼
  라이브러리 로드 → constructor 함수가 root 권한으로 실행됨

공격이 성립하는 경로 (공개 PoC 기준)

공개된 PoC(sudo-chwoot.sh, 발견자 Rich Mirch 작성) 는 다음과 같이 동작한다.

  1. 임시 작업 디렉터리 안에 woot/etc/nsswitch.conf 를 만들고 그 내용을 passwd: /woot1337 로 채운다. 백엔드 이름에 슬래시(/)를 넣은 것이 핵심이다 — glibc 가 이 이름으로 라이브러리를 찾을 때 libnss_/woot1337.so.2 라는, 디렉터리 구성요소를 포함한 경로를 만들어내게 된다.
  2. woot/libnss_/woot1337.so.2 위치에, constructor 함수를 가진 공유 라이브러리를 미리 컴파일해 둔다. 이 함수는 setreuid(0,0)/setregid(0,0) 로 실제 uid/gid를 0(root)으로 바꾸고 셸을 실행한다.
  3. sudo -R woot woot 를 실행한다 — 두 번째 woot 는 존재하지 않는 명령이라 최종 실행 자체는 실패하지만, 그 전에 이미 정책 검사 단계에서 NSS 조회가 일어나고, 그 시점에 위 라이브러리가 로드되어 constructor 가 실행되므로 공격은 이미 성공한 뒤다.
  4. 결과적으로 sudoers 파일에 어떤 권한도 부여받지 않은 일반 사용자가 root 셸을 얻는다.

이 PoC가 인상적인 부분은, 최종적으로 실행하려던 명령(woot)이 사실 존재하지도 않는다는 점이다 — 공격은 "명령 실행" 단계가 아니라 그 이전의 "정책 검사를 위한 조회" 단계에서 이미 완료된다.

수정 방법

실제 수정 커밋(fffcc07c53, "Revert pivot_root and go back to prepending the new root directory")은 커밋 메시지에서 문제를 정확히 짚는다: "우리는 루트 디렉터리를 바꾼 이후에 passwd/group 조회를 할 수 없다." 수정은 pivot_root() 로 실제 프로세스의 루트를 통째로 바꿔버리는 방식을 버리고, 예전 방식인 경로 앞에 새 루트 경로를 붙이는(prepend) 방식으로 되돌렸다 — 즉 chroot 대상 안에서 명령을 실행할 파일 경로만 조정할 뿐, sudo 프로세스 자체가 정책 검사를 마치기 전에 실제로 chroot되는 일은 없다.

패치 후 순서

  sudo 시작 (root 디렉터리는 계속 실제 /)
       │
       ▼
  sudoers 정책 검사
   ├─ passwd/group 조회
   │    └─ /etc/nsswitch.conf 는 여전히 실제 시스템 파일   ← 오염 안 됨
       │
       ▼
  자격 확인 후, 명령을 실행할 때만 경로에 chroot 대상을 prepend
  (프로세스 자체의 루트를 바꾸는 실제 chroot/pivot_root는 이 시점 이후, 필요한 경우에만)

이와 함께 sudo 프로젝트는 --chroot 기능 자체를 deprecated(향후 완전히 제거 예정) 로 표시했다 — "심볼릭 링크가 있는 경로를 chroot 대상과 매칭할 때 완벽하게 처리되지 않는다" 는 한계를 커밋 메시지에서 스스로 인정하면서, 이 기능 자체의 위험성을 낮추는 방향(제거)을 택한 것이다. 이는 CVE-2025-32463과 함께 공개된 CVE-2025-32462(-h/--host 옵션 관련 별도 취약점)와 함께 sudo 1.9.17p1에서 수정됐다.

참고 자료

미해결/불확실 지점

  • sudo.ws 공식 어드바이저리 페이지는 이번 접근에서 403으로 막혀 원문을 직접 열람하지 못했다. 대신 공식 GitHub 릴리스 노트와 실제 fix 커밋 메시지(1차 자료)로 대체해 재구성했으므로 근거 자체는 확보됐지만, 발견자 본인의 서술 톤/추가 세부사항은 대조하지 못했다.
  • 1.9.14에서 왜 pivot_root 방식으로 바꿨는지(원래 의도했던 격리 개선의 구체적 내용)는 이번에는 다루지 않았다.