
CVE-2021-3156 (Baron Samedit) Report and Research
Author: IJ Baig
Date: 2026년 7월 7일
1.8.21.8.31p2, 안정 버전 1.9.01.9.5p1.1.9.5p1이 취약점을 안전하게 분석하기 위해, 취약한 Sudo 버전을 격리된 비운영 환경에서 컴파일했습니다.

Sudo 1.9.5p1의 소스 코드를 다운로드하여 표준 make 유틸리티를 사용해 로컬에서 컴파일했습니다. 호스트 시스템에 기본으로 설치된 패치된 sudo 바이너리를 덮어쓰지 않도록 로컬 디렉터리에서 실행하는 데 주의를 기울였습니다.

빌드 확인: 컴파일 후, 올바른 취약 버전이 빌드되었는지 확인하기 위해 커스텀 바이너리를 실행했습니다.


plugins/sudoers/sudoers.cset_cmnd() (버전 1.9.5p1의 약 864행)
새로 할당된 저장 공간(힙 버퍼)에 단어 목록을 넣기 전에 단어 목록에서 이스케이프 문자(백슬래시)를 제거하는 일을 하는 도우미가 있다고 상상해 보세요. 이 도우미는 모든 백슬래시 뒤에 항상 유효한 문자가 따른다고 맹목적으로 가정하므로, 백슬래시를 볼 때마다 이를 건너뛰고 다음 문자를 복사합니다.
하지만 sudoedit -s 실행 시 프로그램이 인자를 처리하는 방식에 결함이 있습니다. 사용자가 정확히 단일 백슬래시(\)로 끝나는 단어를 몰래 끼워 넣을 수 있는데, 그 뒤에는 보이지 않는 단어 끝 표시(널 종결자, \0)가 바로 이어집니다.
도우미의 코드가 이 끝의 백슬래시에 도달하면 이를 건너뛰고 다음 문자인 널 종결자를 확인합니다. if 문의 로직은 멈추는 대신 도우미가 널 종결자도 건너뛰도록 강제합니다. 루프는 계속 진행되어 그다음에 오는 임의의 경계를 벗어난 메모리를 저장 공간에 복사합니다. 의도된 단어 길이를 넘어선 이 연속적인 복사는 지정된 버퍼를 오버플로우시켜 심각한 힙 기반 버퍼 오버플로우를 초래합니다.
취약 코드 스니펫:
/* Unescape characters, skipping over backslashes */
for (to = user_args, av = NewArgv + 1; (from = *av); av++) {
while (*from) {
// VULNERABILITY: If from[0] is '\' and from[1] is '\0',
// the loop evaluates to true, increments 'from', skipping the null terminator.
if (from[0] == '\\' && !isspace((unsigned char)from[1]))
from++;
*to++ = *from++;
}
*to++ = ' ';
}
*--to = '\0';
Sudo 개발자들은 버전 1.9.5p2에서 엄격한 경계 검사를 추가하여 이 논리 오류를 수정했습니다. 이제 코드는 이스케이프 해제를 시도하기 전에 백슬래시 뒤의 문자가 널 종결자가 아닌지 명시적으로 확인합니다.
패치 Diff:
- if (from[0] == '\\' && !isspace((unsigned char)from[1]))
+ if (from[0] == '\\' && from[1] != '\0' && !isspace((unsigned char)from[1]))
이것이 근본 원인을 수정하는 이유:
from[1] != '\0' 조건이 추가되면서 경계를 벗어난 읽기가 즉시 중지됩니다. 이제 코드가 문자열의 맨 끝에서 끝자락 백슬래시(from[1]이 널 종결자인 경우)를 만나면 if 문이 false로 평가됩니다. 포인터가 조기에 증가하지 않으며, 널 종결자가 문자열의 끝으로 올바르게 처리되고, 힙을 오버플로우하지 않고 루프가 안전하게 종료됩니다.
이 재현을 위해 보안 연구원 Worawit이 개발한 널리 알려진 Python 익스플로잇(구체적으로 exploit_nss.py 변종)을 사용했습니다.
PoC를 실행하기 전에 그 작동 방식을 이해하는 것이 중요합니다. 이 스크립트는 단순히 프로그램을 충돌시키는 것이 아니라 코드 실행을 위해 고도로 정밀한 메모리 조작을 수행합니다.
PoC의 동작을 단계별로 분석하면 다음과 같습니다:
.so)로 동적으로 컴파일합니다. 이 페이로드는 루트 권한으로 /bin/sh를 실행하도록 설계되었습니다.LC_ALL, LANG, TZ)를 설정합니다. Sudo는 시작 시 환경 변수를 힙에 로드하므로, 스크립트는 힙을 예측 가능한 레이아웃으로 배열하는 데 필요한 정확한 크기를 계산합니다.sudoedit -s를 실행하고 단일 백슬래시로 끝나는 명령줄 인자를 전달합니다. 이는 2장에서 논의한 off-by-one 취약점을 트리거하여 경계를 벗어난 쓰기를 유발합니다.service_user 구조체를 정밀하게 덮어씁니다. 이 구조체는 NSS(Name Service Switch)가 시스템 정보를 조회하는 데 사용합니다.service_user 구조체가 손상되어 1단계에서 컴파일한 악성 .so 라이브러리를 가리키게 됩니다. Sudo가 사용자 권한을 조회하려고 할 때 공격자의 라이브러리를 맹목적으로 로드 및 실행하여 루트 셸을 획득합니다.먼저, 무기화 없이 취약점이 존재함을 증명하기 위해 기본적인 크래시 테스트를 수행했습니다.

다음으로, 취약한 바이너리를 대상으로 Worawit의 전체 exploit_nss.py 스크립트를 실행했습니다.

공식 수정 사항을 검증하기 위해, 패치된 Sudo 바이너리를 대상으로 동일한 PoC 트리거를 실행했습니다.
sudoedit -s '\' 2>&1 | grep -q "sudoedit:" && echo "Vulnerable" || echo "Not vulnerable"

서버 전반에서 사용되는 표준 관리 프로그램인 Sudo에는 백슬래시가 포함된 텍스트 입력을 처리하는 방식에 치명적인 결함이 있습니다. 기본 사용자 권한만 가진 공격자가 변조된 명령을 신중하게 전송하여 시스템이 지정된 메모리 영역 밖에 데이터를 쓰도록 속일 수 있습니다. 이 결함으로 인해 공격자는 보안 통제를 완전히 우회하고 비밀번호 없이 시스템에 대한 완전한 무단 관리 권한을 획득할 수 있습니다.
과제: 주요 과제 중 하나는 힙 조작의 취약성(불안정성)이었습니다. 특정 OS 버전을 대상으로 한 익스플로잇 페이로드는 기본 표준 C 라이브러리(glibc)가 메모리 청크를 다르게 관리하기 때문에 다른 OS에서는 종종 실패합니다. 이 취약점을 성공적으로 무기화하려면 대상 환경에 특화된 메모리 정렬 및 환경 변수 레이아웃(Heap Feng Shui)에 대한 정확한 이해가 필요했습니다.
교훈: 방어 및 보안 운영 관점에서 이 심층 분석은 몇 가지 중요한 개념을 다시 한번 확인시켜 주었습니다:
sudoedit -s 명령에 대한 프로세스 실행 텔레메트리를 모니터링하면 SOC 팀이 패치가 인프라 전반에 완전히 배포되기 전에 익스플로잇 시도를 탐지할 수 있습니다.유사 CVE: CVE-2019-14287 (Sudo 보안 우회)
동일한 Sudo 코드베이스 내의 또 다른 주요 취약점도 유사한 근본 원인 패턴을 공유합니다: 사용자 입력의 부적절한 파싱 및 검증입니다. CVE-2019-14287에서는 Sudo가 사용자 ID(UID)를 파싱하는 방식의 논리적 결함으로 인해 공격자가 사용자 ID -1 또는 4294967295를 지정하여 루트 권한으로 명령을 실행할 수 있었습니다.
유사점: Baron Samedit(CVE-2021-3156)은 메모리 손상 결함이고 CVE-2019-14287은 권한 우회이지만, 두 경우 모두 근본 원인은 초기 인자 파싱 논리의 실패입니다. 두 취약점 모두 핵심 권한 함수를 실행하기 전에 Sudo가 경계 케이스 명령줄 인자(끝자락 백슬래시 vs. 예상치 못한 정수 래핑)를 잘못 신뢰하고 잘못 처리한 데서 비롯되었습니다.
안전 및 윤리 선언: 이 보고서에 제시된 모든 익스플로잇 및 테스트는 격리되고 승인된 로컬 가상 머신 내에서만 수행되었습니다. 이 실습 중 어떠한 운영 시스템이나 무단 네트워크도 대상으로 하거나 접촉하지 않았습니다.