Tuesday, August 25, 2015

Cracking a CTF [Part 1]

Capture the Flag, hacker style: walking through the first four puzzles in the 2015 Hou.Sec.Con pre-conference CTF.


I grew up playing Capture the Flag in my backyard. Now with kids of my own and a couple acres of mostly undisturbed woods to call my own, my family enjoys the occasional evening of Capture the Flag.

In hacker culture, a different sort of Capture the Flag (or CTF) is a common way to hone our skills and compete against peers. In hacking CTFs, the flags are digital rather than physical, and the field is bits and bytes rather than grass and trees, but there are still similarities. In both cases, winning requires a combination of skills: sheer speed is rarely enough, but at the same time my carefully-planned strategy has many times been derailed by a quicker opponent.

Most hacker and security conferences include some sort of a CTF challenge. I wrote a couple years ago of winning a trophy by "cheating" at a social engineering CTF (in fairness, I was upfront about my approach, and the rules of engagement did not prohibit reverse engineering the scoring portal to steal the flags!).

This time, I am participating in an online CTF ahead of Hou.Sec.Con, the Houston Security Conference. And since the event is online, it is a chance for me to not only compete, but let my 11 year old daughter shoulder surf and give her own ideas while learning.

This CTF is a bit different. Its creator, known as "DisK0nn3cT," has an apparent devilish streak that feeds on the pain of fellow hackers. He created a devious game wherein even joining the game requires solving a puzzle - and subsequent puzzles don't even have an obvious objective. What they do have is a common theme: the game (as well as the conference) builds on the classic hacker movie "WarGames."


My hat's off to the devs of this year's HouSecCon CTF. Exceedingly hard to device the answers when you aren't even given the questions :-)


The CTF runs in monthly phases, with prizes for the first three hackers to solve all four puzzles each month. As the slate is wiped clean after the end of each month, the coordinators gave me the OK to publish the solutions to the previous month once each new set of flags is revealed. So, without further ado, July:

Hou.Sec.Con CTF July Puzzles

Puzzle 0: Joining the game

