보안정보

전문화된 보안 관련 자료, 보안 트렌드를 엿볼 수 있는
차세대 통합보안관리 기업 이글루코퍼레이션 보안정보입니다.

Sudo 취약점 분석 및 대응방안 part.2

2021.06.02

13,405


 

 

 

 

01. 개요


Qualys 연구팀은 2021년 2월 3일에 sudo에서 발견된 권한상승 취약점 CVE-2021-3156에 대하여 발표하였다. 해당 취약점은 힙 오버플로우(Heap Overflow)를 기반으로 하며, exploit 성공 시 관리자 권한 획득이 가능하다. 

CVE-2021-3156 취약점의 exploit 코드는 c 와 python 2가지 언어의 버전으로 exploit-db 에 공개된 상태이며, exploit 코드가 공개 되기 전에 이미 sudo의 보안 패치가 배포되었다. 현재 해당 취약점을 발견한 Qualys 연구팀에서는 취약점 확인을 위한 도구를 홈페이지(https://qualys-secure.force.com/customer/s/article/000006518)에서 제공 중이다.

Part 1 에서는 권한 상승 취약점의 위험성과, [표 1]에 제시된 sudo의 취약점들을 분석한 후 해당 취약점들에 대한 대응방안을 제시하였다. 이번 Part 2 에서는 sudo에서 발견된 취약점 중 가장 최근에 발견된 CVE-2021-3156의 매커니즘을 소스코드 분석을 통해 상세하게 설명한다.

No

CVE

Description

1

CVE-2015-5602

sudoeit에 입력하는 파일 경로에 와일드카드 문자(*)를 사용하여 상위 권한의 파일을 수정할 수 있는 취약점

2

CVE-2016-7076

wordexp 함수에 특정 인자를 사용하는 응용 프로그램을 실행하여 noexec 제한 옵션이 존재하는 sudo를 우회하여 상위 권한을 획득하는 취약점

3

CVE-2017-1000367

SELinux 모듈이 활성화된 시스템에서 유효성 검증 미흡으로 제한된 권한의 sudoer가 완전한 root 권한을 취득할 수 있는 취약점

4

CVE-2019-14287

-u 옵션의 입력값 검증이 미흡한 취약점을 이용하여 명령어를 실행해 상위 권한을 획득하는 취약점

5

CVE-2019-18634

pwfeedback 옵션이 활성화된 sudo 프로세스에서 비밀번호 입력값에 오버 플로우를 일으켜 상위 권한을 취득할 수 있는 취약점

6

CVE-2021-3156

sudo에 백슬래시 문자에 대한 버퍼 오버플로우가 존재하여 이를 이용해 root 권한을 획득할 수 있는 취약점


[표 1] Part 1 에서 분석한 sudo 취약점의 CVE 번호 목록 (출처 : sudo 취약점 분석 및 대응방안 part.1) 


02. 취약점 분석

CVE-2021-3156 취약점이 존재하는 sudo의 소스코드에는 파라미터로 백슬래시() 문자열을 입력하여 힙 오버플로우 취약점을 발생시킬 수 있는 코드가 존재한다. 해당 코드에 접근하기 위해서는 sudo 실행 시 -e 혹은 –l, -s 2가지 옵션이 설정되어 있어야 하지만, sudo 내부에서 해당 옵션들이 동시에 설정될 수 없도록 구현되어 있기 때문에 일반적인 sudo 명령으로는 취약점 공격이 불가능하다.

그러나 sudo 를 “sudo” 명령어가 아닌 “sudoedit” 명령어로 실행 시 프로그램 내부에서 자동으로 –e 옵션이 적용되면서, “sudoedit –s” 명령 실행 시 “sudo –e –s” 옵션을 적용한 것과 동일한 실행이 가능하기 때문에 취약점이 존재하는 루틴에 접근이 가능하다.

이어서 진행할 03. sudo 소스코드 분석 챕터 에서는 [표 2]에 제시된 취약한 버전에 해당하는 sudo의 소스코드를 분석하여 sudo 취약점의 매커니즘과, 일반 sudo 명령어로 취약점 공격이 불가능한 원인, sudoedit 명령어를 활용한 우회방안에 대하여 설명한다.

구분

취약한 버전

위험도

CVE-2021-3156

sudo 1.8.2 ~ 1.8.31p2

High

sudo 1.9.0 ~ 1.9.5p1


[표 2] CVE-2021-3156 취약점에 노출된 sudo의 버전 정보


sudo에서는 명령 실행 시 전달한 옵션에 따라 플래그를 설정한다. 03. sudo 소스코드 분석 챕터에서 설명하는 플래그와 sudo 실행 시 사용되는 옵션의 매핑 정보는 아래와 같다.

플래그

MODE_SHELL

MODE_RUN

MODE_CHECK

MODE_EDIT

옵션

s

-

l

e


[표 3] Part 1 에서 분석한 sudo 취약점의 CVE 번호 목록 (출처 : sudo 취약점 분석 및 대응방안 part.1) 


sudo 명령 실행 후 취약점이 존재하는 루틴에 도착하기까지 2개의 조건식을 거치게 되며, 해당 조건식 들은 sudo 명령 실행 시 사용된 옵션(플래그) 설정 여부를 체크한다. 2개의 조건식( [그림4-1] section1 ~ 3 )을 모두 만족할 경우 힙 오버플로우 취약점이 존재하는 루틴에 최종 진입하게 된다.


[그림 1] sudo 명령 실행 후 취약점이 존재하는 루틴에 진입하는 과정 ​

 

 

03. sudo 소스코드 분석

 

[그림 2]는 sudo 1.8.31 버전의 소스코드 sudoers.c 파일 내 힙 오버플로우 취약점이 존재하는 set_cmnd() 함수의 내용이다. CVE-2021-3156의 공격 흐름도인 [그림4-1]에서 Section3에 해당하는 루틴으로 힙 오버플로우가 발생되는 상세한 과정은 다음과 같다.

 

Step1 : line 866의 백슬래시() 이스케이프를 해제하는 로직에 접근하게 될 때 from 포인터 변수가 가르키는 백슬래시()문자열 뒤에는 NULL 문자열이 위치하게 된다.

 

Step2 : line 867에서 이스케이프를 진행하기 위해 from 변수를 증감하여 백슬래시() 문자열 뒤에 존재하는 NULL 문자열을 가르키게 되고 line 868에서 from 변수가 한번 더 증감되면서 NULL 문자열 뒤의 임의의 값을 읽게 된다. 

 

Step3 : line 867과 line 868 로직에 의해 증감 연산을 총 두 번 진행하게 되어 NULL 문자열을 건너뛰게 됨으로써 라인 865의 while 문 조건식(from 변수가 NULL 값이 아닐 때까지 실행)을 무시하게 된다. 따라서 line 853에서 계산한 힙 메모리의 크기를 벗어나 임의의 값을 계속 입력할 수 있게 되어 힙 오버플로우 취약점이 발생하게 된다. 

 

  

[그림 2] set_cmnd() 함수 내 힙 오버플로우 취약점이 존재하는 루틴

 

 

[그림 3]의 소스코드는 [그림 5-1]의 Section2에 해당 하는 루틴이며, 해당 루틴들은 sudoers.c 파일 내 set_cmnd() 함수에 존재한다. 취약한 코드에 진입하기 위해서는 2개의 조건식을 만족해야 하는데, MODE_RUN(기본 실행 플래그), MODE_EDIT(-e), MODE_CHECK(-l) 플래그 중 1개의 플래그가 설정되어야 하며, MODE_SHELL(-s), MODE_LOGIN_SHELL 플래그가 설정되어야 한다.

 

 

  

[그림 3] 취약점이 존재하는 루틴에 진입하기 위한 조건들

 

 

그러나 sudo 명령으로는 [그림 3] 에서 체크하는 플래그(옵션)들을 동시에 설정할 수 없도록 되어있기 때문에 일반적인 sudo 명령을 활용한 취약점 공격은 불가능하다.

 

[그림 4]는 parge_args.c 파일 내 parse_args() 함수의 일부 내용으로, sudo 명령 실행 시 적용한 옵션에 따라 플래그를 설정하는 루틴이다. 취약점이 존재하는 루틴에 진입하기 위해 MODE_EDIT(-e) 혹은 MODE_CHECK(-l) 플래그와 MODE_SHELL(-s) 플래그를 동시에 적용하여 실행할 경우 line 532의 조건식에 의해 에러메시지가 출력되며 프로그램이 종료되게 된다.

 

  

[그림 4] –e, -l 옵션과 –s 옵션의 동시 적용을 방지하는 루틴 

 

 

MODE_RUN(기본 실행 플래그) 플래그와 MODE_SHELL(-s) 플래그가 동시에 설정되는 경우에도 parge_args.c 파일 내 parse_args() 함수의 line 571 조건식에 의해 line 588의 이스케이프 루틴에서 백슬래시() 문자열이 이스케이프 되면서, 취약점이 존재하는 백슬래시() 이스케이프 루틴으로의 진입이 불가능하다. 

 

 

  

[그림 5] MODE_RUN 플래그와 MODE_SHELL 플래그 적용 시 백슬래시() 문자열을 이스케이프 하는 루틴

 

 

그러나 sudo의 심볼릭 링크 파일인 sudoedit 명령어로 sudo를 실행시킬 경우 기본으로 MODE_SHELL(-s) 플래그와 MODE_EDIT(-e) 플래그가 설정되므로, [그림 3] 의 조건을 만족하여 취약점이 존재하는 루틴으로 진입할 수 있다. 따라서 sudo 명령어 대신 sudoedit 명령어로 “sudoedit –s ‘’ '임의의 문자열’“ 과 같은 페이로드를 활용한 힙 오버플로우 취약점 공격이 가능하게 된다.

 

 

  

[그림 6] sudoedit 명령어로 sudo 실행 시 설정되는 플래그 ​ 

 

 

04. PoC 분석 및 공격 시연

1) PoC 매커니즘 분석 

