为什么不叫高级篇,因为高级的我也不会
主要讲一下更贴近实际的用法吧
!!!仅大标题1完成,全片未完待续!!!
对DLL进行Fuzz
理论测试
代码还是上一篇提到的代码,依旧是32位,只不过溢出部分写在DLL里面
dll.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #include <stdio.h>
__declspec(dllexport) void vuln(char *FileDir) { char password[6] = "ABCDE"; char str[6]; FILE *fp; if(!(fp=fopen(FileDir,"r"))){ printf("Open Failed\n"); exit(0); } fgets(str, 0x1000, fp);
str[5]='\0'; if(strcmp(str,password)==0) printf("OK.\n"); else printf("NO.\n"); }
|
编译
1
| gcc -shared -o mydll.dll dll.c
|
main.c
1 2 3 4 5 6 7 8 9 10 11 12 13
| #include <stdio.h>
__declspec(dllimport) void vuln();
int main(int argc, char *argv[]) { if (argc != 2){ printf("Usage: ./HelloWorld.exe FileName\n"); return 0; } vuln(argv[1]); return 0; }
|
1
| gcc -o main main.c mydll.dll
|
不想联合编译的话也可以使用GetProAddress
来编写如下harness
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 31 32
| #include <stdio.h> #include <windows.h> typedef DWORD(__cdecl *pvuln)(char* aFileName); pvuln vuln = NULL;
extern "C" __declspec(dllexport) int main(int argc, char *argv[]) { char mydll_path[] = "D:\\HackTools\\Fuzz\\WinAFLFuzz\\testcase\\dll\\mydll.dll"; if (argc != 2){ printf("Usage: ./HelloWorld.exe FileName\n"); return 0; }
static HMODULE hMyDLL = NULL; hMyDLL = LoadLibraryA(mydll_path); if(hMyDLL == NULL){ printf("Load DLL Failed\n"); goto END; } vuln = (pvuln)GetProcAddress(hMyDLL,"vuln"); if(vuln == NULL){ printf("Get Process Address Failed\n"); goto END; } vuln(argv[1]);
END: if(hMyDLL){ FreeLibrary(hMyDLL); } return 0; }
|
开始插桩看看
1 2 3 4 5 6 7 8
| D:\HackTools\Fuzz\__FuzzWork\dynamorio\build_Win32\bin32\drrun.exe ^ -c D:\HackTools\Fuzz\__FuzzWork\winafl\build_Win32\bin\Release\winafl.dll -debug ^ -debug ^ -coverage_module mydll.dll ^ -target_module main.exe ^ -target_offset 0x16B0 ^ -fuzz_iterations 10 -nargs 2 -- ^ main.exe .\in\password.txt
|
开始fuzz
1 2 3 4 5 6 7 8 9 10
| afl-fuzz.exe ^ -i .\in ^ -o .\out ^ -D "D:\HackTools\Fuzz\__FuzzWork\dynamorio\build_Win32\bin32" ^ -I 100000+ -t 90000+ -- ^ -coverage_module mydll.dll ^ -target_module main.exe ^ -target_offset 0x16B0 ^ -fuzz_iterations 5000 -nargs 2 -- ^ main.exe @@
|
瞬间找到crash
样本长这样
这次尝试使用x32dbg分析
得到EXP
1 2 3 4 5 6 7 8 9 10 11 12 13
| payload = b"" shellcode = b""
offset = b"A"*(0x12c-len(shellcode)-32) NSEH = b"\xeb\x06\x90\x90" gadget = b"\xEA\x23\x40\x00" self_gadget = b"\x89\xE0\x05\x24\x06\x00\x00\xFF\xE0" payload = b"\xaa"*32+shellcode+offset+NSEH+gadget+self_gadget
with open("password.txt","wb") as f: f.write(payload)
|
要点就是:Fuzz的时候和插桩的时候加上-coverage_module <你的dll>
实际测试
你已经学会了1+1=2,请证明费马大定理吧,为了统一和方便,这里也用看雪里面的一篇文章
使用winafl对迅雷的torrent解析逻辑进行fuzz
首先是找到合适的软件,然后知道他那个功能是在那个dll中的,你可以使用ProcessMonitor
查看(俗称procmon
),截图没有,特征就是当你打开一个.torrent
文件后,thunder.exe
会马上加载AssisstantTools.dll
。通过查看导出表可以找到一些可以测试的函数,这里我测试的是XL_ParseTorrentFile
查看导入表可以看到依赖的P2PBase.dll
所以fuzz的时候也要加上,开始编写harness,你可以用那篇文章里面的,但是我这里就很慢,
原文文章中的harness由于using
附近的代码只在c++11
中支持,所以使用gcc编译报错的可以尝试加上-std=c++11
如果你使用的是下面我编写的harness,那么直接编译就可以了
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| #include <stdio.h> #include <windows.h>
typedef DWORD(__cdecl *pXL_ParseTorrentFile)(CHAR* aFileName, PVOID* a1); pXL_ParseTorrentFile XL_ParseTorrentFile = NULL; typedef DWORD(__cdecl *pXL_ReleaseTorrentFileInfo)(PVOID a1); pXL_ReleaseTorrentFileInfo XL_ReleaseTorrentFileInfo = NULL;
extern "C" __declspec(dllexport) void fuzz_method(char *FilePath){ PVOID a1 = NULL; XL_ParseTorrentFile(FilePath, &a1); if (a1) { XL_ReleaseTorrentFileInfo(a1); } return; }
int main(int argc, char *argv[]) { if (argc != 2){ printf("Usage: ./HelloWorld.exe FileName\n"); return 0; } static HMODULE hMyDLL = NULL; hMyDLL = LoadLibraryA("AssistantTools.dll"); if(hMyDLL == NULL){ printf("Load DLL Failed\n"); goto END; } XL_ParseTorrentFile = (pXL_ParseTorrentFile)GetProcAddress(hMyDLL, "XL_ParseTorrentFile"); if(XL_ParseTorrentFile == NULL){ printf("Get Process Address Failed\n"); goto END; } XL_ReleaseTorrentFileInfo = (pXL_ReleaseTorrentFileInfo)GetProcAddress(hMyDLL, "XL_ReleaseTorrentFileInfo"); if(XL_ReleaseTorrentFileInfo == NULL){ printf("Get Process Address Failed\n"); goto END; }
fuzz_method(argv[1]);
END: if(hMyDLL){ FreeLibrary(hMyDLL); } printf("Done\n"); }
|
你可以用drrun -t drcov --
来测试看是不是使用成功,之后使用drrun
测试
1 2 3 4 5 6 7 8
| "D:\HackTools\Fuzz\__FuzzWork\dynamorio\build_Win32\bin32\drrun.exe" ^ -c winafl.dll -debug ^ -coverage_module P2PBase.dll ^ -coverage_module AssistantTools.dll ^ -target_module fuzz_program.exe ^ -target_offset 0x11ef ^ -fuzz_iterations 10 -nargs 2 ^ -- fuzz_program.exe "D:\HackTools\Fuzz\WinAFLFuzz\testcase\thunder_fuzzer\testin\ubuntu-18.04.5-desktop-amd64.iso.torrent"
|
-
问题1:
如果你使用的Dynamorio
是大于 8.0.0-1版本的,很大概率会出现错误类似于下面
这种情况就是生成覆盖率文件是对的,但是测试的时候当程序进行IAT导入的时候,在dynamorio
中的harness崩溃了,所以程序还没有进入entry
入口点函数就直接寄了。这个错误很有意思,加载类似ntdll.dll
或者自己在windows上写的DLL(哪怕无符号)都可以,当harness中的LoadLibrary
载入其他DLL的时候(比如某个软件的ffmpeg.dll
)也会报错。
这个问题我解决了一天也没有解决,到是在看雪找了一个和我一样的帖子
https://bbs.kanxue.com/thread-274169.htm
最后我的解决方法是更换到dynamorio 8.0.0-1版本过后重新编译就行了
-
问题2:
当你使用target_method
的时候,程序找不到该方法,这在你进行测试winafl案例的时候很常见,原因是该方法没有进行导出,在函数前面加上extern "C" __declspec(dllexport)
就行了
首先就是缩减testcase
1
| python "D:\HackTools\Fuzz\__FuzzWork\winafl\winafl-cmin.py" --working-dir "D:\HackTools\Fuzz\__FuzzWork\winafl\build_Win32\bin\Release" -D "D:\HackTools\Fuzz\__FuzzWork\dynamorio\build_Win32\bin32" -t 9000 -i "D:\HackTools\Fuzz\WinAFLFuzz\testcase\thunder_fuzzer\testin" -o "D:\HackTools\Fuzz\WinAFLFuzz\testcase\thunder_fuzzer\in" -coverage_module AssistantTools.dll -coverage_module P2PBase.dll -target_module fuzz_program.exe -target_method fuzz_method -nargs 1 -- fuzz_program.exe @@
|
然后开始fuzz,开启一个Master吧
1 2 3 4 5 6 7 8 9 10 11 12
| afl-fuzz.exe ^ -M master ^ -i "D:\HackTools\Fuzz\WinAFLFuzz\testcase\thunder_fuzzer\in" ^ -o "D:\HackTools\Fuzz\WinAFLFuzz\testcase\thunder_fuzzer\out" ^ -D "D:\HackTools\Fuzz\__FuzzWork\dynamorio\build_Win32\bin32" ^ -I 100000+ -t 9000 -- ^ -coverage_module AssistantTools.dll ^ -coverage_module P2PBase.dll ^ -target_module fuzz_program.exe ^ -target_method fuzz_method ^ -fuzz_iterations 5000 -nargs 1 -- ^ fuzz_program.exe @@
|
自己改写的harness确实快,但也不至于一下子就跑出来,这里我用旧版本的迅雷试了下
也就是一个被修复的÷0报错(EXCEPTION_INT_DIVIDE_BY_ZERO)
昨天16h高强度修复问题1,暂时更新到这里