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

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

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

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

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2018-6789 — Exim의 base64 디코딩에서 발생하는 힙 버퍼 오버플로우인 CVE-2018-6789용 익스플로잇으로, 청크 오버랩과 ACL 문자열 조작을 통해 원격 코드 실행을 달성합니다. | Kitploit
도구/GitHubGitHub/beraphin/cve-2018-6789
Vulnerability AnalysisExploitationCTFLearning & EducationBinary ExploitationLabs & Practice
GitHubberaphin/cve-2018-6789

CVE-2018-6789

Exim의 base64 디코딩에서 발생하는 힙 버퍼 오버플로우인 CVE-2018-6789용 익스플로잇으로, 청크 오버랩과 ACL 문자열 조작을 통해 원격 코드 실행을 달성합니다.

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

인기

모두 보기 →

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

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

CVE-2018-6789

환경 구축

의존성 설치

apt-get install gcc net-tools vim gdb python wget git make procps libpcre3-dev libdb-dev libxt-dev libxaw7-dev

이전 버전의 exim 다운로드

wget ftp://mirror.easyname.at/exim-ftp/exim/exim4/old/exim-4.89.tar.gz
tar -xvzf ./exim-4.89.tar.gz
cd ./exim-4.89
cp src/EDITME Local/Makefile
cp exim_monitor/EDITME Local/eximon.conf

그런 다음 Local/Makefile 수정 편의상 각 폴더는 현재 디렉토리를 가리키도록 함

BIN_DIRECTORY=/home/zzx/EVA/cve-2018-6789/exim-4.89/bin
CONFIGURE_FILE=/home/zzx/EVA/cve-2018-6789/exim-4.89/configure
SPOOL_DIRECTORY=/home/zzx/EVA/cve-2018-6789/exim-4.89/exim
EXIM_USER=zzx
AUTH_PLAINTEXT=yes
AUTH_CRAM_MD5=yes
AUTH_TLS=yes

이렇게 하면 디버깅이 편리함 그런 다음 컴파일 및 설치

make install

./configure 수정, 아래 내용으로 덮어쓰기

acl_smtp_mail=acl_check_mail
acl_smtp_data=acl_check_data
begin acl
acl_check_mail:
  .ifdef CHECK_MAIL_HELO_ISSUED
  deny
    message = no HELO given before MAIL command
    condition = ${if def:sender_helo_name {no}{yes}}
  .endif

  accept

acl_check_data:
  accept

begin authenticators
fixed_cram:
  driver = cram_md5
  public_name = CRAM-MD5
  server_secret = ${if eq{$auth1}{ph10}{secret}fail}
  server_set_id = $auth1

실행

./bin/exim -bd -d-receive

취약점 분석

먼저 base64.c에 있는 패치를 분석 1 여기서 result는 base64 디코딩 결과가 저장되는 버퍼로, store_get 함수로 획득함 패치 이전의 size 계산에 문제가 있음을 확인할 수 있음. size가 4n ~ 4n+3 범위에 있을 때 계산된 size의 길이는 동일하지만, b64decode는 4의 배수가 아닌 인자를 디코딩할 때 한두 바이트를 더 디코딩함

예를 들어 직접 전송

auth_md5('Hf'*42)

size=0x40
결과 메모리 분포:

pwndbg> hexdump 0x711d60 0x50
+0000 0x711d60  1d f1 df 1d  f1 df 1d f1  df 1d f1 df  1d f1 df 1d  │....│....│....│....│
+0010 0x711d70  f1 df 1d f1  df 1d f1 df  1d f1 df 1d  f1 df 1d f1  │....│....│....│....│
+0020 0x711d80  df 1d f1 df  1d f1 df 1d  f1 df 1d f1  df 1d f1 df  │....│....│....│....│
+0030 0x711d90  1d f1 df 1d  f1 df 1d f1  df 1d f1 df  1d f1 df 00  │....│....│....│....│
+0040 0x711da0  20 61 61 61  61 61 61 61  61 61 61 61  61 61 61 61  │.aaa│aaaa│aaaa│aaaa│

다시 시도

auth_md5('Hf'*42+'HfH')

size=0x40

pwndbg> hexdump 0x711d60 0x50
+0000 0x711d60  1d f1 df 1d  f1 df 1d f1  df 1d f1 df  1d f1 df 1d  │....│....│....│....│
+0010 0x711d70  f1 df 1d f1  df 1d f1 df  1d f1 df 1d  f1 df 1d f1  │....│....│....│....│
+0020 0x711d80  df 1d f1 df  1d f1 df 1d  f1 df 1d f1  df 1d f1 df  │....│....│....│....│
+0030 0x711d90  1d f1 df 1d  f1 df 1d f1  df 1d f1 df  1d f1 df 1d  │....│....│....│....│
+0040 0x711da0  f1 61 61 61  61 61 61 61  61 61 61 61  61 61 61 61  │.aaa│aaaa│aaaa│aaaa│

두 바이트 오버플로우 발생

Exim 메모리 관리 메커니즘

Exim은 성능 향상을 위해 기존 힙 관리 메커니즘 위에 자체 메모리 관리 메커니즘을 구현함. 이는 코드와 glibc 사이의 중간 버퍼 역할을 하며, malloc과 free의 횟수를 줄이는 것이 목적 2 Exim에서 개별 힙 블록을 storeblock이라고 함. 사용 시 그 안에서 적절한 크기의 버퍼를 분할하여 사용하며, storeblock이 모두 사용되면 새로운 storeblock을 malloc함. 각 storeblock의 구조는 단순한 단일 연결 리스트임:

