들어가며
GIMP라는 이미지에디터를 퍼징한다. GIMP 2.8.16에서 발생하는 CVE-2016-4994을 분석한다. 그리고 발견한 크래시에서 코드 커버리지를 분석한다.
CVE-2017-9048은 Use-After-Free 취약점이다. 동적할당된 heap을 free하고 다시 재사용할 때 취약점이 발생한다. GIMP에서는 조작된 XCF 파일에서 발생한다.
공격자는 유효한 데이터의 손상에서 임의 코드 실행까지 다양한 악의적인 행위를 할 수 있다.
준비
1-day 실습이므로 취약점이 발생했던 같은 환경을 준비한다. 또는 다음의 내용을 학습할 수 있다.
- Ubuntu 20.04(https://releases.ubuntu.com/20.04/)
- afl-fuzz(Fuzzer)
- GDB(크래시 분석 디버깅 도구)
다음의 내용을 학습한다.
- 퍼징 속도 향상을 위한 persist mode 사용
- 상호작용바이너리 퍼징 / GUI 프로그램 퍼징
Persist mode
AFL 지속 모드(Persist mode)는 단일 프로세스를 사용하는 퍼저를 기반으로 한다. 퍼저는 하나의 타겟 프로세스에 코드를 주입하여 값을 변조하거나 삽입한다.
afl-fuzz는 프로세스 내 퍼징의 이점과 멀티 프로세스 도구인 지속 모드를 결합한 작업 방법을 지원한다.
지속 모드에서 AFL++는 각 퍼즈 단계 실행을 위한 새로운 프로세스를 생성하는 대신 단일 분기 프로세스에서 대상을 여러번 퍼즈한다. 이 모드는 퍼징 속도를 20배까지 향상시킬 수 있다.
기본 구조는 아래와 같다.
//Program initialization
while (__AFL_LOOP(10000)) {
/* Read input data. */
/* Call library code to be fuzzed. */
/* Reset state. */
}
//End of fuzzing
Download and Build
1. 대상 프로그램 다운 및 빌드
cd $HOME
mkdir Fuzzing_gimp && cd Fuzzing_gimp
sudo apt-get install build-essential libatk1.0-dev libfontconfig1-dev libcairo2-dev libgudev-1.0-0 libdbus-1-dev libdbus-glib-1-dev libexif-dev libxfixes-dev libgtk2.0-dev python2.7-dev libpango1.0-dev libglib2.0-dev zlib1g-dev intltool libbabl-dev
2. GEGL 0.2(Generic Graphics Library)의 설치가 필요하다.
wget https://download.gimp.org/pub/gegl/0.2/gegl-0.2.0.tar.bz2
tar xvf gegl-0.2.0.tar.bz2 && cd gegl-0.2.0
sed -i 's/CODEC_CAP_TRUNCATED/AV_CODEC_CAP_TRUNCATED/g' ./operations/external/ff-load.c
sed -i 's/CODEC_FLAG_TRUNCATED/AV_CODEC_FLAG_TRUNCATED/g' ./operations/external/ff-load.c
3. build
./configure --enable-debug --disable-glibtest --without-vala --without-cairo --without-pango --without-pangocairo --without-gdk-pixbuf --without-lensfun --without-libjpeg --without-libpng --without-librsvg --without-openexr --without-sdl --without-libopenraw --without-jasper --without-graphviz --without-lua --without-libavformat --without-libv4l --without-libspiro --without-exiv2 --without-umfpack
make -j$(nproc)
sudo make install
4. GIMP 2.8.16 다운로드 및 압축 해제
cd ..
wget https://mirror.klaus-uwe.me/gimp/pub/gimp/v2.8/gimp-2.8.16.tar.bz2
tar xvf gimp-2.8.16.tar.bz2 && cd gimp-2.8.16/
CC=afl-clang-lto CXX=afl-clang-lto++ PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$HOME/Fuzzing_gimp/gegl-0.2.0/ CFLAGS="-fsanitize=address" CXXFLAGS="-fsanitize=address" LDFLAGS="-fsanitize=address" ./configure --disable-gtktest --disable-glibtest --disable-alsatest --disable-nls --without-libtiff --without-libjpeg --without-bzip2 --without-gs --without-libpng --without-libmng --without-libexif --without-aa --without-libxpm --without-webkit --without-librsvg --without-print --without-poppler --without-cairo-pdf --without-gvfs --without-libcurl --without-wmf --without-libjasper --without-alsa --without-gudev --disable-python --enable-gimp-console --without-mac-twain --without-script-fu --without-gudev --without-dbus --disable-mp --without-linux-input --without-xvfb-run --with-gif-compression=none --without-xmc --with-shm=none --enable-debug --prefix="$HOME/Fuzzing_gimp/gimp-2.8.16/install"
make -j$(nproc)
make install
Persistent mode
두가지 방법이 있다.
- app.c 파일을 수정하는 방법
- AFL_LOOP 매크로를 for 반복 루프 내에 포함시킨다.
if ( filenames ){
gint i;
for(i=0;filenames[i] != NULL; i++){
if (run_loop){
#ifdef __AFL_COMPILER
while(__AFL_LOOP(1000)){
file_open_from_command_line (gimp, filenames[i], as_new);
}
exit(0);
#else
file_open_from_command_line (gimp, filenames[i], as_new);
#endif
}
- AFL_LOOP를 xcf_load_invoker 함수 내에 포함시킨다.
--- ../xcf.c 2014-08-20 08:27:58.000000000 -0700
+++ ./app/xcf/xcf.c 2021-10-11 13:02:42.800831192 -0700
@@ -277,6 +277,10 @@
filename = g_value_get_string (&args->values[1]);
+#ifdef __AFL_COMPILER
+ while(__AFL_LOOP(10000)){
+#endif
+
info.fp = g_fopen (filename, "rb");
if (info.fp)
@@ -366,6 +370,12 @@
if (success)
gimp_value_set_image (&return_vals->values[1], image);
+#ifdef __AFL_COMPILER
+ }
+#endif
+
+ exit(0);
+
gimp_unset_busy (gimp);
return return_vals;
첫 번째 방법은 다른 입력 형식도 타겟으로 할 수 있지만 두 번째 방법은 xcf만 대상으로 하므로 더 빠르게 버그를 찾을 수 있다.
Seed corpus creation
샘플 xcf 파일을 구해서 AFL input 폴더에 넣는다.
Fuzzing
GIMP 바이너리를 대상으로 한 퍼징이므로 불필요한 플러그인을 제거한다.
rm ./install/lib/gimp/2.0/plug-ins/*
Fuzzing!
ASAN_OPTIONS=detect_leaks=0,abort_on_error=1,symbolize=0 afl-fuzz -i './afl_in' -o './afl_out' -D -t 100 -- ./install/bin/gimp-console-2.8 --verbose -d -f @@
- gimp-console-2.8은 GIMP의 CLI 버전이다.
- 결정론적 변이 옵션을 허용했다. (-D)
- 코드에 무한 루프 버그가 있으므로 시간 제한(-t 1000)을 설정해야 한다. 시스템 성능에 따라 다를 수 있기 때문에 적절히 조절한다.
Triage
ASan 트레이스를 지원하므로 크래시가 발생한 파일을 매개변수로 전달하여 실행하면 된다.
'Reversing' 카테고리의 다른 글
[AFL++] Install AFL Qemu(Ubuntu 20.04) (0) | 2022.08.24 |
---|---|
[WinAFL] 퍼징으로 1-day 취약점 분석하기(7zip) (0) | 2022.08.17 |
[Fuzzing 101] 퍼징으로 1-day 취약점 분석하기(LibXML) (0) | 2022.08.05 |
[Fuzzing 101] 퍼징으로 1-day 취약점 분석하기(LibTIFF) (0) | 2022.08.01 |
[Fuzzing 101] 퍼징으로 1-day 취약점 분석하기(tcpdump) (0) | 2022.07.28 |