GPN

Never Gonna Tell A Lie And Type You

  • simple authentication bypass in client-side with PHP type juggling

We are given 2 files, Dockerfile and index.php. I assume that the only purpose of the Dockerfile is to find the flag more easily … we can see that the flag is at /flag.txt. Let’s check out the index.php file:

function securePassword($user_secret){
    if ($user_secret < 10000){
        die("nope don't cheat");
    }
    $o = (integer) (substr(hexdec(md5(strval($user_secret))),0,7)*123981337);
    return $user_secret * $o ;

}
//this weird http parameter handling is old we use json
$user_input = json_decode($_POST["data"]);
//attention handling user data is dangerous

if ($_SERVER['HTTP_USER_AGENT'] != "friendlyHuman"){
    die("we don't tolerate toxicity");
}
    if($user_input->{'user'} === "admin🤠") {
        if ($user_input->{'password'} == securePassword($user_input->{'password'})  ){
            echo " hail admin what can I get you ". system($user_input->{"command"});
        }
        else {
            die("Skill issue? Maybe you just try  again?");
        }}

Okay so there are 4 main things to pay attention to 1. the parameters are accessed via POST request, in which the data variable holds a JSON, which has variables user and password 2. the user agent is checked if it matches friendlyHuman 3. the user variable is checked against admin🤠 4. the password is checked against securePassword function

We can bypass the first 3 points easily with burp, the last point might give us a headache

  • the secure function takes the password (checks if it is bigger than 10000), then takes 8B from the MD5 hash, multiplies it by some big value and multiplies the result with the original password
    • from this we can probably guess that the password must be an integer (otherwise we get an error when trying to multiply string with number)
  • we can notice that the password condition only uses loose comparison (== instead of ===), which can lead to type juggling
    • if password = 0e then the result of the securePassword function would also be 0 and the condition would be true
    • however we can’t do that because of the condition that the number must be larger than 10000
  • then I thought about putting some really big number as password … PHP must have some kind of limit on integer size, right?
    • I’ve decided to test the intermediate results of the securePassword function, let’s try with 10000

  • let’s try bigger number

  • let’s try number with 10000 digits

Okay so we can see that the integer is too big and it returned INF … what is not shown in the screenshot is also an error which comes from not specifying the command parameter, as we completed the last condition (yay!). Now just run on the real server and supply the command with cat /flag.txt: