Black Hat Arsenal peepdf Challenge 2015 writeup

At the beginning of August I saw a link on twitter by Jose Miguel Esparza, the author of peepdf tool, about a challenge he created for Black Hat Arsenal conference in USA. So reading the blog post I decided to play with the challenge and now here’s my writeup solution. I hope that you like it.

PS: I suggest you to spend a bit of your time to try to solve the challenge without reading the solution. It’s a very fun this challenge… Then come back here and read my solution. 😉

For more information about the context,you canread the blogpostby Josein his bloghere.

You can download the pdf challenge here or directly from the blog post linked above.

The pdf is not malicious so you can open with Adobe Reader on your PC without using a VM. The version of Adobe Reader we have to use is earlier than XI version, e.g. X is fine, otherwise you can’t understand and play the challenge. 😛

You can download an old version of Adobe Reader from this site: Adobe Reader X

If all these things are clear, let’s go to solve the challenge!

Opening the pdf we can see only a page with the following image:

Another thing we can observe is that there is an attachment inside this pdf named peepdf.pdf. So let’s save and open it. This new pdf asks you to insert a password through a javascript form:

It’s a kind of a new generation crackme, instead of an executable we have to break a PDF, cool, isn’t it?

To extract the embedded pdf you can also use peepdf tool which we’ll see later. For example when you have identified the object that contains our pdf, into the interactive console simply use the command:

PPDF> object 13 > peepdf.pdf

It’s clear that we must investigate and analyze the pdf extracted to understand what is the password, that is the flag!

At this point from peepdf github repo we do a git clone to download peepdf and open the pdf in it. I recommend using the last version fora reason that you’ll understand in a moment. 😉 We’ll see the following info:

First let’s check the four objects which contain Javascript code:Object 5

The object 5 contain JS code to check if the Adobe Reader version is higher than 10. If this is true the string “You should try with an older version of Adobe Reader 😉” appears and the pdf is closed, else run peepdf function (which we’ll understand what it does later).

The object 16 contain the getAnnots() function (CVE-2009-1492). This function returns an array of Annotation objects and through subject method extracts from this array annotations info. But where is the annotation array returned by getAnnots()? It’s simple, in the pdf file format there are many tags, one of these is named /Annots so let’s go to investigate the /Annots tag to discover what object contains this info. To quickly find /Annots tag we can use the ‘search‘ command like this:

Now that we know the content of buf var it’s straightforward what the js does. It takes the content of the object 22, removes “x1” char and with the fromCharCode function converts the hex valuein the correspondingASCIIcharacter. To accomplish to this task you have different options: online tool, Notepad++ and Converter tool by Kahu Security, or, like I did, directly in peepdf.

The object 19 contains the r function definition used by js code contained in object 5.

The object 24 contains js code which executes the code that checks the password typed in.

That said let’s come back to object 5 to understand the function inside the else statement.

The function r takes 2 argument: a (the key) and x.d(this.info.author) (the data). First we must search the data block to be decrypted by r function. Where to find the data block is very simple because we must find the object which contain the pdf info, that is /Author tag. To do that just read the info at the beginning of the post and we can see a row like this: Info: 12. So jump to object 12:

Ok, this is the data block we were looking for. Nowthe onlything left todo isfind the key(first parameter of r function) to decrypt this data block.

Always from the information provided by the info command we can see that there are 2 decoding errors for objects 6 and 8. So let’s inspect the errors:

These objects have two specified filters: /ASCIIHexDecode /DCTDecode. The first decodes data encoded in an ASCII hexadecimal representation, reproducing the original binary data, the second instead decompresses data encoded using a DCT (discrete cosine transform) technique based on the JPEG standard, reproducing image sample data that approximates the original data. Moreover we can notice the marker of jpeg file format. So the presence of DCTDecode filter plus the marker JFIF lead us tosay that object 6 and object 8 are two jpeg images. Let’s extract these images with:

PPDF> stream 6 > stream6.jpg
PPDF> stream 8 > stream8.jpg

At this point, to check if there is something hidden into the jpg we can use a jpg steganography toolset like stegdetect, in particular djpeg tool, which stands for decompress jpeg.

Uhhh, we have found 2 interesting strings:

var a=”QkhQMzNwZGY=”;

peepdf=eval;

But how is this possible? About that you can read this interesting article in VirusBulletin which explains the possibility to hide javascript code into compressed stream with DCT JPEG standard compression.

So now we know also the key to decrypt the data block and understand that peepdf() function is nothing more than eval function.

Finally this is the code that controls the password inserted. The password is computed with calc() function which we have seen in the js into object 24. If code == calc(app.doc.getAnnots({nPage: 0})[0].subject + this.info.producer) then the password is correct and we’ll see “You got it!! You deserve a peepdf t-shirt!! ;)” messagebox, else we’ll see “Try again!!” that is the password is incorrect. Like we have done before with getAnnots() function, let’s do:

Here instead we obtained “Peepdf Library X” string. So let’s go to join these two strings and we get “Black Hat US Arsenal 2015 – peepdfPeepdf Library X“. This string is the right argument of the calc() function, to get the password we must insert in the form when asked. This time we can create a js file named password.js, for example, with the following code and repeat the operation shown on the previous steps.