tmxklab

Fuzzing 정리 본문

Fuzzing

Fuzzing 정리

tmxk4221 2021. 1. 5. 19:08

0. 목차


1. Fuzzing

1.1 Fuzzing

  • 1989년 WIisconsin-Madison대학에서 Barton Miller교수와 학생들이 개발한 기법
  • Fuzz Testing 또는 Fuzzing은 유효하지 않거나 임의의 데이터를 소프트웨어 시스템에 넣어 코딩 오류와 보안 허점을 발견하는 소프트웨어 테스트 기술
  • Fuzzing의 목적은 자동화 또는 반자동 기술을 사용하여 데이터를 삽입하고 시스템 충돌 또는 내장 코드 오류 등과 같은 다양한 예외에 대한 시스템을 테스트하는 것
  • 브라우저, 시스템 커널, 대부분의 API 및 기타 응용 프로그램 등 입력이 존재하는 거의 모든 소프트웨어가 퍼징의 대상이 될 수 있음

1.2 퍼징을 하는 이유

  • 퍼징이 직접 수동 테스트하는 것보다 시간과 노력이 더 적게 듬
  • 특히, 애플리케이션이 복잡할수록 많은 버그와 attack surface가 생기는데 이에 대해 수동 테스트보다 퍼징이 효율적인 방식일 수 있음
  • 무조건적으로 퍼징이 좋은 것은 아니다. 퍼징과 수동 테스트의 조합이 최적

1.3 일반적인 문제

  • 응용 프로그램 또는 퍼저가 찾아야하는 버그의 유형에 따라 세팅하는데 많은 시간이 걸릴 수 있음
  • 익스 가능한 크래시를 발생하기도 하지만 언익스나 오탐 이런 것도 발생하기 때문에 유효한지 검사하기 위해 검토 프로세스가 필요

1.4 퍼징 준비

1) 입력을 받는 타겟 선정

→ 응용 프로그램이 복잡할수록 퍼저로 버그를 찾을 가능성이 높음

2) 찾고자 하는 버그의 유형

→ 익스 가능한 취약점을 나타내는 크래쉬가 언제 발생했는지 알아야 함

3) 퍼저 선정

→ 타겟을 선정하고 어떤 유형의 버그를 찾을지에 대해서 고민했으면 이제 퍼저를 선정한다.

→ 직접 퍼저를 만들 수도 있지만 다른 다양한 퍼저를 선택할 수 있다.


2. Architecture of a typical fuzzer

일반적으로 퍼저는 다음 그림과 같이 세 가지 구성요소로 구성된다. Test Case Generator가 입력 값을 만들고 Worker가 주어진 입력 값을 통해 프로그램을 실행시키고 Logger가 프로그램이 돌면서 버그 분석에 필요한 정보를 기록한다.

추가적으로 세 가지 구성요소를 컨트롤하고 상호작용을 관리하는 Server/Master가 존재한다.

Test Case Generator

  • 새로운 테스트 케이스를 생성하는 역할
  • 테스트 케이스 생성기로 입력 구조를 파악하고 그것에 맞추어 알맞게 테스트 케이스를 생성하는 smart fuzzer와 입력 구조를 파악하지 않고 무작위로 테스트 케이스를 생성하는 dumb fuzzer가 존재

Worker

  • 테스트 케이스 생성기가 제공하는 테스트 케이스를 실행하고 예상치 못한 동작을 인식하는 역할

Logger

  • 발견된 모든 crash와 각각의 테스트 사례를 기록하거나 저장하는 역할
  • 로깅은 crash 스택 추적을 통해 crash 분석을 쉽게 할 수 있음
  • crash로 이어지는 테스트 케이스를 기록하여 이후에 crash를 재현할 수 있게 한다.


3. types of fuzzing

다양한 분류 중에서 퍼징을 분류하는 가장 기본이 되는 방법은 테스트 케이스를 어떻게 생성하는지에 따라 분류하는 것이다. 즉, 퍼징을 위해 입력 값을 어떻게 조절하는지에 따라 다음과 같이 크게 두 가지 방식이 존재한다.

  • Mutation Based Fuzzing(Dumb Fuzzing)
  • Generation Based Fuzzing(Smart Fuzzing)

