BaltCTF 2012 - Asia 400 Writeup
Well, I came home yesterday quite late, so I only had time to “play” for about ~4 hours. Meanwhile, my team solved some other challenges, but I solved the Asia 400 challenge.
In this challenge you got a zipped file called “images.rar”. Inside were lots of .gifs, either black or white. It was immediately obvious that this was a QR code, since there were 626 pictures [25*25 QR Version 2 code, ??+1 seeming random image??].
Stitching them together wasn’t hard, I just used the standard PIL library to handle straightforward image manipulation.
The only real “tricky” part here was figuring out the name-convention used to name the gifs. They were named like this
11.gif
12.gif
…
2512.gif
111.gif
11(1).gif
{see for yourself in the .rar - LINKHERE}
At first I tried sorting them alphabetically, but no cigar. I also tried using a natural sorting script for python (sorting them the same way explorer.exe does, e.g. Team 1 [Team 101 Team 12 Team 21] -> [Team 1 Team 12 Team 21 Team 101] instead of the alphabetically [Team 1 Team 101 Team 12 Team 21]http://www.codinghorror.com/blog/2007/12/sorting-for-humans-natural-sort-order.html), but nothing seemed to work.
After some thinking I figured out that they just concanted the “x” and “y” coordinates of each “pixel” in the QR code without any concantetor - e.g. x=2, y=12 would become 212. Obviously this would introduce collisions at x=5, y=12 and x=21, y=2, so they solved this by putting the “y” into brackets if a collision arose. This explained the strange numbering scheme. Instead of wasting hours on regex and complicated scripts to parse the existing names, I just went for a script that “recreated” this numbering scheme in the right order from scratch, which worked out pretty well - “if you can’t bring mohammed to the mountain bring the mountain to mohammed” and all that…
Any, without further ado, here is the final script used to generate the QR codes - http://pastebin.com/J8MFZTUW or:
import Image, os, math
#Start by scanning the directory and getting results
fakelist = []
for x in range(1, 26):
for y in range(1, 26):
if((20<x<25 and 0<y<10) or (10<x<13 and 0<y<10)): #Since the existing file names seem to regard the entire series 20-25 as collisions, we'll do that to :|
fakelist.append(str(x) + "(" + str(y) + ")" + ".gif")
elif((str(x) + str(y) + ".gif") in fakelist):
print "we fd up!!!!"
os.exit()
else:
fakelist.append(str(x) + str(y) + ".gif")
print fakelist
finalimage = Image.new('RGB', (300, 300))
for imageno, imagename in enumerate(fakelist):
print str(imageno) + " and name: " + imagename + "\n"
tempimage = Image.open('images/' + imagename)
pixel = tempimage.crop((0, 0, 12, 12))
row = int((math.floor(imageno/25)))
column = int(((imageno) % 25))
print str(row) + ":" + str(column)
finalimage.paste(pixel, (column*12, row*12, (column+1)*12, (row+1)*12))
del tempimage
finalimage.save("output.jpg")
See you at defcon CTF! :D