使用winafl对迅雷的torrent解析逻辑进行fuzz
2021-02-25 18:58:00 Author: mp.weixin.qq.com(查看原文) 阅读量:136 收藏

本文为看雪论坛优秀文章

看雪论坛作者ID:昵称好麻烦

一、漏洞挖掘目标

打开torrent文件时,迅雷会对torrent文件进行解析,得到需要下载的内容,所以想要对迅雷解析torrent文件的逻辑进行尝试二进制漏洞挖掘。

二、目标模块与接口

经过使用procmon抓包以及逆向分析,发现迅雷对torrent文件的解析流程在动态链接库AssistantTools.dll的导出函数XL_ParseTorrentFileW中。
所以目标模块就是AssistantTools.dll,接口就是XL_ParseTorrentFileW。

三、部署winafl环境

(1)winafl目录在“D:__workspace__\fuzz\winafl”
(2)dynamorio目录在“D:__workspace__\fuzz\dynamorio” 
注:编译winafl和dynamorio请参考这篇文章

四、编写fuzz主程序并编译

1. 源文件fuzz_program.cpp
#include <stdio.h>#include <Windows.h> #define ASSISTANTTOOLS_DLL "AssistantTools.dll" extern "C" __declspec(dllexport) VOID fuzz_method(CHAR * filePath); // AssistantTools.dllstatic HMODULE hAssistantTools = NULL;// AssistantTools!XL_ParseTorrentFileWsigned int __cdecl XL_ParseTorrentFileW(CHAR* aFileName, PVOID* a1);using Fun_XL_ParseTorrentFileW = decltype(&XL_ParseTorrentFileW);static Fun_XL_ParseTorrentFileW fun_XL_ParseTorrentFileW = NULL;// AssistantTools!XL_ReleaseTorrentFileInfoWvoid __cdecl XL_ReleaseTorrentFileInfoW(PVOID a1);using Fun_XL_ReleaseTorrentFileInfoW = decltype(&XL_ReleaseTorrentFileInfoW);static Fun_XL_ReleaseTorrentFileInfoW fun_XL_ReleaseTorrentFileInfoW = NULL; VOID fuzz_method(CHAR* filePath){    PVOID a1 = NULL;     fun_XL_ParseTorrentFileW(filePath, &a1);     if (a1)    {        fun_XL_ReleaseTorrentFileInfoW(a1);    }     return;} int main(int argc, char* argv[]){    CHAR assistantTools_path[MAX_PATH] = {0};    CHAR* pTemp = NULL;     if (2 != argc)    {        printf("Parameter Error\n");        goto End;    }     // 获取AssistantTools.dll的全路径    if(0 == GetModuleFileNameA(NULL, assistantTools_path, sizeof(assistantTools_path)))    {        printf("GetModuleFileNameA Error\n");        goto End;    }    pTemp = strrchr(assistantTools_path, '\\');    if(NULL == pTemp)    {        printf("strrchr Error\n");        goto End;    }    ++pTemp;    *pTemp = '\0';    strcat(pTemp, ASSISTANTTOOLS_DLL);     // 加载AssistantTools.dll并获取函数地址    hAssistantTools = LoadLibraryA(assistantTools_path);    if (NULL == hAssistantTools)    {        printf("LoadLibraryA fail: 0x%x\n", GetLastError());        goto End;    }    fun_XL_ParseTorrentFileW = (Fun_XL_ParseTorrentFileW)GetProcAddress(hAssistantTools, "XL_ParseTorrentFileW");    if (NULL == fun_XL_ParseTorrentFileW)    {        printf("GetProcAddress fail\n");        goto End;    }    fun_XL_ReleaseTorrentFileInfoW = (Fun_XL_ReleaseTorrentFileInfoW)GetProcAddress(hAssistantTools, "XL_ReleaseTorrentFileInfoW");    if (NULL == fun_XL_ParseTorrentFileW)    {        printf("GetProcAddress fail\n");        goto End;    }     fuzz_method(argv[1]); End:    if(hAssistantTools)    {        FreeLibrary(hAssistantTools);    }     return 0;}

