들어가며
LibXML2라는 XML파싱 라이브러리를 퍼징한다. LibXML2 2.9.4에서 발생하는 CVE-2017-9048을 분석한다. 그리고 발견한 크래시에서 코드 커버리지를 분석한다.
CVE-2017-9048은 스택버퍼오버플로우 취약점이다. 실행중인 스택영역의 값을 덮어씌울 수 있으며, DTD 유효성 검사 함수에서 발생한다.
공격자는 바이너리의 컨텍스트 내에서 임의 코드를 실행할 수 있다.
준비
1-day 실습이므로 취약점이 발생했던 같은 환경을 준비한다. 또는 다음의 내용을 학습할 수 있다.
- Ubuntu 20.04(https://releases.ubuntu.com/20.04/)
- afl-fuzz(Fuzzer)
- GDB(크래시 분석 디버깅 도구)
다음의 내용을 학습한다.
- 새로운 실행 경로 탐색을 위한 커스텀 딕셔너리 사용 방법
- 멀티 코어를 활용한 병렬 퍼징
Dictionaries
복잡한 텍스트 기반 파일 형식(ex: XML)을 퍼징하려는 경우 기본 구문 토큰 목록을 포함하는 사전(Dictionary)을 미리 제공하는 것이 유용하다.
AFL의 경우 이러한 사전은 단순히 단어 또는 값(value)의 집합이며, AFL이 현재 메모리 내 파일에 변경 사항을 적용하기 위해 사용한다. 아래와 같은 기법을 사용하여 AFL은 사전에 제공된 값을 사용한다.
재정의(Override) : 특정 위치를 n개의 바이트 수로 바꾼다. 여기서 n은 사전 항목의 길이
삽입(Insert) : 현재 파일 위치에 사전 항목을 삽입하여 모든 문자를 아래로 이동하고 파일의 크기를 늘린다.
https://github.com/AFLplusplus/AFLplusplus/tree/stable/dictionaries
Paralellization(병렬화)
멀티 코어 시스템을 사용하는 경우 CPU 리소스를 최대한 활용하기 위해 퍼징 작업을 병렬화한다.
독립 인스턴스(Independent instances)
가장 간단한 병렬화 방법이다. 완전히 별개의 afl-fuzz 인스턴스를 실행한다.
AFL은 비결정론적 테스트 알고리즘을 사용한다. 따라서 여러 AFL 인스턴스를 실행하면 크래시 발견 확률이 높아진다.
이를 위해 여러 터미널 창에서 “afl-fuzz” 인스턴스만 실행하면 되며, 각각의 터미널 창에 대해 서로 “output” 폴더를 설정할 수 있다. 간단한 방법은 코어의 수만큼 퍼징 작업을 실행한다.
- 이때 -s 플래그를 사용하는 경우 각 인스턴스에 대해 다른 시드를 사용해야 한다.
공유 인스턴스(Shared instances)
병렬 퍼징에 대한 좀 더 개선된 접근법이다. 각 퍼저 인스턴스는 다른 퍼저에 의해 발견된 테스트 케이스를 수집한다.
일반적인 퍼징은 한 번의 실행에 하나의 마스터 인스턴스만 존재한다.
./afl-fuzz -i afl_in -o afl_out -M Master -- ./program @@
그리고, N-1개의 슬레이브를 구성할 수 있다.
./afl-fuzz -i afl_in -o afl_out -S Slave1 -- ./program @@
./afl-fuzz -i afl_in -o afl_out -S Slave2 -- ./program @@
...
./afl-fuzz -i afl_in -o afl_out -S SlaveN -- ./program @@
Download and Build
1. 대상 프로그램 다운 및 빌드
cd $HOME
mkdir Fuzzing_libxml2 && cd Fuzzing_libxml2
wget http://xmlsoft.org/download/libxml2-2.9.4.tar.gz
tar xvf libxml2-2.9.4.tar.gz && cd libxml2-2.9.4/
sudo apt-get install python-dev
CC=afl-clang-lto CXX=afl-clang-lto++ CFLAGS="-fsanitize=address" CXXFLAGS="-fsanitize=address" LDFLAGS="-fsanitize=address" ./configure --prefix="$HOME/Fuzzing_libxml2/libxml2-2.9.4/install" --disable-shared --without-debug --without-ftp --without-http --without-legacy --without-python LIBS='-ldl'
make -j$(nproc)
make install
2. 실행확인
./xmllint --memory ./test/wml.xml
Seed Corpus creation
github 저장소에서 제공하는 SampleInput.xml 파일을 이용한다.
mkdir dictionaries && cd dictionaries
wget https://raw.githubusercontent.com/AFLplusplus/AFLplusplus/stable/dictionaries/xml.dict
cd ..
Fuzzing
크래시를 탐지하기 위해 —valid 옵션을 활성해야한다. dictionary 경로를 -x 플래그로 지정하고 -D 플래그로 결정론적 변이를 활성화한다.(병렬 퍼징을 위한 마스터 퍼저)
afl-fuzz -m none -i ./afl_in -o afl_out -s 123 -x ./dictionaries/xml.dict -D -M master -- ./xmllint --memory --noenc --nocdata --dtdattr --loaddtd --valid --xinclude @@
슬레이브 인스턴스 실행은 다음과 같다.
afl-fuzz -m none -i ./afl_in -o afl_out -s 234 -S slave1 -- ./xmllint --memory --noenc --nocdata --dtdattr --loaddtd --valid --xinclude @@
Triage
이전 실습에서와 같이 ASAN을 이용해 빌드했기 때문에 디버그하기에는 더 쉽다. 크래시가 발생한 파일을 인자로 하여 바이너리를 실행한다.
./xmllint --memory --noenc --nocdata --dtdattr --loaddtd --valid --xinclude './afl_out/default/crashes/id:000000,sig:06,src:003963,time:12456489,op:havoc,rep:4'
'Reversing' 카테고리의 다른 글
[WinAFL] 퍼징으로 1-day 취약점 분석하기(7zip) (0) | 2022.08.17 |
---|---|
[Fuzzing 101] 퍼징으로 1-day 취약점 분석하기(GIMP) (0) | 2022.08.09 |
[Fuzzing 101] 퍼징으로 1-day 취약점 분석하기(LibTIFF) (0) | 2022.08.01 |
[Fuzzing 101] 퍼징으로 1-day 취약점 분석하기(tcpdump) (0) | 2022.07.28 |
[Fuzzing 101] 퍼징으로 1-day 취약점 분석하기(libexif) (0) | 2022.07.24 |