현재 CVE-2021-3156의 exploit 코드는 Qualys 연구팀의 Baron Samedit 과 Stephen Tong이 공개한 c 와 python 으로 제작한 2개의 코드가 exploit-db 에 공개되어 있으며, 2개의 코드는 개발에 사용된 언어만 다르고 exploit 과정은 동일하다.

exploit-db에 공개된 CVE-2021-3156의 exploit 코드 “Sudo 1.9.5p1 – 'Baron Samedit ' Heap-Based Buffer Overflow Privilege Escalation (1)”(https://www.exploit-db.com/exploits/49521) 에서는 취약점 공격을 위해 힙 오버플로우 취약점 이외에도 timestamp.c 파일 timestamp_lock() 함수에 존재하는 레이스 컨디션(Race Condition) 취약점을 함께 활용한다. ​

​ 

exploit 코드에서는 -source 옵션으로 대상 일반유저의 uid 와 gid의 값을 0 으로 수정한 passwd 파일을 파라미터로 전달받으며, 해당 passwd 파일의 내용을 / etc /passwd 파일에 덮어써서 최종적으로 root권한을 획득하게 된다.

 

 

  

[그림 7] 조작된 passwd 파일이 공격에 활용되는 과정

 

 

exploit 코드 내에서 공격을 위한 절차는 아래와 같이 진행된다.

 

Step1 : –source 옵션으로 조작된 passwd 파일을 받은 후 해당 파일의 내용을 환경변수에 저장한다. 

 

Step2 : 레이스 컨디션 공격에 활용될 디렉터리를 생성 후 해당 디렉터리의 심볼릭 링크를 생성한다.

 

Step3 : –A –s 옵션과 백슬래시() 문자열 뒤에 힙 메모리 인덱스를 맞추기 위한 문자열들을 파라미터로 설정 후 sudoedit을 실행한다. 이때 환경변수에 저장된 조작된 passwd 파일의 내용은 sudo의 스택 메모리에 들어가게 된다.

 

위와 같은 과정은 레이스 컨디션 공격에 성공할 때까지 최대 5000번 반복 실행되게 된다.

 

  

[그림 8] 조작된 exploit-db 에 공개된 CVE-2021-3156의 exploit 코드 

 

 

exploit 코드 실행 시 실제로 sudoedit 에 전달되는 페이로드는 아래와 같다.

 

  

[그림 9] exploit 코드 실행 시 sudoedit 에 전달되는 페이로드

 

 

레이스 컨디션 공격 진행 시 아래와 같이 무작위로 작업 디렉터리가 생성된다.

 

  

[그림 10] exploit 코드 실행 시 무작위로 생성되는 디렉터리

 

 

레이스 컨디션 공격 성공 시 timestamp.c 파일 timestamp_lock() 함수 내 라인 657에 의해 –source 옵션으로 전달받아 스택에 저장되어있는 passwd 파일의 내용이 / etc /passwd 파일에 덮어 쓰여지게 되면서 공격에 성공하게 된다.

 

  

[그림 11] sudo의 스택 메모리 영역에 저장된 조작된 passwd 파일​ 

 

  

[그림 12] 조작된 passwd 파일을 / etc /passwd 파일에 덮어쓰는 루틴

 

 

2) 공격 시연

 