/* Structure describing the beginning of each big block. */
typedef struct storeblock {
  struct storeblock *next;
  size_t length;
} storeblock;

프로그램이 힙을 사용할 때 주로 사용하는 API는 store.c에 있음:

store_get
store_release
store_extend
store_reset

store_get은 버퍼를 획득하는 데 사용되며, 핵심 코드는 다음과 같음:

128 void *
129 store_get_3(int size, const char *filename, int linenumber)
....
145   int length = (size <= STORE_BLOCK_SIZE)? STORE_BLOCK_SIZE : size;
...
161   /* If there was no free block, get a new one */
162 
163   if (!newblock)
164     {
165     pool_malloc += mlength;           /* Used in pools */
166     nonpool_malloc -= mlength;        /* Exclude from overall total */
167     newblock = store_malloc(mlength);
...

보이는 바와 같이 매번 요청되는 store_block의 최소 길이는 STORE_BLOCK_SIZE, 즉 8192

따라서 8192 크기의 store_block은 구조체 헤더와 힙 블록 헤더를 포함하여 총 크기가 0x2020이 됨 3

Exim이 클라이언트가 보낸 명령어를 실행할 때마다 명령어 실행이 성공하면 store_reset을 호출하여 불필요한 캐시나 남은 store_block을 해제함 여기서 말하는 실행 성공은 명령어 형식이 올바르고, 이메일에 불법 문자 등이 포함되지 않은 경우를 의미하며, 그렇지 않으면 store_reset이 호출되지 않음

공격 아이디어

이 취약점은 고전적인 off-by-one(사실 두 바이트 오버플로우도 가능)이나, 오버플로우되는 바이트 수가 적어 힙 블록의 민감한 구조를 직접 덮어쓸 수 없음. 따라서 ptmalloc의 특성을 이용하여 이 취약점의 영향을 확대하고 더 넓은 범위의 overflow, 또는 overlap으로 전환해야 함. off-by-one 취약점의 고전적인 공격 방법은 chunk enlarge -> chunk overlap임. 힙 블록의 크기를 크게 변경한 후 가짜 힙 헤더를 만들어 glibc의 정합성 검사를 우회하여 힙 블록의 중첩을 유발하고 더 넓은 범위의 덮어쓰기를 실현.

여기서 주요 과정은 chunk enlarge -> chunk overlap -> storeblock의 next 포인터 손상 후 store_reset을 트리거하여 임의의 힙 블록을 free시키고, 이 블록을 다시 할당받아 해당 내용을 수정(type confusion)하는 것. meh는 ACL 문자열이 있는 힙 블록을 수정할 것을 권장하는데, ACL 문자열 처리에는 명령 실행 기능이 있기 때문. ACL 문자열은 매우 많지만 대부분 NULL(아마도 설정 파일 때문). 여기서는 acl_smtp_mail 문자열을 선택했으며, 명령 실행 구문은 다음과 같음:

${run{command}}

대략적인 힙 레이아웃은 다음과 같음 4

첫 번째 힙 블록은 base64 디코딩으로 얻은 블록으로, off-by-one을 위해 사용되므로 storeblock의 끝에 위치해야 함. 편의상 0x2020보다 큰 블록을 직접 할당하여 base64 디코딩 결과를 저장함. 두 번째 힙 블록은 sender_helo_name으로, 다음 힙 블록을 덮어쓰는 데 사용됨. sender_helo_name은 storeblock에 저장되지 않고 직접 malloc됨:

1832 static BOOL
1833 check_helo(uschar *s)
1834 {
...
1884 if (yield) sender_helo_name = string_copy_malloc(start);

그러므로 크기는 자유롭게 설정 가능. 세 번째 힙 블록은 base64 디코딩으로 얻은 블록으로, 주로 헤더를 위조하고 덮어쓰여지므로 storeblock의 시작 부분에 위치해야 함. 편의상 0x2020 크기로 직접 할당함.

Exploit

나의 exp도 다른 사람들의 분석을 따라 단계별로 작성되었음. 큰 틀은 동일하지만 힙 레이아웃이 다소 달라 일부 작은 매개변수에 차이가 있음.

먼저 크기가 0x6060인 unsortedbin을 생성. 다음 명령어만으로 가능

ehlo('a'*0x1000)

exim이 "EHLO "+'a'*0x1000을 수신하면 match.c의 match_check_list 함수에서 다음 세 문자열이 생성됨

*name* in helo_lookup_domains? no (end of list)
sender_fullhost = (*name*) [127.0.0.1]
sender_rcvhost = [127.0.0.1] (helo=*name*)
여기서 *name*은 'a'*0x1000

name의 길이가 0x1000이므로 각 문자열은 각각 하나의 storeblock을 차지하고, 이 세 문자열은 연속된 세 개의 storeblock에 위치하게 됨. exim이 ehlo 명령을 성공적으로 완료하면 smtp_in.c의 smtp_setup_msg에서 앞의 세 문자열을 해제하여 0x6060 크기의 힙 블록을 생성함:

4369     cancel_cutthrough_connection(TRUE, US"sent EHLO response");
4370     smtp_reset(reset_point);
4371     toomany = FALSE;
4372     break;   /* HELO/EHLO */

이 때 힙 레이아웃은 다음과 같음: 5

도구 다운로드