MozillaCTF Write-Up SecureFileLock (250)
This very secure locking mechanism encloses files and only gives them to you when you know the passphrase. Find it and you will have the flag.
Ok, let’s see. It’s a 64bit ELF binary, which means no easy “Press F5 in IDA”. Let’s run it
$:~/tmp/mozillactf$ ./securefilelock Welcome to Secure File Lock Playing 'Ethereal Awakening' by Project Divinity (CC BY-NC-SA 2.5) Please enter your password. (max length = 32):
Ok, let’s see what it does in strace if we enter any password (boring stuff omitted).
$:~/tmp/mozillactf$ strace -eexecve ./securefilelock execve("./securefilelock", ["./securefilelock"], [/* 37 vars */]) = 0 Welcome to Secure File Lock Playing 'Ethereal Awakening' by Project Divinity (CC BY-NC-SA 2.5) Please enter your password. (max length = 32): a Processing............................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................. execve("/usr/bin/vlc", ["/usr/bin/vlc", "--play-and-exit", "/tmp/sf.KpQB3w"], [/* 37 vars */]) = -1 ENOENT (No such file or directory)
Ok, so it writes to a temp file and tries to run it in vlc. Let’s try the same thing for password “b”. The get another file which differs in every bytes. Oh well, this sounds like XOR. Entering “ab” as a password results in a file that matches every second byte to the corresponding files for “a” and “b” – ok, its XOR.
Now, let’s once again look at the output we got when the programm started.
Welcome to Secure File Lock Playing 'Ethereal Awakening' by Project Divinity (CC BY-NC-SA 2.5)
Googling for ‘Ethereal Awakening’ and the exact filesize, we find a torrent which lists multiple MP3 files. At this point, there are two ways to handle things. a) Download the MP3 or b) be lucky and have challenge authors that think ahead. Let’s go with b), the CTF was fun up until this point.
MP3? They will probably have a header! Looking at any given MP3 they all shared the same 7 bytes.
49 44 33 03 00 00 00
Ok, so we know the extracted file is an MP3 audio file and we know how the first 7 bytes look. Let’s hope for the condition of b) (challenge authors that think ahead) and guess that the XOR key is 7 bytes long. The idea now is to generate all possible outcomes of the file using just one byte long XOR keys.
import os for i in range(ord('a'),ord('z')+1): os.system("echo %s | ./securefilelock" % chr(i)) os.system("mv /tmp/sf.* /tmp/unpacked_%s" % chr(i)) for i in range(ord('A'),ord('Z')+1): os.system("echo %s | ./securefilelock" % chr(i)) os.system("mv /tmp/sf.* /tmp/unpacked_%s" % chr(i)) for i in range(ord('0'),ord('9')+1): os.system("echo %s | ./securefilelock" % chr(i)) os.system("mv /tmp/sf.* /tmp/unpacked_%s" % chr(i))
After we have generated this, let’s look at each byte until we have found the right key.
import base64 from itertools import izip, cycle import sys import glob def xor_crypt_string(data, key): return ''.join(chr(ord(x) ^ ord(y)) for (x,y) in izip(data, cycle(key))) orig = "ID3\x03\x00\x00\x00" secret = dict() for fn in glob.glob("/tmp/unpacked_*"): char = fn[fn.find("_")+1:] cont = open(fn,"r").read() for i in range(0,7): if cont[i] == orig[i]: secret[i] = char sk = secret.keys() sk.sort() print ''.join(secret[s] for s in sk)
Which returns “yciNhAh” – 250 points.
Leave a Reply