2. 编译源文件fuzz_program.cpp得到fuzz_program.exe
g++ -g -o fuzz_program.exe fuzz_program.cpp

五、准备fuzz

1. 准备在目录“D:__workspace__\fuzz\test_winafl\thunder_torrent”下进行fuzz
2. 将AssistantTools.dll拷贝到目录下
(AssistantTools.dll来自“D:\softwares\Thunder Network\Thunder\Program\resources\bin\SDK\AssistantTools.dll”) 
3. 由于AssistantTools.dll依赖P2PBase.dll,所以也需要将P2PBase.dll拷贝到目录下
(P2PBase.dll来自“D:\softwares\Thunder Network\Thunder\Program\resources\bin\SDK\P2PBase.dll”) 
4. 将winafl.dll拷贝到目录下
(winafl.dll来自"D:__workspace__\fuzz\winafl\build_Win32\bin\Release\winafl.dll")
 
5. 准备一个语料库目录samples,里面塞满各种地方找来的torrent文件

6. 最后目录下如图所示:

六、生成覆盖率文件

1. 通过dynamorio工具对fuzz_program.exe在解析torrent文件时的执行流程进行污点跟踪,得到二进制的覆盖率文件,执行命令如下;

"D:\__workspace__\fuzz\dynamorio\build_Win32\bin32\drrun.exe" -t drcov -- "fuzz_program.exe" "D:\__workspace__\fuzz\test_winafl\thunder_torrent\samples\test.torrent"

2. 之后在当前目录下会看到生成的drcov前缀的log文件;

3. 使用32位ida打开AssistantTools.dll,使用ida插件lighthouse打开刚才生成的log文件;

4. 简单检查一下目标函数XL_ParseTorrentFileW的代码覆盖情况,绿色的为覆盖的部分;

七、对语料库samples最小化到minset目录下

"C:\Python27\python.exe" "D:\__workspace__\fuzz\winafl\winafl-cmin.py" --working-dir "D:\__workspace__\fuzz\winafl\build_Win32\bin\Release" -D "D:\__workspace__\fuzz\dynamorio\build_Win32\bin32" -t 9000 -i "D:\__workspace__\fuzz\test_winafl\thunder_torrent\samples" -o "D:\__workspace__\fuzz\test_winafl\thunder_torrent\minset" -coverage_module AssistantTools.dll -coverage_module P2PBase.dll -target_module fuzz_program.exe -target_method fuzz_method -nargs 1 -- "D:\__workspace__\fuzz\test_winafl\thunder_torrent\fuzz_program.exe" @@


可以看到,原本samples目录中有92个测试样本,最小化到minset目录后得到13个测试样本;

"D:\__workspace__\fuzz\dynamorio\build_Win32\bin32\drrun.exe" -c winafl.dll -debug -coverage_module AssistantTools.dll -coverage_module P2PBase.dll -target_module fuzz_program.exe -target_method fuzz_method -fuzz_iterations 10 -nargs 1 -- "D:\__workspace__\fuzz\test_winafl\thunder_torrent\fuzz_program.exe" "D:\__workspace__\fuzz\test_winafl\thunder_torrent\samples\test.torrent"

之后生成afl前缀的log文件,运行afl-fuzz.exe前设置的coverage_module参数和target_module参数的值只能从log文件中列出的模块里获取。

八、开始fuzz

计划使用一个master,两个slave分别为slave01和slave02;


1. master

"D:\__workspace__\fuzz\winafl\build_Win32\bin\Release\afl-fuzz.exe" -i "D:\__workspace__\fuzz\test_winafl\thunder_torrent\minset" -M master -o "D:\__workspace__\fuzz\test_winafl\thunder_torrent\result" -D "D:\__workspace__\fuzz\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 -- "D:\__workspace__\fuzz\test_winafl\thunder_torrent\fuzz_program.exe" @@


2. slave01