Simply registering requires breaking a code - a "Hackcha" (a play on the captcha's used by some sites to prove you are human when registering - the concept being that humans are good at recognizing patterns in a way that computers cannot do ... yet).


Joining the game requires solving an encryption puzzle.


There is a little hint embedded in the web page source (hacker tip #1: "view source" is a deceptively simple way to see things the developers might not have intended you to see):

<input type="hidden" name="hackcha" value="c3Vic3RpdHV0aW9u"/>

I grew up on text-based email programs (pine, anyone?), so base-64 encoded content tends to stick out. Base-64 encoding is a way of converting binary files (such as pictures and programs) into alphanumeric text that can be attached to an email message. While modern email programs are happy to handle binary attachments, early programs were designed for human-readable text only. Attachments are still converted to base-64, but now the email program does the work for you.

Using my trusty base-64 decoder I find that c3Vic3RpdHV0aW9u is a base-64 encoding of the word "substitution."

Granted, it's not hard to assume that RDZOUPPG is a substitution cipher, but hey, if I am going to hack all the things, might as well examine every corner, right? There aren't too many words related to hacker culture that contain a double letter right before the end. With a little help from http://quipqiup.com/index.php to suggest likely words, the solution turns out to be "backdoor."

Having solved this first puzzle I can now complete my registration and formally join the game. Successfully joining and logging in reveals an imitation of an IRC chat room containing the next three clues:


The game portal is an imitation IRC chat window with the next three clues


Puzzle 1: <1> anextio.com:1337

The next few puzzles begin with nothing but a link or server name. servername:port is a common notation for a web service listening on an unusual port. By convention, web servers listen on ports 80 (normal HTTP) and 443 (secure HTTPS), but the network protocols allow for ports ranging from 1 to 65535. In general, ports 1 to 1024 are reserved for well-known services, but everything above 1024 is fair game. Quite often, device administration will be on a different port (in fact, in this guide to securely installing a wireless router, I explain setting it up to listen on another port). So, entering anextio.com:1337 into my browser, I get the following:
Greetings.

Shall we play a game?[Yes/no]

Ok...Goodbye.

Hmm. So I know there is a service listening on that port - I know I am on the right track - but this output doesn't do me much good. It seems the server expects me to respond to a question, but the web browser doesn't have any way of replying. So let's try a different route.

Telnet and SSH are common programs for logging into a server with a shell (equivalent to a Windows command prompt). When I try using telnet from my Windows PC to access the server, I get the same output. Ah, but Windows and Unix work a bit differently, so perhaps a Unix telnet session will work.
$ telnet anextio.com 1337Trying 45.55.252.213...Connected to anextio.com.Escape character is '^]'.Greetings.
Shall we play a game?[Yes/no]

Yes
c3RhdGljODQ5MV9rc3RhdGljODQ5MV9rL3RtcC8zODQ5MV9rc3RhdGljZXkudHh0ODQ5MV9rL3RtcC8zL3RtcC8zODQ5MV9rZXkudHh0L3RtcC8zL3RtcC8zODQ5MV9rZXkudHh0ZXkudHh0ZXkudHh0ODQ5MV9rZXkudHh0L3RtcC8zODQ5MV9rODQ5MV9rL3RtcC8zL3RtcC8zL3RtcC8zc3RhdGljL3RtcC8zc3RhdGljc3RhdGljL3RtcC8zODQ5MV9rc3RhdGljZXkudHh0L3RtcC8zODQ5MV9rL3RtcC8zL3RtcC8zODQ5MV9rODQ5MV9rc3RhdGljODQ5MV9rODQ5MV9rZXkudHh0ODQ5MV9rL3RtcC8zODQ5MV9rODQ5MV9rL3RtcC8zODQ5MV9rc3RhdGljc3RhdGljODQ5MV9rc3RhdGljc3RhdGljL3RtcC8zZXkudHh0ZXkudHh0ODQ5MV9rODQ5MV9rZXkudHh0ZXkudHh0ZXkudHh0ZXkudHh0ODQ5MV9rODQ5MV9rZXkudHh0c3RhdGljZXkudHh0L3RtcC8zc3RhdGljL3RtcC8zc3RhdGljc3RhdGljc3RhdGljZXkudHh0ZXkudHh0c3RhdGljZXkudHh0ZXkudHh0ODQ5MV9rL3RtcC8zL3RtcC8zc3RhdGljZXkudHh0L3RtcC8zL3RtcC8zL3RtcC8zODQ5MV9rL3RtcC8zODQ5MV9rc3RhdGljODQ5MV9rZXkudHh0c3RhdGljL3RtcC8zL3RtcC8zc3RhdGljODQ5MV9rc3RhdGljODQ5MV9rODQ5MV9rODQ5MV9rZXkudHh0L3RtcC8zL3RtcC8zL3RtcC8zL3RtcC8zZXkudHh0L3RtcC8zODQ5MV9rODQ5MV9rL3RtcC8zZXkudHh0ODQ5MV9rc3RhdGljODQ5MV9rODQ5MV9rL3RtcC8zODQ5MV9rODQ5MV9rODQ5MV9rc3RhdGljL3RtcC8zc3RhdGljZXkudHh0ZXkudHh0L3RtcC8zL3RtcC8zc3RhdGljc3RhdGljZXkudHh0ODQ5MV9rL3RtcC8zZXkudHh0c3RhdGljL3RtcC8zZXkudHh0ODQ5MV9rL3RtcC8zZXkudHh0L3RtcC8zZXkudHh0c3RhdGljZXkudHh0ZXkudHh0L3RtcC8zc3RhdGljZXkudHh0ZXkudHh0L3RtcC8zc3RhdGljZXkudHh0ODQ5MV9rODQ5MV9rZXkudHh0c3RhdGljODQ5MV9rL3RtcC8zc3RhdGljODQ5MV9rc3RhdGljc3RhdGljL3RtcC8zODQ5MV9rZXkudHh0L3RtcC8zODQ5MV9rL3RtcC8zODQ5MV9rODQ5MV9rL3RtcC8zODQ5MV9rZXkudHh0L3RtcC8zZXkudHh0c3RhdGljL3RtcC8zZXkudHh0ODQ5MV9rL3RtcC8zODQ5MV9rc3RhdGljODQ5MV9rZXkudHh0ZXkudHh0c3RhdGljODQ5MV9rL3RtcC8zL3RtcC8zZXkudHh0c3RhdGljc3RhdGljZXkudHh0c3RhdGljODQ5MV9rc3RhdGljc3RhdGljc3RhdGljc3RhdGljZXkudHh0L3RtcC8zODQ5MV9rL3RtcC8zODQ5MV9rc3RhdGljL3RtcC8zL3RtcC8zc3RhdGljZXkudHh0ZXkudHh0ZXkudHh0ZXkudHh0ZXkudHh0ZXkudHh0ZXkudHh0c3RhdGljL3RtcC8zc3RhdGljL3RtcC8zZXkudHh0ZXkudHh0ODQ5MV9rODQ5MV9rL3RtcC8zL3RtcC8zZXkudHh0ZXkudHh0ZXkudHh0ZXkudHh0L3RtcC8zODQ5MV9rc3RhdGljZXkudHh0ZXkudHh0ZXkudHh0ZXkudHh0ODQ5MV9rc3RhdGljL3RtcC8zODQ5MV9rZXkudHh0ZXkudHh0ZXkudHh0c3RhdGljZXkudHh0c3RhdGljc3RhdGljc3RhdGlj <continues indefinitely...>

Again, this looks very much like base 64 encoding; decoding a chunk of it gives the following:
static8491_kstatic8491_k/tmp/38491_kstaticey.txt8491_k/tmp/3/tmp/38491_key.txt/tmp/3/tmp/38491_key.txtey.txtey.txt8491_key.txt/tmp/38491_k8491_k/tmp/3/tmp/3/tmp/3static/tmp/3staticstatic/tmp/38491_kstaticey.txt/tmp/38491_k/tmp/3/tmp/38491_k8491_kstatic8491_k8491_key.txt8491_k/tmp/38491_k8491_k/tmp/38491_kstaticstatic8491_kstaticstatic/tmp/3ey.txtey.txt8491_k8491_key.txtey.txtey.txtey.txt8491_k8491_key.txtstaticey.txt/tmp/3static/tmp/3staticstaticstaticey.txtey.txtstaticey.txtey.txt8491_k/tmp/3/tmp/3staticey.txt/tmp/3/tmp/3/tmp/38491_k/tmp/38491_kstatic8491_key.txtstatic/tmp/3/tmp/3static8491_kstatic8491_k8491_k8491_key.txt/tmp/3/tmp/3/tmp/3/tmp/3ey.txt/tmp/38491_k8491_k/tmp/3ey.txt8491_kstatic8491_k8491_k/tmp/38491_k8491_k8491_kstatic/tmp/3staticey.txtey.txt/tmp/3/tmp/3staticstaticey.txt8491_k/tmp/3ey.txtstatic/tmp/3ey.txt8491_k/tmp/3ey.txt/tmp/3ey.txtstaticey.txtey.txt/tmp/3staticey.txtey.txt/tmp/3staticey.txt8491_k8491_key.txtstatic8491_k/tmp/3static8491_kstaticstatic/tmp/38491_key.txt/tmp/38491_k/tmp/38491_k8491_k/tmp/38491_key.txt/tmp/3ey.txtstatic/tmp/3ey.txt8491_k/tmp/38491_kstatic8491_key.txtey.txtstatic8491_k/tmp/3/tmp/3ey.txtstaticstaticey.txtstatic8491_kstaticstaticstaticstaticey.txt/tmp/38491_k/tmp/38491_kstatic/tmp/3/tmp/3staticey.txtey.txtey.txtey.txtey.txtey.txtey.txtstatic/tmp/3static/tmp/3ey.txtey.txt8491_k8491_k/tmp/3/tmp/3ey.txtey.txtey.txtey.txt/tmp/38491_kstaticey.txtey.txtey.txtey.txt8491_kstatic/tmp/38491_key.txtey.txtey.txtstaticey.txtstaticstaticstatic

While this is not exactly readable, it gave me some clues. The IRC windows gives a URL for puzzle 3: http://anextio.com/static/tmp/expenses/accelio_eticket_0114.pdf; I see a lot of "tmp" and "static" in the jumbled stream so make a guess that the solution is a filename within the /static/tmp folder. I teased out the following URL:

http://anextio.com/static/tmp/38491_key.txt

Which yields the following:
You have made it through the maze; but this is just the beginning. You have no idea what you are dealing with...
5d59c329f3fa14ec210bbe08497983e1

The string of characters is 32 char long - a MD5 hash, a common form of "flags" in a CTF, and precisely the answer that the IRC window is looking for.

Puzzle 2: <2> anextio.com:4041

The next puzzle is similar, but instead of asking if I want to play a game, I am dropped straight into a game of Tic-Tac-Toe, with instructions to win 5 points in under 225 seconds. Again, attempting to telnet from Windows is a fools errand - the "new line" convention differs between Windows and Unix so the ASCII art is illegible and the game board unusable. From Unix however:
sansforensics@siftworkstation:~$ telnet anextio.com 4041
Trying 45.55.252.213...
Connected to anextio.com.
Escape character is '^]'.
Welcome to:
  _______     ______          ______      
 /_  __(_)___/_  __/___ _____/_  __/___  ___
  / / / / ___// / / __ `/ ___// / / __ \/ _ \
 / / / / /__ / / / /_/ / /__ / / / /_/ /  __/
/_/ /_/\___//_/  \__,_/\___//_/  \____/\___/ 
 
Do you have what it takes? Score 5 points in less than 225 seconds. 
Do you want to be X or O?
X
The computer will go first.
   |   |
   |   |
   |   |
-----------
   |   |
   |   |
   |   |
-----------
   |   |
   |   | O
   |   |
What is your next move? (1-9)
It's a tic tac toe game!

Tic tac toe has some well-known strategies by which one can do no worse that tie; using these strategies, if your opponent makes a mistake, you can then win. After winning 5 times I get the following:
Congrats, you won 5 games in 215.0 seconds
aac35f903d7096e16f4254250a08c03e

Puzzle 3: <3> http://anextio.com/static/tmp/expenses/accelio_eticket_0114.pdf


Puzzle three is an Adobe PDF file containing a boarding pass


The fourth puzzle was tricker. I had not tried forensic analysis of an Adobe PDF file before, so this was altogether new terrain for me. Thanks to an excellent blog post by Didier Stevens (linked above), I had a good starting point though. I opened the PDF link and ran it through a variety of PDF tools. I tried all sorts of combinations of the confirmation number, frequent traveler ID, dates, barcode, and nothing worked. I even managed to lock out the account of American Airlines frequent flyer ID DE23814...

I spent many hours hammering on this file to no avail. After an additional clue a few days later though, I realized there were other PDF files to be found. So ... I downloaded http://anextio.com/static/tmp/expenses/accelio_eticket_0115.pdf and scoured it for anything unusual. This time though, I only spent a few minutes on it before moving on.

_0113.pdf and _0116.pdf did not exist, so I knew it was not going to be practical to search for missing documents by hand. Instead, I wrote a quick and dirty script to search for and download any PDF from the directory on the web server:
for i in {10..99}; do curl http://anextio.com/static/tmp/expenses/accelio_eticket_00$i.pdf -o $i.pdf -f; done
for i in {100..999}; do curl http://anextio.com/static/tmp/expenses/accelio_eticket_0$i.pdf -o $i.pdf -f; done

for i in {1000..9999}; do curl http://anextio.com/static/tmp/expenses/accelio_eticket_$i.pdf -o $i.pdf -f; done

Yeah, I could have save a few lines of code by playing around with printf to format the ticket number, but as I said, this was quick and dirty. This script simply iterates through the numbers 10 through 9999, crafts a URL with the right number of digits for accelio_eticket_xxxx.pdf, and uses curl (a text-based web browser) to download the documents. "-o" tells curl to save the files instead of displaying them immediately, and "-f" tells curl to skip over anything that returns an HTTP error (primarily, HTTP 404, file not found). That way the only output was actual files found.

After the script finished, I had the following actual PDF files downloaded from the website:
$ ls -n *.pdf
-rw-rw-r-- 1 1000 1000 115717 Aug 1 17:32 114.pdf
-rw-rw-r-- 1 1000 1000 125712 Aug 1 17:32 115.pdf
-rw-rw-r-- 1 1000 1000 115870 Aug 1 17:40 1314.pdf
-rw-rw-r-- 1 1000 1000 132497 Aug 1 17:33 159.pdf
-rw-rw-r-- 1 1000 1000 173673 Aug 1 17:42 1654.pdf
-rw-rw-r-- 1 1000 1000 133126 Aug 1 17:33 165.pdf
-rw-rw-r-- 1 1000 1000 115790 Aug 1 17:53 4214.pdf
-rw-rw-r-- 1 1000 1000 193983 Aug 1 17:53 4254.pdf
-rw-rw-r-- 1 1000 1000 133961 Aug 1 17:59 5659.pdf
-rw-rw-r-- 1 1000 1000 126696 Aug 1 17:35 754.pdf
-rw-rw-r-- 1 1000 1000 239680 Aug 1 18:14 9109.pdf
-rw-rw-r-- 1 1000 1000 117555 Aug 1 18:15 9214.pdf
-rw-rw-r-- 1 1000 1000 329222 Aug 1 18:15 9254.pdf
-rw-rw-r-- 1 1000 1000 112211 Aug 1 17:36 994.pdf

What do you know? There were 14 PDF documents, ranging from 114 to 9254. That would have taken a while to figure out manually, but the computer did it for me in about a half hour while I was productive doing other things.

Next up was to run all of these files through Didier's pdfid.py script, which gives a simple result showing the number of a variety of types of objects that each file contains. In particular, I was looking for JS and Javascript objects, as those are frequently how an Adobe PDF is exploited.:

$ pdfid.py *.pdf | less
PDFiD 0.2.1 9109.pdf
PDF Header: %PDF-1.6
obj                   50
endobj                50
stream                32
endstream             32
xref                   0
trailer                0
startxref              1
/Page                  0
/Encrypt               0
/ObjStm                7
/JS                    1
/JavaScript            2

/AA                    0
/OpenAction            0
/AcroForm              1
/JBIG2Decode           0
/RichMedia             0
/Launch                0
/EmbeddedFile          0
/XFA                   0
/Colors > 2^24         0

Of all the PDFs, only one contained any Javascript. Now we're getting somewhere. I then opened 9109.PDF in PDFStreamDumper (a program available for Windows), and had it search for Javascript objects. Examining the two Javascript blocks led me to object 129, which was a bitmap image embedded in the PDF file:


Embedded in the PDF is an image with the final flag for this month

With that, I have solved all four puzzles for the month of July. Alas, only the first three finishers win prizes, so my only reward is a place on the leaderboard. Now on to August...


The end of July: on the leaderboard, but not in a prize-winning spot :-(