Category Archives: CTF

NetWars — Tournament of Champions

Last week I competed in the NetWars Tournament of Champions competition put on by SANS at their annual Cyber Defense Initiative in Washington, D.C. It was a great opportunity to flex one’s cyber muscle. Here is a link to their press release on the event.

NetwarsThe competitive atmosphere was palpable and as the tournament began ramping up you could very nearly taste the excitement in the air. It was obvious when the scoring servers opened, because one hundred or so giddy hackers were instantaneously shrouded in a mantle of silence. Game time! I battled my way through progressively challenging obstacles to the beat of some of the most… interesting… music I’ve ever heard in my life, but at the end of day one I was actually only in 9th place overall. Walking back into the room on day two instantly transported you back into the zone, and if our monotone responses to Ed Skoudis’ enthusiastic questions were anything to judge by; we were raring to go. When they finally released the hounds, it was as if we had immediately run into a brick wall. The new NetWars is much more difficult than its predecessor. I’d have to say that that is what helped me; when things got hard I started to shine.

Exposure, if there were a word for what I took away from NetWars that would be it. While trolling the Internet for tricks and practicing them against your own network is great, I really think that the best way to develop the critical thinking skills necessary to be a real threat, is to be confronted with something new. The bad guys have it easy. There is an overabundance of new yet juicy targets for them to interdict, readily available on the web. For the ethical hackers among us acquiring this experience is much more difficult, and we need it if we are to keep the wolves at bay. NetWars Tournament of Champions was an all-new sequence of challenges that forced you to evaluate the problem, hypothesize potential solutions, and finally break in. There are few ways to improve your tradecraft that can compare.

On to the spoils! Everyone invited to the Tournament of Champions received exceedingly nifty, yet awkward to wear, sound activated, flashing shirts. Unintended bonus, you can swap in the batteries from your shirt if your Bluetooth keyboard runs out of juice, nice!

Grand prize at NetWars Tournament of Champions – The Golden Ticket:

goldenticket2You have won FIRST PLACE in the second annual SANS NetWars Tournament of Champions, an achievement of outstanding, astonishing proportions. Through in-depth knowledge, cutting-edge skills, and deep cunning, you secured victory!

As the ultimate winner, winner you will enjoy a trip to spend an amazingly geektastic day at NetWars Research World Headquarters. You’ll observe first-hand the NetWars super-secret lair and command center. Your exclusive travel voucher is valid for up to $500 in flight costs, plus one night of hotel accommodations, and entitles you to spend a full day with Ed Skoudis and his team, seeing how they design, build, and operate SANS NetWars challenges.

It gets even better. You’ll tour the steam punk office, a perfect blend of 1880’s design and cutting-edge technology, infused with a collection of historical crypto systems and curious gadgets. Your adventure will include the Secret Room, the Secret-Secret Room, and experiments with a genuine World War Two Enigma machine. You’ll also feast with Ed and the team at a nearby restaurant, geeking out with in-depth discussions of all things infosec.

But, wait, there’s more! Best of all, during your special day, you’ll get to experience the new SANS NetWars CyberCity. This miniaturized town, chock full of NetWars missions, is our most ambitious challenge ever, designed to teach cyber warriors how cyber action can have kinetic effect against real-world systems. As the ultimate NetWars champion, you’ll get serious bragging rights as you complete several CyberCity missions!

Hereby duly signed, with hearty congratulations, by:

Ed Skoudis, Yori Kvitchko

I also received a plaque commemorating my victory:


Finally, the scoreboard at the end of the competition!


SANS Holiday Challenge 2012

The Year Without a Santa… Hack

Matthew Toussain (0sm0s1z)
Geoffrey Pamerleau (d0m3$t1c)
Christopher Shields (r00t0v3r1d3)

Thank you to Tim Medin, Ed Skoudis, and Tom Hessman for a fun Friday evening.

Guiding Questions

Where did you find the remainder of Snow Miser’s Zone 1 URL?

Snow Miser failed to utilize appropriate OPSEC measures. As such the remainder of his Zone 1 could be found in the reflection on his “Ice Cold Drink”.

What is the key you used with steghide to extract Snow Miser’s Zone 2 URL? Where did you find the key?

The key used was “IceIceBaby!”
I was located in the meta data of the off.jpg image

On Snow Miser’s Zone 3 page, why is using the same key multiple times a bad idea?