"D:\__workspace__\fuzz\winafl\build_Win32\bin\Release\afl-fuzz.exe" -i "D:\__workspace__\fuzz\test_winafl\thunder_torrent\minset" -S slave01 -o "D:\__workspace__\fuzz\test_winafl\thunder_torrent\result" -D "D:\__workspace__\fuzz\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 -- "D:\__workspace__\fuzz\test_winafl\thunder_torrent\fuzz_program.exe" @@

3. slave02

"D:\__workspace__\fuzz\winafl\build_Win32\bin\Release\afl-fuzz.exe" -i "D:\__workspace__\fuzz\test_winafl\thunder_torrent\minset" -S slave02 -o "D:\__workspace__\fuzz\test_winafl\thunder_torrent\result" -D "D:\__workspace__\fuzz\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 -- "D:\__workspace__\fuzz\test_winafl\thunder_torrent\fuzz_program.exe" @@


九、中断fuzz过程

Ctrl+C

十、恢复fuzz

恢复fuzz只需要将原命令的“-i”参数修改为“-”即可,其他参数不变;

1. master

"D:\__workspace__\fuzz\winafl\build_Win32\bin\Release\afl-fuzz.exe-i - -M master -o "D:\__workspace__\fuzz\test_winafl\thunder_torrent\result-D "D:\__workspace__\fuzz\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 -- "D:\__workspace__\fuzz\test_winafl\thunder_torrent\fuzz_program.exe" @@

2. slave01

"D:\__workspace__\fuzz\winafl\build_Win32\bin\Release\afl-fuzz.exe-i - -S slave01 -o "D:\__workspace__\fuzz\test_winafl\thunder_torrent\result-D "D:\__workspace__\fuzz\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 -- "D:\__workspace__\fuzz\test_winafl\thunder_torrent\fuzz_program.exe" @@

3. slave02

"D:\__workspace__\fuzz\winafl\build_Win32\bin\Release\afl-fuzz.exe" -i - -S slave02 -o "D:\__workspace__\fuzz\test_winafl\thunder_torrent\result" -D "D:\__workspace__\fuzz\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 -- "D:\__workspace__\fuzz\test_winafl\thunder_torrent\fuzz_program.exe" @@

十一、查看运行状态

1. 查看单个fuzzer的状态


以查看master的状态为例,将master状态输出到目录stat下;

"C:\python27-x64\python.exe" "D:\__workspace__\fuzz\winafl\winafl-plot.py" "D:\__workspace__\fuzz\test_winafl\thunder_torrent\result\master" "D:\__workspace__\fuzz\test_winafl\thunder_torrent\stat"

在stat目录下输出的是index.html文件和三张png图片,直接拉到浏览器中查看即可;

2. 查看所有fuzzer状态

输出内容会直接打印在屏幕上;

"C:\python27-x64\python.exe" "D:\__workspace__\fuzz\winafl\winafl-whatsup.py" "D:\__workspace__\fuzz\test_winafl\thunder_torrent\result"

十二、fuzz结果

共得到两类crash;

1. 除零异常导致的crash

这类样本占了大多数,一般来说很难利用,意义不大; 

2. 栈溢出导致的crash

别激动,经过分析,很难利用,原因如下:
在解析torrent文件的过程中,每次文件中出现一个‘d’字符,都会导致程序用new分配一段内存,于是只要一个torrent文件中出现大量‘d’字符,就会分配很多内存,当堆空间耗尽时,new分配失败导致异常,出现了栈溢出。

希望大家能发现更多不同类型的crash。

- End -

看雪ID:昵称好麻烦

https://bbs.pediy.com/user-home-825829.htm

  *本文由看雪论坛 昵称好麻烦 原创,转载请注明来自看雪社区。

# 往期推荐

公众号ID:ikanxue
官方微博:看雪安全
商务合作:[email protected]

球分享

球点赞

球在看

点击“阅读原文”,了解更多!


文章来源: http://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&mid=2458381767&idx=1&sn=13bdc3db0efb803c5374d89ece834b8a&chksm=b180dd4d86f7545b2853177e0327f320b54045204ac14f20b4ab7ee068e32cf3fd5ab6f1ca78#rd
如有侵权请联系:admin#unsafe.sh