Skip to content
KitploitKITPLOIT
도구익스플로잇블로그
Log in
제출
도구익스플로잇블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2021-3156-Heap-Based-Buffer-Overflow-in-Sudo-Baron-Samedit- — Sudo의 힙 기반 버퍼 오버플로(CVE-2021-3156)에 대한 기술 분석 및 악용 개발로, 주요 Linux 배포판에서 로컬 권한 상승을 위한 세 가지 작동 악용을 포함합니다. | Kitploit
도구/GitHubGitHub/sornphut/cve-2021-3156-heap-based-buffer-overflow-in-sudo-baron-samedit-
Privilege EscalationVulnerability AnalysisExploitationPenetration TestingPapers & ResearchLearning & EducationBinary Exploitation
GitHubsornphut/cve-2021-3156-heap-based-buffer-overflow-in-sudo-baron-samedit-

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

CVE-2021-3156-Heap-Based-Buffer-Overflow-in-Sudo-Baron-Samedit-

Sudo의 힙 기반 버퍼 오버플로(CVE-2021-3156)에 대한 기술 분석 및 악용 개발로, 주요 Linux 배포판에서 로컬 권한 상승을 위한 세 가지 작동 악용을 포함합니다.

저장소 보기
131년 전아직 검토되지 않음

Qualys Security Advisory

Baron Samedit: Sudo의 힙 기반 버퍼 오버플로 (CVE-2021-3156)

======================================================================== 목차

요약 분석 익스플로잇 감사의 말 타임라인

======================================================================== 요약

