본문 바로가기

IT/System Hacking

AFL fuzz(american fuzzy lop) Fuzzing Tool 사용하기

/* 
written by kaspy (kaspyx@gmail.com)
*/ 

AFL(American fuzzy lop) Fuzz tool 이란 프로그램에 무작위의 데이터를 입력하게하여 버그 및 취약점을 찾아주는 자동화된 툴이라고 보면 된다.

일명 퍼징(fuzzing) 기법을 사용하며, 가장 큰 특징이라면 소스코드가 주어질시에, 컴파일시에 AFL 툴이 입력받는 소스코드 루틴을 찾아줘서 인풋값에 대한 무작위 데이터 생성의 효율성을 가지고 있다. 대신 단점이라면, 소스코드가 없는 black box 상태의 fuzzing은 어렵다는점이다.

http://lcamtuf.coredump.cx/afl/ 사이트의 내용을 참고하여 정리한 내용이다.


1. AFL fuzzer 소스코드 다운로드 및 컴파일

사용환경 : linux 계열

소스코드 및 컴파일은 간단하다.

wget http://lcamtuf.coredump.cx/afl/releases/afl-latest.tgz 

tar -xvf afl-latest.tgz

cd afl-1.96b/

make all

make install


2. AFL fuzzer 사용법

자세한 내용은 다운받은 AFL 디렉토리에 README를 보면 잘나와있다.

AFL을 이용한 Fuzzing 방법은 대략적으로 아래와같다.

AFL 설치 -> Afl 컴파일러와 함께 Fuzzing할 바이너리에 대한 소스코드 컴파일 -> AFL Fuzzing start -> Segmentation fault 나온 inputcase 조사하여 버그 및 취약점 파악 

testcase가 반드시 있어야하는데, 이것은 타겟 바이너리에 임의의 입력값을 넣은뒤에 새로운 path가 생기면 거기에 대한 mutation 우선순위를 높여서 fuzzing의 효율을 높인다.

alf-fuzzer 디렉토리의 testcases 라는 디렉토리에 가보길 바란다. 여러가지 파일에 대한 input case가 있을것이다.


몸풀기로 간단한 fuzzing을 해보자, afl 디렉토리 아래에 test-instr.c 라는 파일이 있을것이다. 그것을 대상으로 fuzzing을 해보자



굉장히 간단한 코드이다. 이소스코드를 afl-gcc와 함께 컴파일하여 fuzzing을 할것이다. (만약 대상이 c++이라면, afl-g++을 이용해야한다.)

1) afl을 이용한 컴파일

./afl-gcc -o test-instr test-instr.c 



위와같이 컴파일시에 afl 메시지도 같이 나와야 잘된것이다.


2) Afl fuzzing 하기


afl-fuzz라는 바이너리로 fuzzing을 한다. 전반적인 사용법은 아래와 같다.


- 인풋 데이터가 Standard input이면


./afl-fuzz -i "Testcase 디렉토리" -o "결과가 만들어진 디렉토리 이름" "Fuzzing할 바이너리 이름" "파라미터이름..."

$ ./afl-fuzz -i testcase_dir -o findings_dir /path/to/program [...params...]


- 인풋 데이터가 파일이면


./afl-fuzz -i "Testcase 디렉토리" -o "결과가 만들어진 디렉토리 이름" "Fuzzing할 바이너리 이름" @@

$ ./afl-fuzz -i testcase_dir -o findings_dir /path/to/program @@


그렇다면 위의 test-instr 파일은 argv는 받지 않고 인풋을 키보드 등으로 입력받으니 첫번째 케이스로 하면 된다.

Test case 디렉토리는 afl 디렉토리의 ./testcases/other/text로 지정할것이고, 결과 디렉토리는 afl-out 디렉토리를 만들어서 이걸로 지정해줄것이다.

 ./afl-fuzz -i ./testcases/others/text/ -o ./afl-out/ ./test-instr


그런데 실행해보면 아래와 같은 에러가 출력될것이다.


추가적인 정보를 보니 아래와같이 명령어를 입력하라고한다, 그대로 입력하고 원래 afl-fuzz 명령어를 입력하면 잘될것이다.

echo core >/proc/sys/kernel/core_pattern

(* 만약 Permission 에러가 출력되면 sudo -s 등으로 슈퍼 계정으로 전환후 위의 명령어를 입력하도록 한다.)


total paths가 항상 1보다 크게 나와야 잘 실행되는것이다.



3) 결과 파일 분석하기



 위에서 fuzzing한 결과는 afl-out 디렉토리로 지정했었다. 디렉토리로 가보면, crashes, hangs, queue 디렉토리가 만들어져있는데, 여기서 crashes는 실제 sig fault (프로그램오류)등이 나왔을때의 unique 인풋 파일이고, queue 디렉토리는 각 path 별 입력값들 그리고 hangs는 지정된 시간을 지났을때까지 멈췄었던 인풋 데이터 case를 볼수있다.

유심히 봐야할것은 crashes 라는 디렉토리 이다. 그러나 이샘플에서는 실질적으로 crash가 발생하지는 않는다. 그냥 2개 path에 대한 input 값만 볼수있다. 


3. AFL Fuzzer 사용하기

좀더 practical한 설명을 이어가도록 하겠다, 리눅스에는 많은 오픈소스 프로젝트들이있다. 이런것들을 대상으로 fuzzing을 해보자.

우선 Fuzzing할 바이너리의 소스코드가 필요하다. 나는 e2fsprogs 라는 리눅스 유틸 바이너리를 대상으로 설명을 하도록 하겠다.

아래의 소스코드를 다운받도록 하자.

e2fsprogs-1.42.tar.gz


다운 받은 압축 파일을 풀어서 해당 디렉토리로 이동한다, 


e2fsprogs 리눅스 유틸은 여너 오픈소스와 마찬가지로 configure -> make all의 순서로 컴파일 된다.


configure 할때 afl-gcc 컴파일러를 등록한후에, make all 명령어로 컴파일&빌드하면 된다.


나는 아래와 같이 입력하였다.


cd e2fsprogs-1.42/

./configure CC="/home/kaspyx/afl-1.96b/afl-gcc"


"./configure" 를 실행하면 뭔가 세팅정보등이 설정되면서 글자들이 주르륵 올라온다. 


아래와 같이 afl-gcc와 관련된 (색깔있는) 문자들이 출력되어야 성공적으로 컴파일러가 등록된것이다.


이제 "make all"을 실행하면, afl-gcc와 함께 컴파일이 시작될것이다. 


마찬가지로, 컴파일이 성공하는지 컴파일 도중 afl 메시지가 뜨는지 잘 확인하도록 하자.



이제 컴파일이 성공하였다면, afl-fuzzer를 이용한 fuzzing을 하기위한 준비는 다된것이다.