RSS

CSAW CTF 2013 – Miscellaneous 200

0 Comments | This entry was posted on Sep 29 2013

For this challenge the first thing I did was as most would do, open the image in an image viewer program (specifically the Windows default image viewer, nothing fancy.) I didn’t see anything eye-catching, and when viewing the file in a hex editor I didn’t see anything immediately out of the ordinary either, there was nothing packed in with the PNG, it looked as a normal PNG would look, with lots of arbitrary junk data, and apparently indicating the image was taken from an IPhone 5. I didn’t realise how important this would be for me to notice at that point in time, but it definitely helped.

Next, I used a program that utilizes ‘libpng’, a very reputable and extensible PNG reference library that has existed and been tested for some years now, to analyze the more technical data for the PNG.

I got a notification that read something about the CRC in the IHDR chunk (the first few bytes of the PNG): “Incorrect crc for IHDR chunk (is c1d0b3e4, should be fcc410a8)”

I then tried changing this integer value with a hex editor at offset 0x1D to the following 4 bytes {0xFC 0xC4 0×10 0xA8}, and in doing so actually gave me more errors, including CRC errors for IDAT chunks, and there were a lot of them. Coincidentally, I decided to make sure that I was heading in the right direction and making sure that the CRC expected was actually the original, and perhaps it was changed deliberately for this challenge. So I checked the data that was currently there in the image header:

- 8 bits/sample (normal)
- truecolor+alpha
- non-interlaced

The one other thing that didn’t seem right, judging by the fact that the tEXt chunk points to an IPhone 5 running IOS 6.1.4, was that the image size was 3264×1681. This does not match any of the standard aspect ratios: 16:10, 16:9, 4:3 etc… And I also figured that editing this image in most image editors to crop it down to a portion of that full image would have possibly removed some of the remains of what the IPhone embedded within that image as a ‘mark’, upon resaving. (Everybody loves to advertise their copyright in there, you know how it goes.)

Through more research an IPhone 5′s camera roll aspect ratio is 4:3. The calculation gave me the idea that the image had somehow been chopped down height-wise.

3264*3/4 = 2448
2448 != 1681

Now, obviously there is no way to get that pixel data back once the image is chopped data-wise, so I tried changing the image size in the header from 3264×1681 to 3264×2448, and by opening the image again in some image viewer, voila! The key was written on the whiteboard the entire time. :)

Revisiting that hint they gave for this challenge part-way through my investigation also backed up this theory, but it wasn’t until I edited the header to match a 4:3 aspect ratio that it was apparent for what that down arrow really meant. All I knew was that this had nothing to do with width or anything horizontal.

There were exactly 2 bytes that needed changing in order to solve this challenge in the end, starting at offset 0×16, that indicate the height of the image. The values, originally, {0×06 0×91}, that needed to be changed to any sufficiently large value big enough to view that ‘hidden’ key on the whiteboard. I just matched it up to a 4:3 aspect ratio and changed those bytes to {0×09 0×90}.

Leetmore CTF 2012: PPC 200 (Oscaderp Forensic)

0 Comments | This entry was posted on Oct 18 2012

The challenge was to get the flag out of the files contained in the archive attached.

We need your help, soldier!

Your goal today is to help us obtain the access to Oscaderp Corp mainframe.
Our intelligence has managed to install a keylogger and a formgrabber on some bad person’s work laptop. You don’t need his name to do your job.
Everything worked as planned, the victim visited mainframe’s authentication page, https://authen.intranet/, and started to type in the password.
But when he had a couple characters left, the keylogger got busted and hard-killed by him.

Present intelligence evidence:
[*] The password that’s being used is 1,048,576 characters long.
[*] According to our calculations, our keylogger managed to capture 1,048,568 password keystrokes.
[*] Formgrabber remained unnoticed, and in a few hours we’ve got the logs with successful mainframe authentication.
The only major problem: they use client-side MD5 to protect the password from being eavesdropped.
[*] We also managed to acquire the source code of the authentication mechanism

You can find all the necessary files in the archive.

YOUR GOAL: obtain the password to the mainframe, and post its SHA1 hash as the flag.

import md5
import sha

# Save the part of the password recorded by the keylogger in this variable.
# final length of recorded password = 1048568 characters
# complete password length = 1048576 characters
key_partial = ''

# Open keylogger file and extract the password related lines.
with open('keylogger_report_08_10_2012.txt', 'r') as fh:
for line in fh:
# Only look at lines that start with "Keys: ".
if line.startswith('Keys: '):
# Only extract lines that have more than 100 characters.
if len(line) > 100:
# Only extract the part after "Keys: " and don't copy
# "\r\n" and append to the partial key.
key_partial = key_partial + line[6:-2]

def bruteforce(key_partial):
"""
Bruteforce the password.

- Add "00000000" to "99999999" to the partial password.
- Compare the md5sum of this full password with the md5 hash
found in index.php ("287d3298b652c159e654b61121a858e0")
"""

md5_key_partial = md5.new()
md5_key_partial.update(key_partial)

for i in range(0,10):
print "Progress: " + str(i)
for j in range(0,10):
str_2 = str(i) + str(j)
for k in range(0,10):
str_3 = str_2 + str(k)
for l in range(0,10):
str_4 = str_3 + str(l)
for m in range(0,10):
str_5 = str_4 + str(m)
for n in range(0,10):
str_6 = str_5 + str(n)
for o in range(0,10):
str_7 = str_6 + str(o)
for p in range(0,10):
str_8 = str_7 + str(p)
md5_key_try = md5_key_partial.copy()
md5_key_try.update(str_8)

# If the md5 hash of our latest tested password matches,
# calculate the sha1 hash of this password and exit this function.
if md5_key_try.hexdigest() == "287d3298b652c159e654b61121a858e0":
sha_key = sha.new()
sha_key.update(key_partial + str_8)
print "\nSHA-key: " + sha_key.hexdigest() + "\n8 last characters: " + str_8 + "\n"
return

# Bruteforce the password.
bruteforce(key_partial)

The output from the above code was:

SHA-key: 947c83329e6cf2d9b747af59edf7974752afd741
8 last characters: 69880983

Solution: 947c83329e6cf2d9b747af59edf7974752afd741