공격 시연 환경은 exploit 코드 개발자가 테스트 한 OS 의 버전과 sudo 버전을 동일하게 구성하여 진행하였다.

 

구분

버전

sudo

1.8.31

OS

Ubuntu 20.04.1

 

[표 4] PoC 시연 시 사용한 sudo 의 버전과 OS 의 종류 및 버전  

 

 

 

root 권한을 획득할 대상 일반유저의 uid 값을 확인한다. 현재 1000으로 설정되어 있는 것이 확인된다.

 

 

  

[그림 13] 대상 일반유저의 uid 값

 

 

/ etc /passwd 파일을 fake_passwd 라는 이름으로 복사한 후, fake_passwd 파일 내에서 test 유저의 uid와 gid를 모두 0 으로 수정한다.

 

 

  

[그림 14] 파라미터로 전달할 조작된 passwd 파일

 

  

 

[그림 15] 대상 유저의 uid, gid 를 0 으로 조작한 passwd 파일의 내용

 

 

https://www.exploit-db.com/exploits/49521 에서 CVE-2021-3156 python exploit code를 다운로드 받은 후 [그림 15] 에서 수정한 fake_passwd 파일을 –source 옵션으로 전달하여 python 3.X 대 버전으로 실행시킨다. 

 

 

“success at iteration …” 메시지 발생 후 기존 test 유저로 다시 로그인 한다. 유저이름과 uid 가 각각 root 와 0 으로 변경된 것이 확인된다.

 

 

  

