Debugging Tools for Windows 만 선택해서 설치
한글에는 security module인 HncAppShield가 있다. HncAppShield는 파일 내용을 파싱해서 사용자에게 문서 내용을 보여주기 전에 .hwp 파일을 스캔해서 파일 내 악성 페이로드가 있는지 확인한다.
이 module을 fuzzing target으로 잡았다.
HncAppShield.dll 파일이 있는 프로그램을 설치하면 된다.
https://www.hancom.com/cs_center/csDownload.do
HncAppShield.dll이 파일 내용 보여주기 전 내용 확인하는 모듈이기 때문에 뷰어에도 있을 것이다. 따라서 한컴오피스 2022 뷰어를 설치했다.
target module은 C:\Program Files (x86)\Hnc\Office NEO\HOfficeViewer96\Bin 경로에 위치한다.
앞서 WinAFL 환경구축 및 사용법 글에서 적은 내용으로 리마인드하자면 다음의 조건이 있다.
이 조건을 충족하는 target 내 함수가 있는지 분석하여 선정해야 한다.
1. 함수 내에서 input 파일을 열어야 함
2. input 파일 파싱할 수 있어야 함
3. 함수 내에서 input 파일 닫아야 함
4. 리턴까지 정상 실행되어야 함
IDA로 HncAppShield.dll 파일을 연다. permission denied 오류가 발생하면, HncAppShield.dll 파일을 바탕화면 등에 복사해서 해당 경로에서 IDA로 파일을 연다. winafl 경로에 HncAppShield.dll 파일을 복사한 후 열었다.
(또는 IDA를 관리자 권한으로 실행한 후 원본 dll 파일을 연다.)
exports 테이블을 확인해보자.
인자로 file path를 받는 AppShield_InpectMalware() 함수를 WinAFL로 fuzz할 함수로 선택했다. file path만 인자로 받기 때문에 인자가 적어 harness 작성이 쉽다.
HncAppShield는 DLL이므로, DLL을 로드하고 input과 함께 함수를 호출할 수 있는 harness (loader)를 작성해야 한다. harness는 WinAFL에서 afl-fuzz.exe로 fuzzing 시 주면 된다.
#include <stdio.h>
#include <Windows.h>
#include <iostream>
extern "C" __declspec(dllexport) __declspec(noinline) int fuzz_hwp(wchar_t* hwp);
typedef int(*INSPECT)(wchar_t* filename);
INSPECT AppShield_InspectMalware;
wchar_t* charToWChar(const char* text)
{
size_t size = strlen(text) + 1;
wchar_t* wa = (wchar_t*)malloc(sizeof(wchar_t) * size);
mbstowcs(wa, text, size);
return wa;
}
int fuzz_hwp(wchar_t* filename)
{
AppShield_InspectMalware(filename);
return 0;
}
int main(int argc, char** argv)
{
HINSTANCE HncAppShield = LoadLibrary("C:\\Program Files (x86)\\Hnc\\Office NEO\\HOfficeViewer96\\Bin\\HncAppShield.dll");
int isDetected = 0;
if (HncAppShield == NULL) {
fprintf(stderr, "Error: Unable to open target dll\n");
return -1;
}
AppShield_InspectMalware = (INSPECT)GetProcAddress(HncAppShield, (LPCSTR)1);
//printf("function ptr: 0x%x\n", AppShield_InspectMalware);
isDetected = fuzz_hwp(charToWChar(argv[1]));
printf("[Malware result] %d\n", isDetected);
return isDetected;
}
cmake_minimum_required(VERSION 3.0)
get_filename_component(ProjectId ${CMAKE_CURRENT_SOURCE_DIR} NAME)
string(REPLACE " " "_" ProjectId ${ProjectId})
project(${ProjectId})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
file(GLOB SOURCES *.cpp)
add_executable(${PROJECT_NAME} ${SOURCES})
CMakeLists.txt 파일이다. cmake를 사용해서 32bit로 컴파일한다.
cd targettest
mkdir build
cd build
cmake -G"Visual Studio 17 2022" -A Win32 ..
cmake --build . --config Release
32bit executable로 컴파일하기 때문에 Win32을 주고, 그 뒤에는 source 상대 경로를 준다. build 상위 경로에 있으므로 ..으로 줬다.
컴파일 결과 build\bin\Release 경로에 harness 실행 파일이 생성된다.
cd %DynamoRIO경로%\\bin32
drrun.exe -c "%winafl경로%\\build32\\bin\\Release\\winafl.dll" -debug -target_module harness.exe -coverage_module "%타겟DLL경로%" -target_method fuzzme -fuzz_iterations 10 -nargs 1 -- "%harness경로%" "%파일경로%"
drrun.exe -c는 configure-and-run 명령어로 harness가 퍼징에 적합한지 검사한다.
cd C:\Users\johan\DynamoRIO-Windows-9.0.19174\DynamoRIO-Windows-9.0.19174\bin32
drrun.exe -c "C:\Users\johan\winafl\build32\bin\Release\winafl.dll" -debug -target_module targettest.exe -coverage_module "C:\Program Files (x86)\Hnc\Office NEO\HOfficeViewer96\Bin\HncAppShield.dll" -target_method fuzz_hwp -fuzz_iterations 10 -nargs 1 -- "C:\Users\johan\targettest\build\bin\Release\targettest.exe" "C:\Users\johan\targettest\input\test.txt"
테스트 끝나면 DynamoRIO의 bin32 경로에 테스트 로그가 남으며, iterations 옵션을 10으로 줬으므로 10번의 실행 로그가 남고 “Everything appears to be running normally.” 로그가 남아있으면 harness를 퍼징에 사용할 수 있다.
https://github.com/Cisco-Talos/clamav-fuzz-corpus/tree/master/scantype/HWP3
위 github에 올라온 hwp seed corpus를 사용한다. (한컴오피스가 없기 때문,,😓)
AFL 문서에는 큰 corpus가 있으면 afl-cmin을 사용해서 target 바이너리에서 다른 code path를 가는 파일들의 집합을 식별하도록 할 수 있다. 퍼저 실행 시 WARNING으로 tet caes가 useless 할 수 있어서 smaller set을 사용하라고 출력되는데, afl-cmin.py를 사용하면 seed corpus를 minimize할 수 있다.
winafl-cmin.py -D D:\\DRIO\\bin32 -t 100000 -i in -o minset -covtype edge -coverage_module m.dll -target_module test.exe -target_method fuzz -nargs 2 -- test.exe @@
winafl-cmin.py -D C:\\Users\\johan\\DynamoRIO-Windows-9.0.19174\\DynamoRIO-Windows-9.0.19174\\bin32 -t 100000 -i C:\\Users\\johan\\targettest\\input -o C:\\Users\\johan\\targettest\\mininput -covtype edge -coverage_module targettest.exe -target_module targettest.exe -target_method fuzz_hwp -nargs 1 -- C:\\Users\\johan\\targettest\\build\\bin\\Release\\targettest.exe @@
-i input 파일 directory
-o minimized corpus 저장할 directory
-t 실행 timeout (ms)
-D DynamoRIO directory
-covtype basic block만 추적하는 기본 coverage tracker
@@ WinAFL에서 생성하는 파일이름 대체
현재 seed corpus가 작지만, seed corpus 크기가 크면 corpus minimization 효과가 클수도 있을 것 같다.
cd C:\\Users\\johan\\winafl\\build32\\bin\\Release
afl-fuzz.exe -i C:\\Users\\johan\\targettest\\input -o C:\\Users\\johan\\targettest\\output -D C:\\Users\\johan\\DynamoRIO-Windows-9.0.19174\\DynamoRIO-Windows-9.0.19174\\bin32 -t 1000 -- -coverage_module targettest.exe -fuzz_iterations 1000 -target_module targettest.exe -target_method fuzz_hwp -nargs 1 -- C:\\Users\\johan\\targettest\\build\\bin\\Release\\targettest.exe @@
-i input
-o fuzzing 결과
@@ input 대체
첫 번째 -- 다음에는 instrumentation option을 준다.
두 번째 -- 이 다음으로 실행할 명령어 준다. harness에 input file을 인자로 준다.
-fuzz_iterations 1000 WinAFL이 fuzz_hwp 함수 1000번 실행 후 프로세스 재시작
-t 1000 timeout 1000ms (각 test case 실행 1000ms 후 time out)
-nargs 1 실행하는 파일의 인자 수 (여기에서는 harness 파일의 인자 수)
afl-fuzz 명령어 인수를 줄 때 -coverage_module , -target_module 모두 harness 파일명인 targettest.exe로 바꿔서 퍼저가 정상적으로 실행될 수 있었다. coverage module이 dll 파일명으로 주는걸 봐서 target dll로 주면 되는건줄 알았는데, harness에서 target dll을 로드해서 target function을 실행하므로 harness를 주면 됐다.
[Fuzzing] WinAFL target function offset 자동으로 넣어주기 (0) | 2022.07.08 |
---|---|
[Fuzzing] WinAFL 환경구축 및 사용법 (0) | 2022.07.08 |
[Fuzzing] AFL fuzzing dact (0) | 2022.06.28 |
[Fuzzing] AFL++ 설치 (0) | 2022.06.28 |
[Fuzzing] AFL 설치 (0) | 2022.06.28 |