3.1 Mutation Based Fuzzing(Dumb Fuzzing)

Dumb Fuzzing은 새로운 테스트 케이스를 생성하기 위해 입력 구조의 모델이 필요하지 않는 테스트 케이스 생성기이다. 따라서, 이러한 방식은 데이터 형식이나 입력 구조에 대한 명확한 이해가 어려울 때 사용한다.

장점)

  • 쉽고 빠르게 구현이 가능하다.
  • 입력 구조에 대한 분석을 하지 않아도 된다.

단점)

  • 입력에 미리 정의되 구조가 필요하거나 체크섬이 포함되어 있는 경우 유효한 입력을 생성하는데 어려움이 존재한다.

3.2 Generation Based Fuzzing(Smart Fuzzing)

Smart Fuzzing은 Dumb Fuzzing과 다르게 입력 구조의 모델을 완전히 이해한 상태에서 수행하는 퍼징이다. 입력 구조의 모델을 분석해 포맷에 맞춰 변형한 뒤 생성해 주어야 하므로 구현 난이도가 높다. 이러한 방식은 오피스 문서, 음원 파일 등 파일 포맷이 복잡한 프로그램 경우에는 파일 포맷을 어느 정도 맞춰주어야만 퍼징이 가능한 경우가 많기 때문에 Smart퍼징이 효율적인 경우가 많다.

장점)

  • 실제 프로그램에 더 높은 Code Coverage로 이어지는 유효한 입력 값을 생성한다.

단점)

  • 입력 모델에 대한 이해도가 선행되어야 한다.
  • 구현 난이도가 높아 준비하고 취약점을 찾기까지 시간이 걸린다.

+) Guided fuzzing

테스트 케이스 생성기로 생성된 테스트 케이스는 품질 차이가 크다. 테스트 케이스 생성기가 변형하거나 생성할 테스트 케이스를 결정하려면 일종의 지침이 필요하다. 가장 일반적인 지침은 Code Coverage를 넓히는 것이다. 이론적으로 더 많은 Code Coverage가 넓을 수록 더 많은 버그를 찾을 수 있기 때문이다.

→ Code Coverage에 관해 아래 참고자료 확인


4. Fuzzing Tools

Sanitizers

  • 트리거된 취약점 및 프로그램 stack trace를 포함하여 crash가 발생했을 때 광범위한 로그를 제공해주는 기능
  • 감지해야 하는 crash 유형에 따라 Sanitizers 선택
    • AddressSanitizer(ASan) : bof취약점 및 기타 메모리 문제 감지
    • ThreadSanitizer(TSan) : data race condition을 감지, 현재 베타 상태이며 과도한 메모리 오버 헤드가 발생
    • MemorySanitizer(MSan) : bss영역에 대한 읽기 엑세스 감지
    • UndefinedBehaviourSanitizer(UBSan) : integer overflow 또는 misalignment of pointers에 대해 감지

American Fuzzy Lop (AFL)

  • Coverage기반 mutation based fuzzer, dumb fuzzer
  • 테스트 케이스의 Code Coverage를 효율적으로 늘리기 위해 유전 알고리즘을 사용하는 Fuzzer

Peach Fuzzer

  • 대표적인 Smart Fuzzer
  • Mutation 방식과 Generation 방식을 둘 다 사용가능

libFuzzer

  • coverage-guide in-process fuzzing engine
  • In-process fuzzing은 한 프로세스에서만 발생하는 퍼징 기술

domato

  • DOM fuzzer

음... 다양한 퍼저들이 많은데 이후에 다양한 퍼저를 사용해보면서 내용을 추가해야겠따. 그리고 나중에 퍼저를 만들정도의 실력이 되면 개인적으로 퍼저를 만들어보는 것도 진행해보겠다.


5. references

5.1 Fuzzing 관련

5.2 fuzzer 계보 시각화 사이트

5.3 FuzzBench - fuzzer 평가 벤치마킹 Tool

5.4 Code Coverage에 관한 글

Code Coverage 개념이 퍼징에 있어서 굉장히 중요한 개념이다. 이에 관해서 아래 링크에서 잘 설명되어 있다.

Comments