Cyber Jawara 2018 – Login Form

In where I live, there is this major CTF Competition called Cyber Jawara. A friend of mine saved the challenge and get it back to live for me to try 😀

He gave me a website like this:

Yes, I was confused too. I mean, how do I even exploit it? But he said that there’s a backend running so it should be injected by the URL.

Going through the code, we see that the first lines of code,

<?php
require 'flag.php';
function login($username, $hash) {
if ($username === 'CJ' && $hash === '81eb1cf42dc766553d51bc73d70adebe8607031b') {
return true;
} else {
return false;
}
}

it uses hash to verify the login. And in this case, we need to get into that one and only credential.

Let’s dive into the interesting part of the code:

function init($flag) {
    $query = array();
    if (!empty($_SERVER['QUERY_STRING'])) {
        $query_str = $_SERVER['QUERY_STRING'];
        $query = parse_str($query_str);
    }

In this line of codes, I never saw parse_str so I tried to look at it on the php website: http://php.net/manual/en/function.parse-str.php

It says that this parse_str is dangerous. Sweet! We need to find what’s dangerous of it.

We can see on the page this example:


<?php
$str = "first=value&arr[]=foo+bar&arr[]=baz";
// Recommended
parse_str($str, $output);
echo $output[‘first’];  // value
echo $output[‘arr’][0]; // foo bar
echo $output[‘arr’][1]; // baz// DISCOURAGED
parse_str($str);
echo $first;  // value
echo $arr[0]; // foo bar
echo $arr[1]; // baz
?>

What is discouraged was the usage of only 1 parameter instead of 2. And if you look closely, it provides output differently.

If you use 2 parameters, the content of $str will be inputted into an array of the second parameter.

If you use 1 parameter, the discouraged version, the content of $str will be a variable of its own.

This is the golden ticket. With this, we can input what is needed to bypass the login form.

But let’s see WHAT is needed to bypass the login form.

    if (!empty($query['action'])) {
$action = $query['action'];
}

if($action === ‘login’){
if(!empty($query[‘username’])){
$username = $query[‘username’];
}
if(!empty($query[‘password’])){
$password = $query[‘password’];
}
if(!empty($username) && !empty($password)){
$hash = sha1($password);
}
if(!empty($hash) && login($username, $hash)){
print “<h1>Welcome!<h1><br>”;
print $flag;
}else{
print “Wrong”;
}
}else{
highlight_file(__FILE__);
}
}

These are the chocolate fountain. We have here the query which includes the parse_str in it.

So, now we have to collect all content of the queries here.

From here, we see $action, $username, and $ password as the content of $query.

Thus, these are the payload we have to input.

But wait, if you see the validation code, $password will be hashed by sha1 and if we input anything in it, the hash which later validated will be different from what they need.

If we see closely, the code where they validate the password (!empty($password)) will not be executed if they don’t meet the requirements. Therefore, if we empty the password, they will not execute it so we don’t need to give them the password.

Instead, we need to give them the hash. This hash will act as the one from the hashed password we input at the login form. It will be compared with what they have.

Thus, our payload will be action=login&username=CJ&hash=81eb1cf42dc766553d51bc73d70adebe8607031b.

Integrate it with our url. In this case, I will made up the IP to hide my friend’s server information ;p

for example: 192.168.0.1/?action=login&username=CJ&hash=81eb1cf42dc766553d51bc73d70adebe8607031b

Enter it and we will get the flag 😀

Leave a Reply

Your email address will not be published. Required fields are marked *