libAFL 소개
libAFL의 등장 배경
AFL++, libFuzzer, Honggfuzz 등 주요하게 사용되는 퍼저가 존재하지만, 이들은 확장성 있게 설게되지 않았다.
퍼저 개발자는 이러한 기존 도구 중 하나를 포크하거나 처음부터 새로운 퍼저를 만들어야 한다. 어떤 경우든 연구자들은 서로 호환되지 않는 수많은 퍼저를 개발하게 되고, 퍼저의 뛰어난 기능을 새로운 프로젝트에 결합할 수도 없다.
이런 갈라파고스화 문제를 해결하기 위해서, AFL++ 개발자들이 만든 퍼저 개발용 라이브러리가 libAFL이다.
libAFL의 특징
- Rust 컴파일러가 동작하는 어떤 플랫폼에서도 사용할 수 있다.
- AFL++ 개발자들이 제작한 것으로, 최신 퍼징 트렌드를 반영했다.
- LLMP(저수준 메시지 전달)을 개발해 코어에 따라 기능을 선형적으로 확장할 수 있다. TCP로 여러 머신에 확장할 수도 있다.
- QEMU-mode, Frida-Mode 등 바이너리 전용 모드를 이용할 수 있다.
핵심 개념
Observer
테스트 중인 프로그램을 실행하는 동안 관찰된 정보를 퍼저에 제공하는 엔티티이다. 입력이 흥미롭다고 판단되면 serialize 되어 다른 노드에 전달되어 코퍼스에 추가될 수 있다.
퍼저는 Observer를 기반으로 테스트 케이스가 퍼저에게 흥미로운지 아닌지를 선택하는 Feedback을 통해 동작한다.
Executor
테스트 중인 프로그램을 실행한다.
InprocessExecutor
프로세스 내에서 harness 프로그램(함수)를 실행한다.
ForkServerExecutor
harness code가 afl-cc에 의해 컴파일되어 EDGES_MAP을 사용할 수 없다.
대상이 공유 메모리 테스트케이스를 사용하도록 구성된 경우, ForkServerExecutor는 핸드셰이크 중에 이를 인식하고 그에 따라 자동으로 설정한다.
InprocessForkExecutor
harness를 실행하기 전에 Fork한다.
어떤 상황에서는 harness가 매우 불안정하거나 harness가 전역 상태를 혼란스럽게 만들 수 있다. 이 경우 자식 프로세스에서 harness runs를 실행하기 전에 fork하여 문제를 일으키지 않도록 하려는 것이다.
Feedback
테스트 중인 프로그램의 실행 결과를 흥미로운지 아닌지를 분류하는 엔티티이다. 실행이 흥미로운 경우, 대상 프로그램에 피드백을 제공하는 데 사용된 해당 입력이 corpus에 추가된다.
Feedback은 Observer와 헷갈릴 수 있다.
대부분의 경우 Feedback은 하나 이상의 Observer가 보고한 정보를 처리하여 실행이 흥미로운지 여부를 결정한다. 여기서 ' 흥미로운' 입력은 제어 흐름 그래프에서 이전에 볼 수 없었던 edge에 도달하는 입력이다.
일반적으로 향후 변형을 위해 입력을 유지할지 여부를 결정하는 데 사용되지만, 소위 Objective Feedback이라고 하는 다른 용도로도 사용된다. 이 경우 '흥미로운 정도'는 목표가 달성되었는지를 나타낸다. 일반적으로 이러한 목표는 crash 또는 time-out이지만, 프로그램의 특정 부분에 도달했는지 또는 sanitization을 감지하는 데에도 사용할 수 있다.
Input
Input은 "프로그램의 입력은 프로그램 동작에 영향을 주는 외부 소스에서 가져온 데이터"이다. 추상 퍼저에서 Input은 "프로그램 입력의 내부 표현 또는 한 부분"으로 재정의할 수 있다.
프로그램의 입력은 바이트 배열이며 AFL과 같은 퍼저에서는 이러한 바이트 배열을 정확히 저장하고 조작한다.
하지만 항상 그런 것은 아니다. 프로그램은 선형 바이트 배열이 아닌 입력(예: use case나 프로토콜을 구성하는 일련의 시스템 호출)을 기대할 수 있으며 퍼저는 프로그램이 입력을 소비하는 것과 동일한 방식으로 입력을 나타내지 않는다.
예를 들어 문법 퍼저의 경우, 입력은 유효성을 유지하면서 쉽게 조작할 수 있는 데이터 구조이므로 일반적으로 추상 구문 트리이지만, 프로그램은 바이트 배열을 입력으로 기대하므로 실행 직전에 트리를 바이트 시퀀스로 serialize한다.
Corpus
테스트케이스가 저장되는 곳이다.
corpus는 테스트케이스를 디스크나 메모리 등 다양한 방식으로 저장하거나 디스크 스토리지의 속도를 높이기 위해 캐시를 구현할 수 있다.
일반적으로 테스트케이스는 흥미롭다고 판단될 때 corpus에 추가되지만, 테스트 중인 프로그램을 충돌시키는 것과 같은 목표를 달성하는 테스트케이스를 저장하는 데에도 사용된다.
LibAFL에서, corpus가 fuzzer가 요청하는 다음 테스트케이스를 검색하는 역할은 Scheduler 가 담당한다. FIFO처럼 corpus로부터 테스트케이스를 pop하는 policy를 나타낸다.
Mutator
하나 이상의 입력을 받아 그 입력에 의해 파생된 새로운 입력 인스턴스를 생성하는 엔티티이다.
Generator
입력을 처음부터 생성하도록 설계된 컴포넌트이다. 일반적으로 무작위 입력을 생성하기 위해 random generator가 사용된다.
Stage
corpus에서 받은 하나의 입력에 동작하는 엔티티다.
예를 들어, corpus의 입력이 주어지면 mutational stage가 Mutator를 적용하고 생성된 입력을 한 번 이상 실행한다.
이 작업을 몇 번 수행해야 하는지는 schedule할 수 있다. 예를 들어 AFL은 입력의 performance score를 사용하여 havoc mutator를 몇 번 호출할지 선택한다.
stage는 analysis stage일 수도 있다. 테스트케이스에 더 많은 엔트로피를 도입하는 것을 목표로 하는 Redqueen의 Colorization stage컬러화 단계나 테스트케이스의 크기를 줄이는 것을 목표로 하는 AFL의 Trimming Stage가 그 예이다.
'보안 > fuzzing' 카테고리의 다른 글
[번역] A Look at AFL++ Under The Hood (0) | 2024.04.12 |
---|---|
[하드웨어 해킹]OpenWrt 풀 시스템 퍼징 (1) | 2024.02.06 |
[하드웨어 해킹] shannon 퍼징 (0) | 2024.01.22 |
[하드웨어 해킹] QEMU 수정하기 (0) | 2024.01.21 |
[하드웨어 해킹] CVE-2011-0531 재현하기(실패) (0) | 2024.01.19 |