Plaid CTF 2012 – RoboDate

So apparently robots, despite their lack of hormones, still have an underlying desire to mate. We stumbled upon a robot dating site, RoboDate. Hack it for us!
We found the source code for this robot encryption service, except the key was redacted from it. The service is currently running at
Title: RoboDate (100)
Category: Password Guessing

The challenge is to get admin rights on a robo-dating website.

When we open the website there appears to be very limited functionality available. After doing a view source we see a hidden login form:

    <form action="/59ec1e5173d9cb794f1c29bc333f7327/login.py" method="POST">
        <lable for="username">Username:</label>
        <input id="username" name="username" placeholder="Username">
        <label for="status">Dating status:</label>
        <input id="status" name="status" placeholder="Single">
        <input value="Login" type="submit">

Let’s try to submit some data to it, to see what happens.

$ curl -v -L -d 'username=abc&status=def'
< Location: frontpage.py?token=fa28d9e350239a00f60ddb91715b7e42882aeb9ed4c5682ebef01cbb6c20cf27
    debug info:

    user_data = abc|def|user
    key = Only admins can see the key.

From that output is seems pretty clear we need to manipulate user_data to end in |admin. But how do we do that. Let’s try to manipulate the token value. The initial token we received was fa28d9e350239a00f60ddb91715b7e42882aeb9ed4c5682ebef01cbb6c20cf27. Let’s see what happens if we change the first fa to f0.

$ curl -s
token=f028d9e350239a00f60ddb91715b7e42882aeb9ed4c5682ebef01cbb6c20cf27 | grep -A1 user_data
    user_data = kbc|def|user
    key = Only admins can see the key.

So changing fa to f0 changed the first character of the key from a to k. That looks like xor and indeed python can confirm that:

>>> 0xfa ^ 0xf0 == ord('a') ^ ord('k')

So we can very easily implement a small program to manipulate the text to be what we want:

import os
def string_xor(a,key):
        return ''.join(chr(ord(a[i]) ^ ord(key[i%len(key)])) for i in range(len(a)))

h = 'f028d9e350239a00f60ddb91715b7e42882aeb9ed4c5682ebef01cbb6c20cf27'.decode('hex')
u = 'abc|def|user'
w = 'abc|de|admin'
key = string_xor(u,h)
want = string_xor(w,key).encode('hex')
h = want + h[len(u):].encode('hex')
os.system('curl -s | grep -A1 user_data' % h)

Running this yields the key:

$ python t.py 
    user_data = kbc|de|admin
    key = 2012-04-25_14:46:24.29582+05:27@2012%