Evading anti-virus's script emulator

Part of Tempest's research team duty is to provide adequate support and tooling for pentest projects, either by brainstorming an attack or customizing softwares to overcome specific needs. Some time ago I was asked to customize an use-after-free exploit (CVE-2010-3971) for Internet Explorer (IE) in order to bypass Kaspersky Internet Security (KIS). While I can't quite remember what version of KIS was in place back then, for the matter of this blog post, I'm going to setup a new environment and test whether the bypass is still applicable.

First I'm going to review the exploit code for CVE-2010-3971 in order to outline relevant aspects and possible targets for the detection. Then, I'm going to talk about the anti-virus's script emulator engine as an effort in order to provide a glimpse of its inner workings and fragilities. Finaly, there is a port of the evasion technique applied to a more recent exploit (CVE-2013-2551) and tested against the latest anti-virus version (KIS 2014).

Understanding the exploit code (CVE-2010-3971)

Let's take a look at the javascript exploit code present in Metasploit Framework (MSF). The image below presents a partial code excerpt that is relevant to this blog post. If you want to read the entire code, check the file "ms11_003_ie_css_import.rb" – shipped within MSF.

First thing you may notice is the ruby-like string interpolation present in the above code, more specifically #{js_function}, #{special_sauce} and #{placeholder}. Those are dynamic values set by MSF as it prepares to serve the exploit. For short, #{js_function} is a random name for the js function, #{special_sauce} holds the ROP chain for the stack pivoting and VirtualAlloc RWX trick to bypass DEP, #{placeholder} is related to the vulnerability itself, which is caused by a recursive CSS import.

The first three blocks of code are responsible for spraying the heap, while the final block imports the crafted CSS file to trigger the vulnerability. The reference to the undeclared heapLib Class may also com to attention, which is a heap spray library included in metasploit and later incorporated to the above js code. In order to assess the nature of the detection and to obtain a better view of the actual html/js generated by MSF, I served the exploit and dumped the generated files.

For this specific exploit, metasploit generates three files: an HTML page, a CSS file and a stub for a .NET DLL. The HTML page contains the aforementioned js code including the code for heapLib, the CSS file is quite simple, it makes use of @import directive to recursively import itself triggering the vulnerability. On the other hand, the .NET DLL bears the sole purpose of having Internet Exporer to load the .NET MIME Filter (mscorie.dll), which version 2.0.5 doesn't opt-in for ASLR and thus isn't randomized, supporting the ROP.

A brief view of the generated javascript code can be seen below:

As you can see, the actual code is a lot bigger than the previous one. Also, note the function name, as the heapLib class, are randomized but the same isn't true for variable names (heap, heapspray). The long unicode encoded yellow string is the ROP payload mentioned earlier as #{special_sauce}. There is a big portion of code highlighted as heapLib code, which was stripped from the previous image. It offers several functions to deal with the heap spraying, while its not illustrated above for the sake of brevity, I can tell you all its functions names are also randomized.

Understanding the detection and evading it

Further experiments showed that neither the unrandomized names or the heapLib code was the matter of the detection, leaving the ROP payload as the most likely detection target as one could already suspect. For my surprise, changing from unescape('ue028%u105a%u575b%...') to alert('ue028%u105a%u575b%...') causes the detection to fail, the reason for that is because the AV isn't detecting the unicode encoded string but the decoded string returned by unescape.

Based on the above results, it is fair to assume that the anti-virus is employing a dual detection approach, mixing javascript emulation to static signature detection. In theory, defeating one of the two technologies would disrupt the detection. In my opinion it's more effective to surrender the script emulator rather than coding another shellcode encoder module for metasploit.

I conducted several experiments to understand the inner workings of the emulator in order to gather accurate information instead of rushing into trial and error. The information extracted from the experiments are summarized below:

  • 1. All functions are emulated regardless of the existence of a code path leading to it.

  • 2. Conditional branch expressions are availed (i.e. emulator will not enter all code branches).

  • 3. Code inside Eval() is also emulated.

  • 4. Human interaction is simulated (i.g. mouse clicks).

  • 5. Long loops are detected (i.e. slow down the emulator).

With all this in mind, I came up with a solution that would test the limits of the simulated human interaction and benefit from the conditional branches behavior presented by the emulator. The first thing I'm going to do is to isolate the unescape function, as I don't want it to be executed by the emulator.

As you can see highlighted in red, the call to unescape() was replaced by an indirect call through eval(). Now I have to make use of a conditional branch to differentiate between the execution flow inside the emulator and outside (i.e. real execution in Internet Explorer). The final code should be something like this:

To assert the presence of the emulator, as I said before, I'm going to test the limits of the human interaction simulation, and then rely on common actions performed by an user that aren't properly simulated by the KIS script emulator. For this matter, I'm going to track mouse event's coordinates and try to check whether it's a natural movement or hardcoded events generated by the emulator, much like a Turing test.

For tracking the mouse I added an onmousemove event handler at the document object, the handler is responsible for storing the x and y coordinates in a global array. The condition I end up using is requiring at least three onmousemove events with differing y coordinates. As I remember, KIS was only simulating two onmousemove events. The final code can be seen below:

Testing the evasion with CVE-2013-2551 and KIS 2014

The previous two sections are based on the experience I've had when first implemented the evasion technique. Now I'm going to apply the same evasion principle to the exploit demonstrated at pwn2own 2013 contest, it's an integer overflow in the Vector Markup Language (VML) implemented in Internet Explorer. Also, I'm going to test the effectiveness of the evasion against Kaspersky Internet Security 2014 running on a Windows 7 32 bits.

The initial tests showed that isolating the unescape function was not enough to fool KIS 2014, at least for the exploit in question. By exclusion, I was able to find three additional points where the script emulator's heuristics was detecting the exploit.

The first suspicious code structure detected by the heuristic analyzer is related to the vulnerability itself. The exploit code creates 0x1000 elements of type "v:shape" and appends it to the body, as you can see below:

The two remaining code patterns detected by KIS 2014 are responsible for building the heap spray with the ROP payload and the NOP slide. As you can see highlighted in red in the following image, there are two long loops concatenating strings to build a large heap block for the final spray:

By removing the "v:shape" element and downsizing both loops to a single iteration, I was able to load the resulting exploit code to Internet Explorer without having KIS 2014 blocking it. So, I've made the following changes to the anti-emulation code in order to hide the suspicious behavior of the exploit:

With the aforementioned modifications, by the time of this writing, it is possible to completely bypass Kaspersky Internet Security 2014 and exploit Internet Explorer. However, there are still concerns on the post exploitation phase, as the anti-virus is still monitoring the state of the Operating System and key processes. In fact, after the successful exploitation, the approach of popping up calc.exe was detected as a malicious behavior coming from IE. Although calc.exe isn't a malicious binary, the act of IE spawning a process is surely suspicious. Fortunately, the reverse meterpreter payload isn't detected as it executes in-memory.

Aceita-se formatação à la TWiki. HTML e scripts são filtrados. Máximo 15KiB.

Enviando... por favor aguarde...
Comentário enviado com suceso -- obrigado.
Ele aparecerá quando os moderadores o aprovarem.
Houve uma falha no envio do formulário!
Deixei uma nota para os admins verificarem o problema.
Perdoe-nos o transtorno. Por favor tente novamente mais tarde.