Using the same keys multiple times is a bad idea because if an attacker can deduce the key for one encryption they can use it to decrypt all messages, which were encrypted with the reused key. Since we had access to a combination of known plaintext and ciphertext we could determine the key used and then apply it to the encrypted Zone 4 URL.

What was the coding error in Zone 4 of Heat Miser’s site that allowed you to find the URL for Zone 5?

The PHP Header Redirect failed to specify exit() in order to force stop the execution of the remainder of the page.

How did you manipulate the cookie to get to Zone 5 of Heat Miser’s Control System?

Manipulating the UID cookie to the md5 of 1 allowed access to Heat Miser’s Zone 5 Control System.

Now for the real meat of the writeup:

Heat Miser – Write up:

Zone 0:

Viewing the source code gives us the KEY –> 1732bcff12e6550ff9ea44d594001418


Zone 1:

The solution to Zone 1 was simple once you read the HMISER Note on the Zone 0 page:

We had a security concern where the Zone 1 URL ended up in search engine results. We added a file to prevent the search engines from caching these pages. The system is now secure and no unauthorized users have access to the URL.

Search engines use the Robot Exclusion Standard to gain information on what pages on any given website are publically viewable. Participating Web Crawlers check for the existence of a robots.txt file to determine the pages on the web site to exclude.

For our purposes, browsing to this file yields the URL of Heat Miser’s Zone 1 Controller:

Viewing the source gives us the KEY –> d8c94233daef256c42bb95bd61382e02


Zone 2:

The HIMSER Note on the Zone 1 page indicates that a link to Zone 2 existed at one time. Viewing the page source reveals the following comment:

<!-- redacted, too many people clicked on the link and took it offline
<a href="/zone-2-761EBBCF-099F-4DB0-B63F-9ADC61825D49">Zone 2</a>

Copying the zone information to the URL bar grants us access to Zone 2. Viewing the source code gives us the KEY –> ef963731de7e886226fe4a6a6c2971f1


Zone 3:

Heat Miser gives us the first portion of the link to get to Zone 3:


But to get to Zone 3 we need a little bit more information. It helps to stalk our targets! @sn0w_m1s3r gives us our first clue:

“Another oops. Brilliant move @h34t_m1s3r. Your OS X term is semi-transparent, hot head! Oh, & u don’t need Metasploit for any of these zones”

Following the breadcrumbs brings us to a tweet by @h34t_m1s3r:

“Hot dog! We have some toolz ready in case we need them later

If we analyze the image we can see the URL bar of Heat Miser’s browser through his transparent terminal. Opening the image in Gimp and adjusting the brightness and levels makes the image easier to read. Putting the pieces together gives us the new link:


Viewing the source code gives us the KEY –> 0d524fb8d8f9f88eb9da5b286661a824


Zone 4:

Zone 3 gives us the link to Zone 4 right off the bat! Accessing the Control System on the other hand is not quite so straightforward. Browsing to the supplied link executes a PHP Header redirect sending the browser to noaccess.php. Snow Miser gives us a hint:


What he is referring to is an open redirect in Heat Miser’s code. The PHP code causing the redirect looks something like the following:


The problem results because Heat Miser failed to call exit() after the redirect. This means that the server continues to execute the rest of the code on the page. To access this code all that we need to do is navigate to the site with a browser that does not support PHP redirection. For our purposes we used Netcat:

nc 80

This pulls down the source and reveals the link to Zone 5 as well as the KEY –> e3ae414e6d428c3b0c7cff03783e305f


Zone 5:

