소프트웨어 퍼징에 대한 개념을 이해하고 다양한 라이브러리 사용에 익숙해지기 위하여 Fuzzing101의 1번 연습 문제를 진행한다.
1번 문제는 xpdf를 대상으로 퍼징을 진행한다. xpdf 3.02 버전에는 CVE-2019-13288가 존재한다. 해당 취약점은 PDF 파싱 과정에서 특정 함수에 무한 재귀를 유발하여 DoS를 일으킬 수 있는 취약점이다.
먼저 xpdf 3.02 버전을 설치한다.
cd $HOME
mkdir fuzzing_xpdf && cd fuzzing_xpdf/
sudo apt install build-essential
wget https://dl.xpdfreader.com/old/xpdf-3.02.tar.gz
tar -xvzf xpdf-3.02.tar.gz
cd xpdf-3.02
sudo apt update && sudo apt install -y build-essential gcc
./configure --prefix="$HOME/fuzzing_xpdf/install/"
make
make install
위와같은 과정을 거쳐 xpdf를 설치하면 $HOME/fuzzing_xpdf/install/
경로에 xpdf가 설치된다.
xpdf에 사용할 예제용 pdf가 필요한데 이를 설치한다.
cd $HOME/fuzzing_xpdf
mkdir pdf_examples && cd pdf_examples
wget https://github.com/mozilla/pdf.js-sample-files/raw/master/helloworld.pdf
wget http://www.africau.edu/images/default/sample.pdf
wget https://www.melbpc.org.au/wp-content/uploads/2017/10/small-example-pdf-file.pdf
테스트용 pdf를 설치한 xpdf의 툴인 pdfinfo로 확인해본다.
AFL++는 Coverage-guided fuzzer로 새로운 실행 경로와 잠재적 버그를 발견하기 위해 각 입력에 대한 커버리지 정보를 수집한다. 화이트 박스일 경우 AFL++ instrumentation을 이용하여 각 기본 블록(함수, 루프 등)의 프롤로그 부분에 함수 호출을 삽입할 수 있다.
대상에 대한 instrumentation을 활성화하려면 AFL의 컴파일러로 코드를 컴파일해야한다. 그렇기에 이전에 설치한 xpdf를 삭제한다.
rm -rf $HOME/fuzzing_xpdf/install
cd $HOME/fuzzing_xpdf/xpdf-3.02/
make clean
기존에 설치한 xpdf 삭제가 완료되었다면 위에서 말한것처럼 alf-clang-fast
컴파일러를 통해 xpdf를 빌드한다.
export LLVM_CONFIG="llvm-config-11"
CC=$HOME/AFLplusplus/afl-clang-fast CXX=$HOME/AFLplusplus/afl-clang-fast++ ./configure --prefix="$HOME/fuzzing_xpdf/install/"
make
make install
이제 아래와 같은 명령으로 fuzzer를 실행할 수 있다.
afl-fuzz -i $HOME/fuzzing_xpdf/pdf_examples/ -o $HOME/fuzzing_xpdf/out/ -s 123 -- $HOME/fuzzing_xpdf/install/bin/pdftotext @@ $HOME/fuzzing_xpdf/output
위 과정에서 아래와 같은 에러가 발생 할 수 있는데 이때 일시적으로 AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1
을 설정하면서 실행할 수 있다.
AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 afl-fuzz -i $HOME/fuzzing_xpdf/pdf_examples/ -o $HOME/fuzzing_xpdf/out/ -s 123 -- $HOME/fuzzing_xpdf/install/bin/pdftotext @@ $HOME/fuzzing_xpdf/output
위 에러를 core_pattern
파일을 수정하여 해결할 수도 있다.
sudo su
echo core > /proc/sys/kernel/core_pattern
exit
약 13분 정도 퍼징을 수행한 결과 퍼저 실시 지정한 output 경로에서 8개의 saved crashes가 확인된다.
gdb를 통해 pdftotext에 크래시를 유발했던 파일을 넣고 run할 경우 Segmentation fault
를 확인할 수 있다.
gdb에서 backtrace하면 Parser::getObj
함수가 무한 재귀된것을 확인할 수 있다.