Sudo(https://www.sudo.ws/)에서 힙 기반 버퍼 오버플로를 발견했습니다. 이 취약점:

  • 모든 로컬 사용자(일반 사용자 및 시스템 사용자, sudoers 및 비sudoers 모두)가 인증 없이(즉, 공격자는 사용자 비밀번호를 알 필요 없음) 악용할 수 있습니다.

  • 2011년 7월(커밋 8255ed69)에 도입되었으며, 기본 구성에서 1.8.2부터 1.8.31p2까지의 모든 레거시 버전과 1.9.0부터 1.9.5p1까지의 모든 안정 버전에 영향을 미칩니다.

  • 이 취약점에 대해 세 가지 다른 익스플로잇을 개발하여 Ubuntu 20.04(Sudo 1.8.31), Debian 10(Sudo 1.8.27), Fedora 33(Sudo 1.9.2)에서 전체 루트 권한을 획득했습니다. 다른 운영 체제 및 배포판도 악용 가능할 가능성이 높습니다.

======================================================================== 분석

Sudo가 "shell" 모드(shell -c command)로 명령을 실행하기 위해 실행되는 경우:

  • MODE_SHELL 플래그를 설정하는 -s 옵션을 통해;
  • 또는 MODE_SHELL 및 MODE_LOGIN_SHELL 플래그를 설정하는 -i 옵션을 통해;

그런 다음 Sudo의 main() 시작 시 parse_args()는 모든 명령줄 인수를 연결하고(587-595행) 모든 메타 문자를 백슬래시로 이스케이프하여(590-591행) argv를 다시 작성합니다(609-617행):


571 if (ISSET(mode, MODE_RUN) && ISSET(flags, MODE_SHELL)) { 572 char **av, *cmnd = NULL; 573 int ac = 1; ... 581 cmnd = dst = reallocarray(NULL, cmnd_size, 2); ... 587 for (av = argv; *av != NULL; av++) { 588 for (src = *av; src != '\0'; src++) { 589 / quote potential meta characters */ 590 if (!isalnum((unsigned char)*src) && *src != '_' && *src != '-' && *src != '$') 591 *dst++ = '\'; 592 *dst++ = *src; 593 } 594 dst++ = ' '; 595 } ... 600 ac += 2; / -c cmnd */ ... 603 av = reallocarray(NULL, ac + 1, sizeof(char *)); ... 609 av[0] = (char )user_details.shell; / plugin may override shell */ 610 if (cmnd != NULL) { 611 av[1] = "-c"; 612 av[2] = cmnd; 613 } 614 av[ac] = NULL; 615 616 argv = av; 617 argc = ac; 618 }

나중에 sudoers_policy_main()에서 set_cmnd()는 명령줄 인수를 힙 기반 버퍼 "user_args"에 연결하고(864-871행) 메타 문자를 이스케이프 해제합니다(866-867행). "sudoers 매칭 및 로깅 목적":


819 if (sudo_mode & (MODE_RUN | MODE_EDIT | MODE_CHECK)) { ... 852 for (size = 0, av = NewArgv + 1; *av; av++) 853 size += strlen(*av) + 1; 854 if (size == 0 || (user_args = malloc(size)) == NULL) { ... 857 } 858 if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL)) { ... 864 for (to = user_args, av = NewArgv + 1; (from = *av); av++) { 865 while (*from) { 866 if (from[0] == '\' && !isspace((unsigned char)from[1])) 867 from++; 868 *to++ = *from++; 869 } 870 *to++ = ' '; 871 } ... 884 } ... 886 }

불행히도 명령줄 인수가 단일 백슬래시 문자로 끝나는 경우:

  • 866행에서 "from[0]"은 백슬래시 문자이고 "from[1]"은 인수의 널 종결자입니다(즉, 공백 문자가 아님).

  • 867행에서 "from"이 증가되고 널 종결자를 가리킵니다.

  • 868행에서 널 종결자가 "user_args" 버퍼로 복사되고 "from"이 다시 증가되어 널 종결자 다음 첫 번째 문자를 가리킵니다(즉, 인수의 범위를 벗어남).

  • 865-869행의 "while" 루프는 범위를 벗어난 문자를 읽고 "user_args" 버퍼로 복사합니다.

즉, set_cmnd()는 힙 기반 버퍼 오버플로에 취약합니다. "user_args" 버퍼로 복사되는 범위 밖의 문자들이 해당 버퍼의 크기(852-853행에서 계산됨)에 포함되지 않았기 때문입니다.

그러나 이론적으로는 어떤 명령줄 인수도 단일 백슬래시 문자로 끝날 수 없습니다. MODE_SHELL 또는 MODE_LOGIN_SHELL이 설정된 경우(858행, 취약한 코드에 도달하기 위한 필수 조건) MODE_SHELL이 설정되고(571행) parse_args()가 이미 모든 메타 문자(백슬래시 포함)를 이스케이프했기 때문입니다(즉, 모든 단일 백슬래시를 두 번째 백슬래시로 이스케이프).

그러나 실제로 set_cmnd()의 취약한 코드와 parse_args()의 이스케이프 코드는 약간 다른 조건으로 둘러싸여 있습니다:


819 if (sudo_mode & (MODE_RUN | MODE_EDIT | MODE_CHECK)) { ... 858 if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL)) {

대비:


571 if (ISSET(mode, MODE_RUN) && ISSET(flags, MODE_SHELL)) {

따라서 질문은 다음과 같습니다. MODE_SHELL을 설정하고 MODE_EDIT 또는 MODE_CHECK를 설정하여(취약한 코드에 도달하기 위해) 기본 MODE_RUN을 설정하지 않음으로써(이스케이프 코드를 피하기 위해) 가능할까요?

대답은 아니오인 것 같습니다. MODE_EDIT(-e 옵션, 361행) 또는 MODE_CHECK(-l 옵션, 423 및 519행)를 설정하면 parse_args()가 "valid_flags"에서 MODE_SHELL을 제거하고(363 및 424행) MODE_SHELL과 같은 잘못된 플래그를 지정하면 오류와 함께 종료됩니다(532-533행):


358 case 'e': ... 361 mode = MODE_EDIT; 362 sudo_settings[ARG_SUDOEDIT].value = "true"; 363 valid_flags = MODE_NONINTERACTIVE; 364 break; ... 416 case 'l': ... 423 mode = MODE_LIST; 424 valid_flags = MODE_NONINTERACTIVE|MODE_LONG_LIST; 425 break; ... 518 if (argc > 0 && mode == MODE_LIST) 519 mode = MODE_CHECK; ... 532 if ((flags & valid_flags) != flags) 533 usage(1);

하지만 허점을 찾았습니다. "sudo" 대신 "sudoedit"으로 Sudo를 실행하면 parse_args()가 자동으로 MODE_EDIT을 설정하지만(270행) "valid_flags"를 재설정하지 않으며, "valid_flags"에는 기본적으로 MODE_SHELL이 포함됩니다(127 및 249행):


127 #define DEFAULT_VALID_FLAGS (MODE_BACKGROUND|MODE_PRESERVE_ENV|MODE_RESET_HOME|MODE_LOGIN_SHELL|MODE_NONINTERACTIVE|MODE_SHELL) ... 249 int valid_flags = DEFAULT_VALID_FLAGS; ... 267 proglen = strlen(progname); 268 if (proglen > 4 && strcmp(progname + proglen - 4, "edit") == 0) { 269 progname = "sudoedit"; 270 mode = MODE_EDIT; 271 sudo_settings[ARG_SUDOEDIT].value = "true"; 272 }

결과적으로 "sudoedit -s"를 실행하면 MODE_EDIT 및 MODE_SHELL(둘 다 설정되지만 MODE_RUN은 아님)을 설정하여 이스케이프 코드를 피하고 취약한 코드에 도달하며 단일 백슬래시 문자로 끝나는 명령줄 인수를 통해 힙 기반 버퍼 "user_args"를 오버플로시킬 수 있습니다:


sudoedit -s '' perl -e 'print "A" x 65536' malloc(): corrupted top size Aborted (core dumped)

공격자 관점에서 이 버퍼 오버플로는 이상적입니다:

  • 오버플로하는 "user_args" 버퍼의 크기를 제어할 수 있습니다(연결된 명령줄 인수의 크기, 852-854행).

  • 오버플로 자체의 크기와 내용을 독립적으로 제어할 수 있습니다(마지막 명령줄 인수 뒤에는 크기 계산(852-853행)에 포함되지 않은 첫 번째 환경 변수들이 편리하게 이어집니다).

  • 오버플로하는 버퍼에 널 바이트를 쓸 수도 있습니다(단일 백슬래시로 끝나는 모든 명령줄 인수 또는 환경 변수는 "user_args"에 널 바이트를 씁니다, 866-868행).

예를 들어 amd64 Linux에서 다음 명령은 24바이트 "user_args" 버퍼(32바이트 힙 청크)를 할당하고 다음 청크의 크기 필드를 "A=a\0B=b\0"(0x00623d4200613d41), fd 필드를 "C=c\0D=d\0"(0x00643d4400633d43), bk 필드를 "E=e\0F=f\0"(0x00663d4600653d45)로 덮어씁니다:


env -i 'AA=a' 'B=b' 'C=c' 'D=d' 'E=e' 'F=f' sudoedit -s '1234567890123456789012'

--|--------+--------+--------+--------|--------+--------+--------+--------+-- | | |12345678|90123456|789012.A|A=a.B=b.|C=c.D=d.|E=e.F=f.| --|--------+--------+--------+--------|--------+--------+--------+--------+-- size <---- user_args buffer ----> size fd bk

도구 다운로드