정현진Jeong Hyeonjin

정현진 — 보안 포트폴리오

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

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

유형
연구 기록
분류
시스템
발행
2025. 12. 28.
분량
1분
종류
연구 기록

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

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 모드를 씁니다.

0 백링크1 링크3 태그

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