티스토리 뷰

Failure Observation Engine (FOE) 퍼저?

CERT에서 만든 바이너리 퍼징 도구.

파일을 여러가지 기법으로 변조하여 응용프로그램으로 실행하고 크래쉬 발생 시 이를 수집한다.

또한 windbg와 msec 모듈을 사용하여 크래쉬에 대한 EXPLOITABLE, PROBABLY EXPLOITABLE, .. 등 공격 가능성에 대해 분류해준다.

최신 버전은 BFF (Basic Fuzzing Framework) 와 FOE 퍼저가 합쳐져서 유용한 크래쉬에 대한 순위도 매겨진다.

https://www.cert.org/vulnerability-analysis/tools/foe.cfm?


이 퍼저를 이용해서 Windows 환경에서 퍼징을 돌려서 몇몇 취약점을 찾아냈었는데 안드로이드 앱에서 취약점을 찾고 싶어서 소스를 조금 수정했다.

아래는 그 과정에 대한 내용이다.






첫 번째, 패키지 확인하기


먼저, adb shell 로 접속하여 실행할 대상 어플리케이션의 패키지 이름을 확인한다.

pm list package


다음으로는 해당 어플리케이션을 실행시키고 클래스 이름을 확인한다.

dumpsys activity | grep [패키지 이름]


패키지 이름과 클래스 이름을 확인했으면 어플을 실행시켜본다.

am start -n [패키지 이름]/[클래스 이름]


정상적으로 실행이 된다면 파일을 해당 어플로 열어본다. (여기선 hwp 파일을 사용했다)

adb push [파일 명] /sdcard/Download/[파일 명]

adb shell am start -a android.intent.action.VIEW -d "file:///sdcard/Download/[파일명]" -t application/hwp


여기가지 실행이 된다면 이제 FOE 퍼저의 소스코드를 수정한다.



두 번째, FOE 퍼저 소스 수정하기


BFF와 합쳐지기 전의 FOE 퍼저를 사용했다.

퍼저를 다운받으면 기본적으로 C:\FOE2 폴더가 생긴다.

여기에 또 여러가지 폴더들이 있는데 이중에서 certfuzz 디렉토리를 선택하고 fuzzers 디렉토리로 들어가면 __init__.py 파일을 찾을 수 있다.

이 파일 안에는 Fuzzer 라는 클래스가 선언되어 있다.

FOE 가 사용하는 퍼징 방법은 bytemut, swap, copy, bitmut 등 여러 방법을 사용하고 있는데 이는 "C:\FOE2\configs\foe.yaml"의 약 74번째 줄에서 확인할 수 있다.

Fuzzer 클래스는 yaml 파일에서 설정한 퍼징 방법에 따라 생성할 퍼저의 부모 클래스로 사용된다.

"C:\FOE2\certfuzz\fuzzers" 디렉토리에 퍼징 방법에 따른 각 퍼저 클래스들이 서로 다른 파일에 선언되어 있다.

__init__.py 파일 외에 아무 파일이나 선택해서 열어보면 클래스 안에 _fuzz 함수가 선언 되어 있는 것도 확인할 수 있다.

다시 __init__.py 파일로 돌아와서, 약 159 번째 줄의 fuzz 함수를 보자.

실제 퍼징을 수행하는 _fuzz 함수를 호출하기 전에 _prefuzz 함수를 호출하고, _fuzz 함수 호출이 끝나면 _postfuzz 함수를 호출한다.

퍼저에서 생성된 파일을 모바일로 전달하기 위해 _postfuzz를 수정했다.


_postfuzz 함수는 약 188 번째 줄에 선언되어 있고 내용은 채워져있지 않다.

여기에 아래 내용들을 채워넣자.


cmd = "adb -s [디바이스 이름(adb devices로 확인)] push "+self.output_file_path+" /sdcard/fuzz/"+self.basename_fuzzed

os.system(cmd)

self.output_file_path 에는 퍼징이 수행된 파일이 저장되는 임시 폴더의 경로와 파일 이름이 저장되어 있다.

퍼징이 수행된 파일의 이름은 "해쉬값-iteration 번호"로 이루어져 있고 self.basename_fuzzed 에 저장되어 있다.

위 코드는 퍼징된 파일을 모바일 디바이스의 "/sdcard/fuzz/" 디렉토리에 같은 이름으로 넣는 코드이다.


어플리케이션을 실행하기 전에, 미리 실행되고 있을지 모르는 해당 어플리케이션을 중지시킨다.

cmd = "adb -s [디바이스 이름] shell am force-stop [패키지 이름]"

os.system(cmd)


이제 깨끗한 환경에서 어플리케이션을 이용하여 퍼징된 파일을 연다.

이때, hwp 파일을 열 수 있는 어플리케이션이 여러개인 경우, 퍼징 대상 어플을 기본 어플로 미리 설정해줘야 한다.

cmd = ''

cmd += "adb -s [디바이스 이름] shell am start -a android.intent.action.VIEW -d \""

cmd += "file:///sdcard/fuzz/"+self.basename_fuzzed

cmd += "\" -t application/hwp"

os.system(cmd)

time.sleep(5)

파일이 열리는 시간이 조금 느려서 5초간 기다리게 했다.


이제 크래쉬 여부를 확인할 차례다.

(crash_hash, is_crash) = self.check_crash()

크래쉬 여부를 확인하는 check_crash() 함수를 새로 만들었다.

안드로이드는 새로운 어플리케이션을 실행할 때, zygote 프로세스를 fork 한 후, 복제된 자식 프로세스에 어플리케이션을 동적으로 로딩한다.

이렇게 생성된 어플리케이션은 기존의 zygote 프로세스가 구성해놓은 라이브러리 및 리소스에 대한 링크 정보를 그대로 사용하기 때문에 빠르게 실행이 가능하다.

모든 어플리케이션은 zygote 프로세스 위에서 돌아가기 때문에 어플리케이션의 크래쉬 여부를 알기 위해서는 zygote 프로세스를 감시하면 된다.

zygote의 자식 프로세스가 위험 시그널로 인해 종료되었을 경우 크래쉬로 판단한다.

또는 logcat의 정보를 파싱하여 크래쉬를 판단한다.


if is_crash == False:

    print("No Crash")

else:

print("Found Crash")

self.save_crash(self.output_file_path, crash_hash)

os.system("adb -s [디바이스 이름] shell su -c rm /sdcard/fuzz/"+self.basename_fuzzed)

크래쉬가 맞다면 해당 파일을 특정 디렉토리로 옮겨서 저장해줄 save_crash() 함수를 새로 만들었다.

크래쉬를 유발시킨 hwp 파일과 logcat의 정보를 파일로 저장한다.


여기까지 진행이 되었다면 "C:\FOE2\certfuzz\campaign\iteration.py" 파일의 약 388 번째 줄(if self.runner)부터 약 406 번째 줄(if analysis_needed)까지, PC 프로그램을 실행시키는 부분이므로 주석처리한다.


퍼저를 실행시켜보면 크래쉬가 전혀 터지질 않는다.

__init__.py 로 다시 돌아가서 약 163 번째 줄에서 self._postfuzz() 가 호출되는데, 퍼징된 파일이 기록되는 시점은 그보다 약 4줄 아래에 있는 self.write_fuzzed() 가 호출되었을 때다.

163 번째 줄의 self._postfuzz() 를 주석처리하고, write_fuzzed() 의 return 직전에 _postfuzz() 를 호출하도록 한줄을 추가했다.


다시 실행시켜보면 크래쉬가 빵빵 터진다 ^-^乃


댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함