정현진Jeong Hyeonjin

← 기록 목록

시스템

AFL++는 어떻게 동작하는가: 퍼징 루프와 구성 파일 정리

퍼징이 무엇인지, AFL++가 fork 서버와 공유 메모리로 커버리지를 모아 입력을 바꿔 가는 과정, 그리고 설치 폴더의 도구들이 각각 무슨 일을 하는지 정리했습니다.

발행
2025. 12. 28.
분량
1분
조회
0회

sudo 프로젝트에서 퍼저를 고르기 전에 AFL++를 공부하면서 정리했습니다.

퍼징이란

퍼징은 프로그램에 무작위나 변형된 입력을 대량으로 넣어, 비정상 종료나 오류를 일으키는 입력을 찾는 자동화 테스트 기법입니다. 성능, 안정성, 보안 취약점을 찾는 데 씁니다.

AFL의 퍼징 루프

  1. afl-fuzz가 대상 프로그램을 실행합니다.
  2. 대상이 처음 실행될 때 파이프로 afl-fuzz와 통신하며 fork 서버를 띄웁니다. 이후로는 매번 처음부터 실행하지 않고 fork()로 새 인스턴스를 만듭니다.
  3. 표준 입력이나 파일로 입력이 전달됩니다.
  4. 실행 경로(커버리지)가 공유 메모리에 기록되고 프로그램이 끝납니다.
  5. afl-fuzz가 공유 메모리의 기록을 보고, 새로운 경로를 연 입력을 바탕으로 다음 입력을 만듭니다.
  6. 다시 2~5를 반복합니다.

fork 서버 덕분에 프로그램 초기화 비용을 매번 치르지 않아도 됩니다. 커버리지를 보기 때문에 새로운 코드 경로에 닿은 입력을 우선해서 변형합니다.

설치 폴더의 구성

직접 쓰는 도구

도구 하는 일
afl-fuzz 퍼저 본체
afl-showmap 대상의 커버리지 맵 출력 (계측이 잘 됐는지 확인)
afl-cmin 커버리지를 유지하면서 시드 개수 줄이기
afl-tmin 크래시를 재현하는 입력을 작게 줄이기
afl-whatsup 진행 상태 요약 (큐, 크래시, 속도)
afl-plot 통계 그래프 생성
afl-analyze 입력의 어느 부분이 어떻게 처리되는지 분석
afl-gotcpu CPU 코어 상태 점검

계측 빌드용 컴파일러 래퍼

대상 프로그램을 AFL이 커버리지를 볼 수 있게 계측(instrumentation) 해서 빌드할 때 씁니다.

래퍼 설명
afl-cc 범용 래퍼, 내부에서 clang/gcc 선택
afl-clang-fast, afl-clang-fast++ LLVM 패스 기반 계측 (주로 권장)
afl-gcc, afl-gcc-fast gcc 기반 계측

소스가 없을 때: 모드

모드 방식
qemu_mode 바이너리만 있을 때 QEMU로 계측
frida_mode Frida 기반 동적 계측
unicorn_mode Unicorn 기반 에뮬레이션
nyx_mode, coresight_mode 가상화·하드웨어 기반 특수 모드

그 밖의 파일

  • LLVM 계측 패스(afl-llvm-pass.so, cmplog-*.so 등): 컴파일할 때 커버리지 수집, 비교문 분해 같은 변환을 끼워 넣음
  • 런타임 오브젝트(afl-compiler-rt*.o): 계측된 바이너리에 함께 링크됨
  • libdislocator.so, libtokencap.so: 메모리 오류 탐지, 비교 토큰 수집 보조
  • dictionaries/: 퍼징 힌트로 쓰는 토큰 사전
  • custom_mutators/: 사용자 정의 변이기

sudo 프로젝트에서

팀에서는 이 구조를 바탕으로 sudoers 파서(visudo)를 계측 빌드해 퍼징했습니다. 빠른 퍼징용(LTO), ASan 탐지용, ASan+디버그 심볼(크래시 분석용) 세 가지로 빌드를 나눴고, sudoers 키워드로 사전을 만들어 넣었습니다.

정리

  • 퍼저의 핵심은 커버리지를 보고 입력을 고르는 것입니다.
  • fork 서버로 실행 비용을 줄이고, 공유 메모리로 실행 경로를 주고받습니다.
  • 소스가 있으면 컴파일러 래퍼로 계측하고, 없으면 QEMU·Frida 모드를 씁니다.
→

연결된 프로젝트

단어 390글자 1,261연결 1