Windows 10帮助文件chm格式漏洞挖掘

阅读量    687263 | 评论 5   稿费 400

分享到: QQ空间 新浪微博 微信 QQ facebook twitter

 

xp系统下windows帮助文件格式为hlp,在win7/win8/win10下,微软升级了帮助文件格式,使用了chm格式,这里引用维基百科上的说明

微软HTML帮助集,即编译的HTML帮助文件(英语:Microsoft Compiled HTML Help, CHM),是微软继承早先的WinHelp发展的一种文件格式,用来提供在线帮助,是一种应用较广泛的文件格式。因为CHM文件如一本书一样,可以提供内容目录、索引和搜索等功能,所以也常被用来制作电子书。

简单介绍一下背景,下面直接开干

 

fuzz API

涉及到chm文件解析的windows 10上文件主要有hh.exehhctrl.ocx,其中ocx格式把它当作dll格式即可,hh.exe是打开chm文件的主程序,hhctrl.ocx中导出了解析chm文件的主要函数。

1579228361354

根据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

看一下效果,姿势应该没啥问题

1579229832260

再看看代码覆盖数据

1579229884124

效果还行,可以接受,最小化一下输入语料就可以开始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 speed0.1-0.5/s之间,最多应该不会超过0.5,一般稳定在0.2左右,但是如果你说你机器多,cpu核数多,无所谓,那也可以,因为我测试了,即使是这么慢的速度,24小时以内也会fuzz出几个crash的。

1579230864933

但是我这种穷逼就不行了,最好是找到速度慢的原因,能够优化一下,那当然是好的了。简而言之就是需要提高姿势水平,下面来进行优化

patch com调用

具体原因我们去看一下HtmlHelpA的代码

1579230532340

上图圈出来的代码

  1. com初始化
  2. 窗口操作
  3. 消息循环

后两种无疑都是比较耗时的操作,com初始化我一开始不知道会特别耗时的,看了我们dicord群里symeon的文章发现原来是耗时的啊,所以我打算试着patch掉这部分代码,看看有没有效果

1579231060323

保存一下,之后使用这个被patchhhctrl.ocx测试,最后的结果让我失望了,速度感觉最多也就提升了0.1,对我来说没啥卵用啊。看样还是姿势不太对,而且这种方式有个弊端,不停的弹出窗口,很容易导致windows各种紊乱,出现奇奇怪怪的bug。比如vscode会不停崩溃

1579243682230

具体原理呢,我作为一个菜鸟呢,也不懂,所以不到万不得已,不要使用一直弹窗的fuzz方式

无窗口化调用

根据上面的测试,无论是否patchcom调用,都依然会建立窗口,所以下一步看看能否使用命令行的方式调用chm解析,经过搜索发现,hh.exe还真有命令行调用方式

hh.exe -decompile <decompile_dir> <decompile_file>

我们调用一下试试,看看它是怎么做的

打开process monitor,并执行

hh.exe -decompile test_chm D:test.chm

1579233197713

可以发现,原来hh.exe是调用doWinMaindecompile 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的反汇编代码看一下

1579234120175

两个参数分别为rcxrdx,第一个参数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存储命令行参数,由此编写doWinMainharness 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;
}

编译,运行,之后看看效果

1579243243239

十多分钟可能就会出现crash

1579243860689

速度依然慢,但跟以前比较的话,速度几乎提升足足有几十倍,就这还要啥自行车呢,经过大概24小时的运行的话,你会发现明显比使用HtmlHelpA的方式快多了,所以也发现了更多的crash

 

crashes简要分析

crash分析我基本会直接用脚本跑一下,看看跑出来了几种,看看结果

1579245066116

出现了很多种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这玩意就是越深入越有意思

祝大家挖洞愉快哈

分享到: QQ空间 新浪微博 微信 QQ facebook twitter
|推荐阅读
|发表评论
|评论列表
加载更多