[그림 17] exploit 성공 시 발생하는 메시지 

 

 

  

 

[그림 18] exploit 성공 후 uid 가 0 으로 변경되면서 root 권한이 획득된 화면

 

 

/ etc /passwd 파일에서 test 유저의 uid가 0으로 변경된 것이 확인된다.

 

 

  

[그림 19] 조작된 passwd 파일의 내용으로 변경된 / etc /passwd 파일의 내용

 

 

05. 대응방안

 

1) systemtap 스크립트 활용

 

systemtap 스크립트를 활용하여 sudoedit 명령어의 실행을 차단할 수 있다. 해당 스크립트를 실행하면 sudoedit 명령은 사용 불가능하게 되고, 기존 sudoedit의 기능은 sudo –e 명령어로 대체가 가능하다. 단, 시스템 재부팅 시 스크립트를 다시 실행해야 하는 번거로움이 존재한다.

 

Step1 : 필요한 systemtap 패키지 및 종속성을 설치한다.

 

 

  

[그림 20] systemtap 패키지 및 종속성 설치

 

 

RedHat7 혹은 RetHat6,8 에서는 debuginfo 패키지를 추가로 설치해야 한다.

 

 

  

[그림 21] Redhat 7 계열에서의 debuginfo 패키지 설치

 

 

  

 

