본문 바로가기

보안, 해킹/_Fuzzing

[Fuzzing101] Exercise 1 (CVE-2019-13288)

Fuzzing101 을 통해 fuzzing 과정, fuzzer 사용법등에 대하여 익숙해져보려고 한다.

Fuzzing101의 Exercise 1 은 CVE-2019-13288이 발생하는 Xpdf 도구를 이용하여 fuzzing을 경험해보는 문제이다.

 

CVE-2019-13288은 조작된 파일을 통해 무한 재귀를 일으킬 수 있는 취약점이다. 이는 DoS 공격에 활용될 수 있다.

 

퍼징은 다음과 같은 순서로 진행된다.

1. 환경 구축

2. 타겟 계측 및 빌드

3. 시드 코퍼스 준비

4. 퍼징 실행

5. 결과 분석

6. 보고 및 수정

 

일단 환경 구축부터 해보자.

 

나는 현재 mac을 사용해서 공부중이기에 docker를 사용하여 공부하려고 한다.

 

docker hub에 존재하는 aflplusplus/aflplusplus 이미지를 가져와서 컨테이너를 만든다.

docker pull aflplusplus/aflplusplus

 

이후의 컨테이너 실행은 본인이 원하는 이름(--name 사용), 플래그를 지정하여 사용하면 된다.

특별히 지정해줘야할 플래그는 다음과 같다.

--security-opt seccomp=unconfined
--cap-add=SYS_PTRACE

 

 

이 플래그들은 권한 및 보안에 대한 플래그들로 퍼징을 제대로 수행하기 위해 지정한다.

--security-opt seccomp=unconfined 는 Docker의 시스템 콜에 대한 감시, 제한을 풀어버리는 플래그 이며 -cap-add=SYS_PTRACE 이 플래그는 gdb같은 디버거가 다른 프로세스를 볼 수 있도록 만들어주는 플래그다.

 

 

환경을 만들었으니 퍼저에 대한 설정 즉, 타겟 계측을 설정하고  빌드해야 한다.다음과 같은 명령어를 사용했다.

#LLVM 설정
export LLVM_CONFIG=$(which llvm-config-15 || which llvm-config)
#컴파일러 교체 및 설계도 작성
CC=afl-clang-fast CXX=afl-clang-fast++ ./configure --prefix="/src/exercise1/install"

 

 

우리가 사용하려는 afl++는 내부적으로 afl-clang-fast 라는 컴파일러를 사용한다.

afl-clang-fast를 사용하기 위해서는 위의 명령어들을 작성해줘야 한다.

export ~ 명령어는 afl++가 내부적으로 LLVM 구조를 가지고 있기에 afl++ 에게 사용할 LLVM에 대한 도구들의 위치를 지정해주는 것이고 CC = ~ 명령어는 기본적으로 사용하는 C 컴파일러가 아닌 지정한 컴파일러로의 사용을 의미하며 --prefix ~ 부분은 빌드한 결과를 해당 경로에 저장하라는 의미이다.

 

이후의 빌드는 다음의 명령어를 사용했다.

make -j$(nproc)
make install

 

 

-j$(nproc) 은 모든 cpu 자원을 동원해 빌드하라는 명령으로 속도를 위해 사용했다.

 

이제 계측 설정 및 빌드를 진행하였기에 퍼저를 실행하면 된다.

 

다음의 명령어로 실행했다.

AFL_I_DONT_CARE_ABOUT_MISSING_CRASH_REPORTER=1 AFL_SKIP_CPUFREQ=1 \
afl-fuzz -i seeds -o out -s 123 -- ./install/bin/pdftotext @@ /dev/null

 

대문자 AFL~~ 부분들은 환경변수 설정이다. 리눅스가 아닌 mac에서 진행하기에 에러무시를 설정한 것이다.

 

afl-fuzz 는 fuzzing 실행 명령어다.

-i 는 어떤 디렉토린 내부에 있는 파일들에 대하여 퍼징을 시작할지를 의미한다.

-o 는 어떤 디렉토리에 결과를 담을지 지정한다.

-s 는 난수값 설정 플래그이다. 

-- 는 플래그 설정이 끝났음을 의미한다. 이후의 값이 인자로 프로그램에 들어갈 값임을 의미한다.

./install/bin/pdftotext 는 아까 계측 과정에서 빌드한 프로그램 경로이다.

@@ 는 퍼저가 변조한 파일 이름을 이 자리에 넣으라는 것을 의미한다.

/dev/null 은 프로그램이 화면에 쏟아내는 수만 줄의 글자들을 쓰레기통(/dev/null)에 버려 속도를 높인다.

 

이후로는 분석을 진행하면 된다.

afl++ 실행 화면, 퍼징 대상: helloworld.pdf

 

나는 Fuzzing101의 helloworld.pdf를 대상으로 퍼징을 진행했다.

 

퍼징을 진행하면 발생한 crash와 hang에 대하여 퍼징할때 -o로 지정한 폴더로 문제를 일으킨 파일들이 저장된다.

 

여기서 crash 폴더에 저장된 한 파일을 gdb를 붙여서 분석해보자.

gdb --args ./install/bin/pdftotext out/default/crashes/id:000000~~ (파일명이 아주 길다.) /dev/null

 

라는 명령어로 gdb를 붙여본다.

이후 그대로 run을 진행하면 crash, 즉 segmentation fault가 발생한다.

이후 bt 명령어, frame, list 명령어등 여러 명령어로 문제 함수 찾아본다.

helloworld.pdf 의 pdftotext에 의한 문제는 


Parser::getObj
(this=0xaaaaaca0df40, obj=0xffffff81ed90, fileKey=0x0, encAlgorithm=cryptRC4, keyLength=0, objNum=2, objGen=0) at Parser.cc:94

여기서 문제가 발생했음을 알 수 있었다.

 

해당 함수의 구체적인 내용은 다음과 같다.

89	    if (buf1.isEOF())
90	      error(getPos(), "End of file inside dictionary");
91	    // stream objects are not allowed inside content streams or
92	    // object streams
93	    if (allowStreams && buf2.isCmd("stream")) {
94	      if ((str = makeStream(obj, fileKey, encAlgorithm, keyLength,
95				    objNum, objGen))) {
96		obj->initStream(str);
97	      } else {
98		obj->free();

 

 

이 코드가 crash를 일으키는, 무한재귀를 일으킨다.

만약 makeStream 함수가 getObj를 호출하도록 되어있다면 서로 호출하게 되며 무한재귀를 일으키게 된다.

 

이번에 실습해본 Xpdf에 대한 취약점을 퍼징으로 찾아보는 과정은 퍼저에 대한 기본적인 지식과 사용법을 어느정도 파악할 수 있게 만들어준 것 같다.

'보안, 해킹 > _Fuzzing' 카테고리의 다른 글

[Fuzzing101] Exercise2 (CVE-2009-3895, CVE-2012-2836)  (0) 2026.02.03
Fuzzing  (0) 2026.01.03