Zone 5 is interesting… On first inspection it appears much the same as zone four, except for one major difference: cookies. Zone 5 uses cookies to authenticate a user before allowing access to the weather controller.  Inspecting the cookie by pasting javascript:alert(document.cookie) into the URL bar shows us what it is set to: UID=b8c37e33defde51cf91e1e03e51657da reversing the hash (we used reveals that the UID is set to the md5 of 1001. That is a standard user identification number under Linux systems. Using that schema the next step was to try changing the UID in order to privilege escalate. We originally tried 0 for root, but it was using a UID of 1 that gave us access:

javascript:void(document.cookie=”UID= c4ca4238a0b923820dcc509a6f75849b”)

We changed our cookie with the above URL injection, reloaded the page (Zone 5 not noaccess.php), and presto we’re in!

Viewing source gives us the KEY –> f478c549e37fa33467241d847f862e6f

Heat Miser Answers at a Glance:

Screen Shot 2013-06-24 at 6.38.19 PM


Snow Miser – Write up:

­­­­ Zone 0:

Viewing the source code gives us the KEY –> 1732bcff12e6550ff9ea44d594001418


Zone 1:

Snow Miser’s a bit too fond of his ice cold drinks! Someone should give tell him to use proper OPSEC because the link to his zone 1 URL is in the reflection on his glass. Flipping it horizontal and 180 degrees gives us the rest of the URL for Zone 1:


Viewing the source code gives us the KEY –> 38bef0b61ba8edda377b626fe6708bfa


­­­­Zone 2:

Snow Miser let’s us know that because of one of his snow-minions we have to do image analysis in order to get the URL for Zone 2. Step one is finding the image. The first trick is to get an image with a format that Steghide can use. Viewing the source to pull page resources shows us on.png, but if we click on the disable button. The resource changes to: off.jpg. Downloading the image and using exiftool on us gives us some notable metadata namely the passphrase:


The next step is to run steghide with the extract switch while specifying the above as the passphrase. Welcome to Zone 2!


Viewing the source code gives us the KEY –> b8231c2bac801b54f732cfbdcd7e47b7


Zone 3:

One of Snow Miser’s minions has been running rampant and messing up the Global Chiller Control System links! In order to facilitate access Snow Miser provides the first part of the Zone 3 URL for his authorized minions:


 Additionally, his fraternal nemesis has left us a whopper on Twitter:

“@h34t_m1s3r: Uh oh, @sn0w_m1s3r left his Ice Cream Sandwich Android phone at my volcano. Data extraction complete.”

From here we get the android file system of Snow Miser’s phone, jackpot! We check the browser cache with some Terminal Fu to see if he’s accessed the Chiller System from his phone:

“strings data/ | grep zone-3-EAB6B031”

Yay! Link:


Viewing the source gives us the KEY –> 08ba610172aade5d1c8ea738013a2e99


Zone 4:

Zone 3 Control System… almost there right? Look out, incoming crypto! Fortunately, Snow is kind enough to give us samples of his plaintext and ciphertext, “for verification purposes” of course:

Old Plaintext:


Old Ciphertext


New Ciphertext: 20d916c6c29ee54343e81ff1b14c1372650cbf19998f51b5c51bf66f49ec62184034a94fc9198fa9179849

Doing some careful eyeballing gives us some clues on how to start:

Old Plaintext:             z    o   n   e   –   4   –
Old Ciphertext:          20 d9 16 c6 c2 9e e5
New Ciphertext:        20 d9 16 c6 c2 9e e5

Let’s examine what we know. The ciphertext is exactly twice as long as the plaintext, and both sets of plaintext (the URLs) must start with zone-4-. The first 14 characters of both new and old ciphertexts were identical which aligns with the “zone-4-“. This gave us the hint that the same key was used to encrypt both the original and the old URL’s. On to the Python!

Our less then elegant solution……….

“knownpt = "zone-4-F7677DA8-3D77-11E2-BB65-E4BF6188709B"

knownct = "0x20 0xd9 0x16 0xc6 0xc2 0x9e 0xe5 0x3c 0x30 0xea 0x1e 0xff 0xc6 0x3b 0x1c 0x72 0x14 0x7e 0xb8 0x6b 0x99 0x8a 0x25 0xc0 0xcf 0x1b 0xf6 0x69 0x39 0xe8 0x62 0x1b 0x31 0x32 0xd8 0x3a 0xbb 0x16 0x83 0xdf 0x61 0x92 0x38"

knownctarray = knownct.split(" ")

unknownct = "0x20 0xd9 0x16 0xc6 0xc2 0x9e 0xe5 0x3c 0x30 0xea 0x1e 0xff 0xc6 0x3b 0x1c 0x72 0x14 0x7e 0xb8 0x6b 0x99 0x8a 0x25 0xc0 0xcf 0x1b 0xf6 0x69 0x39 0xe8 0x62 0x1b 0x31 0x32 0xd8 0x3a 0xbb 0x16 0x83 0xdf 0x61 0x92 0x38"

keyarray = unknownct.split(" ")

cttobreak = "0x20 0xd9 0x16 0xc6 0xc2 0x9e 0xe5 0x43 0x43 0xe8 0x1f 0xf1 0xb1 0x4c 0x13 0x72 0x65 0x0c 0xbf 0x19 0x99 0x8f 0x51 0xb5 0xc5 0x1b 0xf6 0x6f 0x49 0xec 0x62 0x18 0x40 0x34 0xa9 0x4f 0xc9 0x19 0x8f 0xa9 0x17 0x98 0x49"

cttobreakarray=cttobreak.split(" ")

count = 0
for c in knownpt:
   for i in range (256):
      result = hex(ord(c)^i)
      if result == knownctarray[count]:
         #print hex(i)
         #print result
   count = count + 1
answer = ""
for i in range(43):
print "The URL for Zone 4 is: " + answer

Since the length of the cipher text is exactly twice that of the plaintext we determined that Snow Miser took the ASCII of the URL and converted each character to hexadecimal. The plaintext was then encrypted using a byte-wise XOR with a one time pad (the key). XOR was assumed to be the operation performed on the two sets of bytes because an encryption algorithm is not a true encryption algorithm without XOR…right? Normally, this type of encryption would be impossible to reverse; luckily for us we were provided with a plaintext/ciphertext pairing. The python program allowed us to determine the key byte-by-byte. Once we had the key we could easily decrypt the posted ciphertext to obtain the Zone 4 URL we desired. The mess of Python above spits out the Zone 4 URL:


Viewing the source gives us the KEY –> de32b158f102a60aba7de3ee8d5d265a

Zone 5:

Zone 5 is top secret! Fortunately, the link to its URL can be found in the source code:


Additionally, Snow gives us the hint that the code is now part of an svn package management system (version 1.7). This means that we can pull down the Subversion Sqlite database by browsing to it:


Heat Miser gives us a clue on what to do from here by linking to a blog post by Tim Medin entitled: “All your svn are belong to us”


We open the database, check the table definitions (schema) to give ourselves a reference point, and grab the NODES:

sqlite3 wc.db
select local_relpath, ".svn/pristine/" || substr(checksum,7,2) || "/" || substr(checksum,7) || ".svn-base" as alpha from NODES;

This spits out the golden egg:


The next step is get to the Zone 5 Controller. Execute the following:

wget –O -

wget –O -

This returns the following output:

$accessallowed = FALSE;
$content = "<h1>Access Denied</h1>\n<!-- current server time is ".date('Y-m-d H:i').' -->';


function generate_otp($time) {
$pass = sha1("$time 7998f77a7dc74f182a76219d7ee58db38be3841c");

function verify_otp($inpass) {
    // passwords are valid for up to 3 minutes
    // don't forget to use the server time (see the noaccess.php page)

$validstamps = array(
    date('Y-m-d H:i', strtotime('+1 minute')), // added just in case the time sync is off
date('Y-m-d H:i'),
date('Y-m-d H:i', strtotime('-1 minute')),
date('Y-m-d H:i', strtotime('-2 minute')),

foreach ($validstamps as $stamp) {
   if (strtolower($inpass) == generate_otp($stamp))

        return TRUE;
return FALSE;

if ((array_key_exists('otp', $_POST) && verify_otp($_POST['otp'])) || (array_key_exists('otp', $_COOKIE) && verify_otp($_COOKIE['otp']))) {
    setcookie('otp', generate_otp(date('Y-m-d H:i')));
} else {
header( 'Location: noaccess.php' );

$accessallowed = TRUE;

Uh oh! Access Denied, but we did manage to get some of the server side code pertaining to the Controller’s Page. Examining it gives us insight. We need to hand the server a password in order to gain access to the Controller. Fortunately, noaccess.php tells us how to make a time based password, but to do that we need to get ahold of the server time. The server time can be found in the source of noaccess.php. Back to the Python!

import hashlib
salt = 7998f77a7dc74f182a76219d7ee58db38be3841c
hashlib.sha1(“2012-12-16 20:17 ” + seed).hexdigest() 

Output:           f614951b7f741dbbead5d47d285fcc47b1e63aec

We now have a three minute window to take the output and authenticate into the Zone 5 Controller from the Zone 4 page. That’s it!

Viewing the source gives us the KEY –> 3ab1c5fa327343721bc798f116be8dc6

Snow Miser Answers at a Glance:

Screen Shot 2013-06-24 at 7.03.55 PM


And that’s it! Hope you all enjoyed the writeup.