在xp
系统下windows
帮助文件格式为hlp
,在win7/win8/win10
下,微软升级了帮助文件格式,使用了chm
格式,这里引用维基百科上的说明
微软HTML帮助集,即编译的HTML帮助文件(英语:Microsoft Compiled HTML Help, CHM),是微软继承早先的WinHelp发展的一种文件格式,用来提供在线帮助,是一种应用较广泛的文件格式。因为CHM文件如一本书一样,可以提供内容目录、索引和搜索等功能,所以也常被用来制作电子书。
简单介绍一下背景,下面直接开干
fuzz API
涉及到chm
文件解析的windows 10
上文件主要有hh.exe
和hhctrl.ocx
,其中ocx格式把它当作dll格式即可,hh.exe
是打开chm
文件的主程序,hhctrl.ocx
中导出了解析chm
文件的主要函数。
根据MSDN
可以找到HtmlHelpA
函数定义
HWND HtmlHelpA(
HWND hwndCaller,
LPCSTR pszFile,
UINT uCommand,
DWORD_PTR dwData
);
根据其定义编写harness code
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <Windows.h>
#include <HtmlHelp.h>
typedef int(*PFN_HtmlHelpA)(HWND hwndCaller, LPCSTR pszFile, UINT uCommand, DWORD_PTR dwData);
int main(int argc, char **argv)
{
if (argc != 2) {
printf("Usage: %s input_filen", argv[0]);
return 1;
}
HMODULE hLibHH = NULL;
PFN_HtmlHelpA pfnHtmlHelpA = NULL;
hLibHH = LoadLibraryA("C:\Windows\System32\hhctrl.ocx");
if (hLibHH == NULL)
return 2;
pfnHtmlHelpA = (PFN_HtmlHelpA)GetProcAddress(hLibHH, "HtmlHelpA");
if (pfnHtmlHelpA != NULL)
{
pfnHtmlHelpA(NULL, argv[1], HH_DISPLAY_TOPIC, NULL);
pfnHtmlHelpA(NULL, NULL, HH_CLOSE_ALL, NULL);
}
return 0;
}
编译为release x64
版本,根据你的喜好,别的版本也没有任何问题
fuzz
之前我们最好使用drrun
观察一下其代码覆盖情况,这么做的原因在于,该做的都做了,没挣到钱,老婆孩子跟别人跑了,那不就悲剧了。所以姿势水平很重要,用drrun
跑一下
..DynamoRIObin64drrun.exe -t drcov -- TestHtmlHelp.exe D:corpuschm_corpus203cdd1b35e54a50a67277cdb7f727640fe140056cabbf456147d930ff01625.chm
看一下效果,姿势应该没啥问题
再看看代码覆盖数据
效果还行,可以接受,最小化一下输入语料就可以开始fuzz
了
C:python27-x64python winafl-cmin.py -D D:DropboxfuzzingDynamoRIObin64 -t 20000 -i D:corpuschm_corpus -o D:DropboxfuzzingTestHelpchm_minset -covtype edge -coverage_module hhctrl.ocx -target_module TestHtmlHelp.exe -target_offset 0x1070 -nargs 2 -- TestHtmlHelp.exe @@
开始fuzz
afl-fuzz.exe -i D:DropboxfuzzingTestHelpinput -o output -S chm_slave_1 -D D:DropboxfuzzingDynamoRIObin64 -t 20000 -- -coverage_module hhctrl.ocx -target_module TestHtmlHelp.exe -target_offset 0x1070 -nargs 2 -- TestHtmlHelp.exe @@
速度优化
如果真按照上面的这么做了,我们会发现,直接调用HtmlHelpA
的这种fuzz
方式,速度非常非常的慢,大概的exec speed
在0.1-0.5/s
之间,最多应该不会超过0.5
,一般稳定在0.2
左右,但是如果你说你机器多,cpu核数多,无所谓,那也可以,因为我测试了,即使是这么慢的速度,24小时以内也会fuzz
出几个crash
的。
但是我这种穷逼就不行了,最好是找到速度慢的原因,能够优化一下,那当然是好的了。简而言之就是需要提高姿势水平,下面来进行优化
patch com调用
具体原因我们去看一下HtmlHelpA
的代码
上图圈出来的代码
- com初始化
- 窗口操作
- 消息循环
后两种无疑都是比较耗时的操作,com
初始化我一开始不知道会特别耗时的,看了我们dicord
群里symeon的文章发现原来是耗时的啊,所以我打算试着patch
掉这部分代码,看看有没有效果
保存一下,之后使用这个被patch
的hhctrl.ocx
测试,最后的结果让我失望了,速度感觉最多也就提升了0.1
,对我来说没啥卵用啊。看样还是姿势不太对,而且这种方式有个弊端,不停的弹出窗口,很容易导致windows
各种紊乱,出现奇奇怪怪的bug。比如vscode
会不停崩溃
具体原理呢,我作为一个菜鸟呢,也不懂,所以不到万不得已,不要使用一直弹窗的fuzz
方式
无窗口化调用
根据上面的测试,无论是否patch
掉com
调用,都依然会建立窗口,所以下一步看看能否使用命令行的方式调用chm
解析,经过搜索发现,hh.exe
还真有命令行调用方式
hh.exe -decompile <decompile_dir> <decompile_file>
我们调用一下试试,看看它是怎么做的
打开process monitor
,并执行
hh.exe -decompile test_chm D:test.chm
可以发现,原来hh.exe
是调用doWinMain
来decompile chm
文件的,MSDN
上没有搜到doWinMain
官方定义,来看看doWinMain
反汇编代码
__int64 __fastcall doWinMain(HMODULE hModule, __int64 a2)
{
__int64 v2; // rbx
HMODULE v3; // rdi
unsigned int v4; // ebx
v2 = a2;
v3 = hModule;
if ( !dword_18008FD64 )
{
if ( OleInitialize(0i64) == 1 )
OleUninitialize();
else
dword_18008FD64 = 1;
}
dword_1800900E8 = 1;
WinSqmIncrementDWORD(0i64, 2400i64, 1i64);
v4 = sub_18002750C(v3, v2);
if ( dword_18008FD64 )
{
OleUninitialize();
dword_18008FD64 = 0;
}
return v4;
}
ida
显示有两个参数,我们结合hh.exe
的反汇编代码看一下
两个参数分别为rcx
和rdx
,第一个参数hModule
,这个好确认,回溯反汇编代码就可以知道,它利用的是LoadLibrary
的返回值,第二个参数目前不知道是什么,所以利用windbg
调试一下hh.exe
0:000> lm
start end module name
00007ff7`0bb40000 00007ff7`0bb49000 hh (deferred)
00007ffe`933e0000 00007ffe`93683000 KERNELBASE (deferred)
00007ffe`944f0000 00007ffe`9458e000 msvcrt (deferred)
00007ffe`94640000 00007ffe`946d7000 sechost (deferred)
00007ffe`94f90000 00007ffe`95033000 ADVAPI32 (deferred)
00007ffe`952b0000 00007ffe`95362000 KERNEL32 (deferred)
00007ffe`953f0000 00007ffe`95510000 RPCRT4 (deferred)
00007ffe`95780000 00007ffe`95970000 ntdll (pdb symbols) c:symbolsntdll.pdbC2E19EA1901E9B82E4567D2D21E56D21ntdll.pdb
0:000> bu hh+0x1670
0:000> g
Breakpoint 0 hit
hh+0x1670:
00007ff7`0bb41670 ff151a1c0000 call qword ptr [hh+0x3290 (00007ff7`0bb43290)] ds:00007ff7`0bb43290={ntdll!LdrpDispatchUserCallTarget (00007ffe`9580c590)}
0:000> dps rdx
000001d4`b54c3d92 69706d6f`6365642d
000001d4`b54c3d9a 65745c3a`4420656c
000001d4`b54c3da2 44206d68`635f7473
000001d4`b54c3daa 632e7473`65745c3a
000001d4`b54c3db2 abababab`ab006d68
000001d4`b54c3dba abababab`abababab
000001d4`b54c3dc2 feeefeee`feababab
000001d4`b54c3dca 0000feee`feeefeee
000001d4`b54c3dd2 00000000`00000000
000001d4`b54c3dda feee0000`00000000
000001d4`b54c3de2 c660feee`feeefeee
000001d4`b54c3dea 00003000`61eda2de
000001d4`b54c3df2 00000000`00000000
000001d4`b54c3dfa 00000000`00000000
000001d4`b54c3e02 00000000`00000000
000001d4`b54c3e0a 00000000`00000000
0:000> dc rdx
000001d4`b54c3d92 6365642d 69706d6f 4420656c 65745c3a -decompile D:te
000001d4`b54c3da2 635f7473 44206d68 65745c3a 632e7473 st_chm D:test.c
000001d4`b54c3db2 ab006d68 abababab abababab abababab hm..............
000001d4`b54c3dc2 feababab feeefeee feeefeee 0000feee ................
000001d4`b54c3dd2 00000000 00000000 00000000 feee0000 ................
000001d4`b54c3de2 feeefeee c660feee 61eda2de 00003000 ......`....a.0..
000001d4`b54c3df2 00000000 00000000 00000000 00000000 ................
000001d4`b54c3e02 00000000 00000000 00000000 00000000 ................
rdx
存储命令行参数,由此编写doWinMain
的harness code
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <Windows.h>
#include <HtmlHelp.h>
typedef int(*PFN_DoWinMain)(HMODULE, const char *);
int main(int argc, char **argv)
{
if (argc != 2) {
printf("Usage: %s input_filen", argv[0]);
return 1;
}
HMODULE hLibHH = NULL;
PFN_DoWinMain pfnDoWinMain = NULL;
hLibHH = LoadLibraryA("C:\Windows\system32\hhctrl.ocx");
if (hLibHH == NULL)
return 2;
pfnDoWinMain = (PFN_DoWinMain)GetProcAddress(hLibHH, "doWinMain");
std::string chCommandLine = "-decompile test_chm ";
chCommandLine += std::string(argv[1]);
if (pfnDoWinMain != NULL)
pfnDoWinMain(hLibHH, chCommandLine.c_str());
return 0;
}
编译,运行,之后看看效果
十多分钟可能就会出现crash
速度依然慢,但跟以前比较的话,速度几乎提升足足有几十倍,就这还要啥自行车呢,经过大概24小时的运行的话,你会发现明显比使用HtmlHelpA
的方式快多了,所以也发现了更多的crash
crashes简要分析
crash分析我基本会直接用脚本跑一下,看看跑出来了几种,看看结果
出现了很多种crash
,随便挑一个用windbg
看看
0:000> g
ModLoad: 00007fff`6de50000 00007fff`6df01000 C:Windowssystem32hhctrl.ocx
ModLoad: 00007fff`907e0000 00007fff`9087e000 C:WINDOWSSystem32msvcrt.dll
ModLoad: 00007fff`8ff60000 00007fff`900f4000 C:WINDOWSSystem32USER32.dll
ModLoad: 00007fff`8ebc0000 00007fff`8ebe1000 C:WINDOWSSystem32win32u.dll
ModLoad: 00007fff`8f750000 00007fff`8f776000 C:WINDOWSSystem32GDI32.dll
ModLoad: 00007fff`8ec90000 00007fff`8ee24000 C:WINDOWSSystem32gdi32full.dll
ModLoad: 00007fff`8ebf0000 00007fff`8ec8e000 C:WINDOWSSystem32msvcp_win.dll
ModLoad: 00007fff`8fb00000 00007fff`8fba3000 C:WINDOWSSystem32ADVAPI32.dll
ModLoad: 00007fff`90680000 00007fff`90717000 C:WINDOWSSystem32sechost.dll
ModLoad: 00007fff`90cd0000 00007fff`90df0000 C:WINDOWSSystem32RPCRT4.dll
ModLoad: 00007fff`90df0000 00007fff`914d5000 C:WINDOWSSystem32SHELL32.dll
ModLoad: 00007fff`8ee30000 00007fff`8ee7a000 C:WINDOWSSystem32cfgmgr32.dll
ModLoad: 00007fff`90c20000 00007fff`90cc9000 C:WINDOWSSystem32shcore.dll
ModLoad: 00007fff`90880000 00007fff`90bb6000 C:WINDOWSSystem32combase.dll
ModLoad: 00007fff`8eb40000 00007fff`8ebc0000 C:WINDOWSSystem32bcryptPrimitives.dll
ModLoad: 00007fff`8ee80000 00007fff`8f5ff000 C:WINDOWSSystem32windows.storage.dll
ModLoad: 00007fff`8e610000 00007fff`8e62f000 C:WINDOWSSystem32profapi.dll
ModLoad: 00007fff`8e5a0000 00007fff`8e5ea000 C:WINDOWSSystem32powrprof.dll
ModLoad: 00007fff`8e570000 00007fff`8e580000 C:WINDOWSSystem32UMPDC.dll
ModLoad: 00007fff`8fd70000 00007fff`8fdc2000 C:WINDOWSSystem32shlwapi.dll
ModLoad: 00007fff`8e580000 00007fff`8e591000 C:WINDOWSSystem32kernel.appcore.dll
ModLoad: 00007fff`8ea20000 00007fff`8ea37000 C:WINDOWSSystem32cryptsp.dll
ModLoad: 00007fff`8f8c0000 00007fff`8fa16000 C:WINDOWSSystem32ole32.dll
ModLoad: 00007fff`8fe90000 00007fff`8ff54000 C:WINDOWSSystem32OLEAUT32.dll
ModLoad: 00007fff`6feb0000 00007fff`6ff59000 C:WINDOWSWinSxSamd64_microsoft.windows.common-controls_6595b64144ccf1df_5.82.18362.535_none_2a26181e466b3888COMCTL32.dll
ModLoad: 00007fff`914f0000 00007fff`9151e000 C:WINDOWSSystem32IMM32.DLL
ModLoad: 00007fff`8c8d0000 00007fff`8c969000 C:WINDOWSsystem32uxtheme.dll
ModLoad: 00007fff`639e0000 00007fff`63a2b000 C:Program FilesListaryListaryHook64.dll
ModLoad: 00007fff`71920000 00007fff`71985000 C:WINDOWSSYSTEM32OLEACC.dll
ModLoad: 00007fff`90720000 00007fff`907c2000 C:WINDOWSSystem32clbcatq.dll
ModLoad: 00007fff`71a90000 00007fff`71abe000 C:WindowsSystem32itss.dll
ModLoad: 00007fff`844c0000 00007fff`84696000 C:WindowsSystem32urlmon.dll
ModLoad: 00007fff`7d830000 00007fff`7dd06000 C:WindowsSystem32WININET.dll
ModLoad: 00007fff`84210000 00007fff`844b6000 C:WindowsSystem32iertutil.dll
ModLoad: 00007fff`8df50000 00007fff`8df5c000 C:WindowsSystem32CRYPTBASE.DLL
(1bdc.34b0): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
itss!DllGetClassObject+0x3706:
00007fff`71a9b346 488b4020 mov rax,qword ptr [rax+20h] ds:6e65746e`6f432f84=????????????????
0:000> k
# Child-SP RetAddr Call Site
00 000000ea`e0aff450 00007fff`71a9a9b2 itss!DllGetClassObject+0x3706
01 000000ea`e0aff480 00007fff`71a9b214 itss!DllGetClassObject+0x2d72
02 000000ea`e0aff4b0 00007fff`71a9b10e itss!DllGetClassObject+0x35d4
03 000000ea`e0aff4f0 00007fff`6de74963 itss!DllGetClassObject+0x34ce
04 000000ea`e0aff530 00007fff`6de75403 hhctrl!Ordinal10+0x24963
05 000000ea`e0aff7c0 00007fff`6de77811 hhctrl!Ordinal10+0x25403
06 000000ea`e0aff800 00007fff`6de774de hhctrl!doWinMain+0x391
07 000000ea`e0affbb0 00007ff7`29521226 hhctrl!doWinMain+0x5e
08 000000ea`e0affbe0 00007ff7`29521868 TestDoWinMain+0x1226
09 000000ea`e0affc80 00007fff`8fde7bd4 TestDoWinMain+0x1868
0a 000000ea`e0affcc0 00007fff`9170ced1 KERNEL32!BaseThreadInitThunk+0x14
0b 000000ea`e0affcf0 00000000`00000000 ntdll!RtlUserThreadStart+0x21
0:000> !load msec_x64.dll
0:000> !exploitable
!exploitable 1.6.0.0
Exploitability Classification: UNKNOWN
Recommended Bug Title: Read Access Violation starting at itss!DllGetClassObject+0x0000000000003706 (Hash=0xb07b0e28.0xbed30cef)
一个OOB
,具体啥情况需要具体分析
总结
当天下午,我在discord
群里提醒了大家关注一下windows help
文件格式,群里的乌克兰老哥动作比我还快,当晚出结果就提交给了MSRC
,然后被拒了,就跟我说了一声,所以我也不打算提了。反正漏洞是没有被修复的,被利用的话,那就是0day
🙂
如果有老哥有新颖的攻击面,比如outlook/office
等,使MSRC
能够接受的话,可以带我一个哈
整个过程挺有意思的,作为一个菜鸡,就写个文章总结一下。其实整个过程还有有更好的fuzz
方式,不需要写什么harness code
,直接fuzz hh.exe
,使用doWinMain
作为target_method
,也可以达到目的,但上面这种方式,是我比较喜欢的,所以就详细说了一下。万一大家能有更好的方式呢,希望大家也不吝赐教,fuzz
这玩意就是越深入越有意思
祝大家挖洞愉快哈
发表评论
您还未登录,请先登录。
登录