시작하기 전에...
이번 Fuzzing은 기본적으로 취약점을 찾기까지 너무 오랜 시간이 걸려 결론적으로 유의미한(예제에 있는) 취약점을 찾지 못했다. 뭐 사실 우리가 Fuzzing에 익숙해지려고 하는거지, CVE 분석하자고 Fuzzing을 돌리는 것은 아니니 그냥 하자.
CVE-2016-4994
Use-after-free vulnerability in the xcf_load_image function in app/xcf/xcf-load.c in GIMP allows remote attackers to cause a denial of service (program crash) or possibly execute arbitrary code via a crafted XCF file.
GIMP(v2.8.16)의 xcf-load.c 의 xcf_load_image 함수에서 발생하는 use-after-free 취약점으로 원격 공격자는 조작된 XCF파일을 통해 서비스 거부를 발생 시키거나 코드를 실행할 수 있다.
Persistent mode
AFL Persistent mode 는 단일 프로세스를 사용하는 fuzzer, 즉 타겟 프로세스에 코드를 주입하고 메모리의 입력 값을 변경하는 프로세스 fuzzer를 기반으로 한다.
afl-fuzz는 단일 프로세스 fuzzing의 이점과 더 전통적인 다중 프로세스 도구인 Persistent Mode의 견고성을 결합한 작업모드를 지원한다.
Persistent mode에서 AFL++은 각 fuzzer 실행에 대해 새로운 프로세스를 fork하는 대신 단일 fork 프로세스에서 대상을 여러 번 fuzzing 한다. 이 모드는 fuzzing 속도를 최대 20배 향상시킬 수 있다.
대상의 기본 구조는 다음과 같다.
//Program initialization
while (__AFL_LOOP(10000)) {
/* Read input data. */
/* Call library code to be fuzzed. */
/* Reset state. */
}
//End of fuzzing
즉 소스코드를 수정해서 단일 프로세스로 하여 Fuzzing을 하는 것이다.
xcf
XCF 파일은 대부분 The GIMP Team의 GIMP에 속한다. XCF는 GIMP 그래픽 편집기에서 만든 이미지 프로젝트를 저장하는 데 사용되는 기본 파일 형식이다. XCF 파일의 내용에는 이미지, 텍스트, 모양, 효과, 구성, 레이어, 현재 선택, 투명도, 채널 및 프로젝트 메타데이터가 포함된다. 이 파일 형식은 사용자가 나중에 XCF 파일을 다시 열고 이전 편집 세션에서 중단한 부분을 선택할 수 있기 때문에 사진 편집 작업의 중간 결과를 저장하는 데 적합하다. XCF 형식은 이전 버전과 호환되므로 이전 버전의 GIMP는 새 버전으로 만든 프로젝트를 열 수 있다.
target build
종속 패키지를 설치한다.
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
GEGL 0.2(Generic Graphics Library)가 필요한데 우분투에는 이게 없다. 그래서 따로 build해야 한다.
wget https://download.gimp.org/pub/gegl/0.2/gegl-0.2.0.tar.bz2
tar xvf gegl-0.2.0.tar.bz2
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
code를 살짝 수정한다.
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
sed는 스트림 치환명령이다.
s : 대체를 나타내는 명령이다
g : 전역을 나타내는 명령으로 한줄의 모든 스트림을 치환한다. (이걸 안하면 한줄에 처음 발견된 것만 치환됨)
-i : 원본 파일을 수정한다. 이를 안하면 치환되었을때를 출력하고 원본파일은 수정되지 않는다.
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 --prefix="$HOME/fuzzing_GIMP/gimp-2.8.16/install"
make -j$(nproc)
sudo make install
prefix 없어도 된다. 어짜피 종속패키지니까
configure 옵션
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
여기서 다른 패키지는 그냥 설치했지만 gegl은 따로 빌드해줬다. 그래서
PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$HOME/fuzzing_GIMP/gegl-0.2.0/
와 같이 환경변수를 추가하는 방법으로 라이브러리를 찾는 경로를 추가했다.
$(nproc)은 현재 시스템에서 사용 가능한 프로세서(코어)의 수를 반환하는 명령이다.
configure 옵션
`--disable-gtktest`, `--disable-glibtest`, `--disable-alsatest`: 각각 GTK, GLib, ALSA에 대한 테스트를 비활성화하는 옵션입니다. 테스트를 수행하지 않고 빌드할 때 사용됩니다.
- `--disable-nls`: Native Language Support(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`: Python 지원을 비활성화하는 옵션으로, 프로그램이 Python 스크립트를 사용하지 않도록 설정합니다.
- `--enable-gimp-console`: GIMP의 콘솔(터미널) 모드를 활성화하는 옵션으로, 그래픽 사용자 인터페이스가 아닌 터미널에서 GIMP을 사용할 수 있도록 설정합니다.
- `--without-mac-twain`: macOS에서 TWAIN(스캐너 및 카메라와의 상호 작용을 위한 API)을 사용하지 않도록 설정하는 옵션입니다.
- `--without-script-fu`: Script-Fu를 사용하지 않도록 설정하는 옵션으로, GIMP의 스크립트 기능을 비활성화합니다.
- `--without-dbus`: D-Bus를 사용하지 않도록 설정하는 옵션으로, D-Bus 통신을 사용하지 않도록 합니다.
- `--disable-mp`: MP(마커 플롯)를 비활성화하는 옵션으로, 마커 플롯 지원을 사용하지 않도록 설정합니다.
- `--without-linux-input`: Linux Input을 사용하지 않도록 설정하는 옵션으로, Linux 입력 관련 기능을 지원하지 않도록 합니다.
- `--without-xvfb-run`: xvfb-run을 사용하지 않도록 설정하는 옵션으로, X Virtual Framebuffer를 사용하지 않도록 합니다.
- `--with-gif-compression=none`: GIF 이미지의 압축을 비활성화하는 옵션입니다. GIF 이미지를 압축하지 않도록 설정합니다.
- `--without-xmc`: X Motion Compensation을 사용하지 않도록 설정하는 옵션으로, XMC 지원을 비활성화합니다.
- `--with-shm=none`: 공유 메모리를 사용하지 않도록 설정하는 옵션으로, 공유 메모리를 사용하지 않도록 합니다.
- `--enable-debug`: 디버깅 정보를 포함하여 디버깅을 용이하게 하는 옵션입니다. 이는 컴파일된 코드에 추가 정보를 포함시키는 것을 의미합니다.
옵션이 잔뜩 있는데 보통 공식문서나 readme 혹은 Makefile 등 개발자가 어딘가에다가 적어두긴 했다. 노가다 하면서 알아내야 한다. 참고로 위 설명은 chat gpt 피셜이다.
Persistent mode 적용
두 가지 방법이 있다.
1. app.c 파일을 수정하는 방법
2. AFL_LOOP 매크로를 for 반복 루프 내에 포함시키는 방법
파일을 load하는 것을 내포한 함수를 loop로 감싸서 반복
파일을 가져오고 일련의 작업을 하는 부분을 loop로 감쌈
소스코드를 수정해서 빌드한다는게 쉬운 작업이 아니다. 당연히 오류가 많이 뜰 것이고 쉽지 않을 것이다. 그래서 오픈소스니 코드를 분석하고 적합한 방법으로 코드 수정을 해야한다. (물론 나도 못한다.)
솔직히 뉴비는 코드 수정이 쉽지 않으니 개념을 익힌다는 생각으로 하자.
seed corpus
예제로 준 것을 사용하자.
Fuzzing
해당 취약점은 GIMP core에 영향을 준다. 필요없는 플러그인을 삭제해서 시작 시간을 줄여주자.
rm ./install/lib/gimp/2.0/plug-ins/*
ASAN_OPTIONS=detect_leaks=0,abort_on_error=1,symbolize=0 afl-fuzz -i './afl_in' -o './afl_out' -D -t 1000+ -- ./install/bin/gimp-console-2.8 --verbose -d -f @@
- gimp-console-2.8 버전은 GIMP의 콘솔 전용 버전이다.
- deterministic으로 해라 -D
- 이 코드에는 무한 루프 버그가 있어서 -t 옵션을 넣어준다.
이렇게 last new find 에 none yet (odd, check syntax!) 라고 뜰 경우 input이 프로그램에 들어가지 않는 상황으로 대부분 실행파일의 파라미터 (-d, -t 이런거) 문제일 확률이 크다. (존재하지 않는 파라미터, 잘못된 옵션)
<틀린 부분이 있다면 비난과 욕설을 해주세요>
'Fuzzing' 카테고리의 다른 글
Fuzzing101 Exercise7 (2) | 2024.07.07 |
---|---|
AddressSanitizer (0) | 2024.04.22 |
AFL++ download (1) | 2023.10.04 |
AFL++ (0) | 2023.10.04 |
FUZZING의 과정 (0) | 2023.09.29 |