[그림 22] Redhat 6, 8 계열에서의 debuginfo 패키지 설치

 

 

Step2 : 파일명을 sudoedit-block.stap 로 지정하여 systemtap 스크립트를 제작한다. 

 

 

 

[그림 23] sudoedit-block.stap  파일 내 systemtap 스크립트 내용

 

 

Step3 : 제작한 systemtap 스크립트 백그라운드로 실행시킨다. 

 

 

  

 

[그림 24] sudoedit-block.stap 스크립트를 백그라운드로 실행

 

 

systemtap 스크립트가 백그라운드로 동작하는 동안 sudoedit 명령어가 작동하지 않는 것을 확인할 수 있다.

 

 

  

 

[그림 25] sudoedit 실행 시 차단되는 화면

 

 

2) 보안 업데이트

 

취약한 버전의 sudo 사용 시 취약점이 해결된 최신 버전으로의 업데이트가 필요하다.

 

No

취약한 버전

보안 패치 버전

 패치일자

1

1.8.2 ~1.8.31p2

1.8.32

2021-02-09

2

1.9.0 ~ 1.9.5p1

1.9.5p2

2021-01-26

 

[표 5] 취약점이 패치된 sudo 의 버전 정보 

 

 

 

현재 sudo의 버전은 “sudo –V” 명령어로 확인이 가능하다.

 

 

 

[그림 26] sudo 버전 확인

 

 

“sudoedit –s '' `perl –e 'print "A" x 65536'`” 페이로드로 현재 사용중인 sudo의 취약점 존재 여부 확인이 가능하다. 취약점이 존재하는 sudo 일 경우 해당 명령 실행 시 에러가 발생한다.

 

 

  

[그림 27] 사용중인 sudo에 취약점 존재 시  발생하는 메시지

 

 

취약점이 패치 된 sudo 일 경우 “usage:” 로 시작하는 메시지가 발생한다.

 

 

  

[그림 28] 사용중인 sudo에 취약점 존재하지 않을 시  발생하는 메시지

 

 

[그림 29]는 취약점이 패치 된 sudo 1.8.32 의 소스코드 sudoers.c 파일 내 set_cmnd() 함수의 내용이다. 기존 취약점이 존재하는 루틴에 힙 메모리 할당 시 계산한 사이즈와 파라미터로 전달 된 문자열의 사이즈를 계산하여 힙 오버플로우 공격을 방지하는 로직이 추가되었다.

 

 

  

[그림 29] 힙 오버플로우 공격 방어를 위해 추가된 로직

 

 

06. 참고자료

 

[1] CVE-2021-3156: Heap-Based Buffer Overflow in Sudo (Baron Samedit)

https://blog.qualys.com/vulnerabilities-research/2021/01/26/cve-2021-3156-heap-based-buffer-overflow-in-sudo-baron-samedit 

[2] Sudo 1.9.5p1 - 'Baron Samedit ' Heap-Based Buffer Overflow Privilege Escalation (1)

https://www.exploit-db.com/exploits/49521

[3] Privilege escalation via command line argument parsing - sudo - (CVE-2021-3156)

https://access.redhat.com/security/vulnerabilities/RHSB-2021-002

[4] Dashboard Toolbox - VMDR DASHBOARD: Baron Samedit | Heap-based buffer overflow Sudo

https://qualys-secure.force.com/customer/s/article/000006518