CSAW CTF 2015 - Forensics 100 Transfer Writeup

This challenge starts off with the following hint:

I was sniffing some web traffic for a while, I think i finally got something interesting. Help me find flag through all these packets.

This challenge started off with a pcap. Let’s take the cheap way out and do a basic Wireshark filter for frame contains flag:

Awesome - looks like we found a packet. Following the TCP stream reveals a Python script (formatted - you’re welcome) and what appears to be the output of the script:

import string
import random
from base64 import b64encode, b64decode

FLAG = 'flag{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}'

enc_ciphers = ['rot13', 'b64e', 'caesar']
# dec_ciphers = ['rot13', 'b64d', 'caesard']

def rot13(s):
    _rot13 = string.maketrans( 
    "ABCDEFGHIJKLMabcdefghijklmNOPQRSTUVWXYZnopqrstuvwxyz", 
    "NOPQRSTUVWXYZnopqrstuvwxyzABCDEFGHIJKLMabcdefghijklm")
    return string.translate(s, _rot13)

def b64e(s):
    return b64encode(s)

def caesar(plaintext, shift=3):
    alphabet = string.ascii_lowercase
    shifted_alphabet = alphabet[shift:] + alphabet[:shift]
    table = string.maketrans(alphabet, shifted_alphabet)
    return plaintext.translate(table)

def encode(pt, cnt=50):
    tmp = '2{}'.format(b64encode(pt))
    for cnt in xrange(cnt):
        c = random.choice(enc_ciphers)
        i = enc_ciphers.index(c) + 1
        _tmp = globals()[c](tmp)
        tmp = '{}{}'.format(i, _tmp)

    return tmp

if __name__ == '__main__':
    print encode(FLAG, cnt=?)

2Mk16Sk5iakYxVFZoS1RsWnZXbFZaYjFaa1prWm<snip>

We see that there are three different encryption/encoding routines available - base64 encoding, a caesar cipher, and a rot13 function. Let’s dissect the encode function to see if we can figure out what’s going on with the input.

It looks like we start off by base64 encoding the input and prepending “2” to it. Then, as many times as specified (the default is 50), we choose a random function and run it on the current input.

The important line in our reversal is tmp = '{}{}'.format(i, _tmp). This line prepends the output of the function chosen with the function’s index in enc_ciphers + 1. This makes sense, as the index + 1 of the base64 encode function is 2, and that’s exactly what we prepend to the initial input before base64 encoding it.

So, in a nutshell here are the corresponding keys:

  • 1 - rot13
  • 2 - base64 encode
  • 3 - caesar cipher

All we have to do to get the original flag is to reverse this process. We have to start by creating the inverse of our functions. Rot13 is its own inverse, and for Caesar cipher we can just change shift=3 to shift=-3. Then, we only have to add the following base64 decode function:

def b64d(s):
    return b64decode(s)

Finally, we just need to put the pieces together to do the reversing. I used the following decode and main functions:

def decode(pt):
	while "flag" not in pt:
		i = int(pt[0])
		raw = pt[1:]
		print "Running function " + dec_ciphers[i-1]
		_pt = globals()[dec_ciphers[i-1]](raw)
		pt = _pt
	print pt

if __name__ == '__main__':
	with open('csaw_data.txt', 'r') as raw:
		print decode(raw.read().strip())

This gives us the following output:

Running function b64d
Running function b64d
Running function caesard
Running function b64d
Running function b64d
Running function b64d
Running function b64d
Running function rot13
Running function b64d
Running function caesard
Running function caesard
Running function caesard
Running function rot13
Running function rot13
Running function rot13
Running function b64d
Running function rot13
Running function rot13
Running function rot13
Running function b64d
Running function caesard
Running function caesard
Running function rot13
Running function b64d
Running function caesard
Running function caesard
Running function caesard
Running function b64d
Running function b64d
Running function b64d
Running function b64d
Running function b64d
Running function caesard
Running function b64d
Running function rot13
Running function rot13
Running function caesard
Running function caesard
Running function caesard
Running function caesard
Running function caesard
Running function caesard
Running function caesard
Running function caesard
Running function b64d
Running function b64d
Running function caesard
Running function caesard
Running function caesard
Running function b64d
Running function rot13
Running function caesard
Running function b64d
Running function caesard
Running function b64d
Running function rot13
Running function caesard
Running function rot13
Running function caesard
Running function caesard
Running function b64d
flag{li0ns_and_tig3rs_4nd_b34rs_0h_mi}

There’s the flag! flag{li0ns_and_tig3rs_4nd_b34rs_0h_mi}

Jordan (@jw_sec)

Jordan Wright

Security Researcher, Programmer, Time's 2006 Person of the Year

San Antonio, Texas