Post

PicoCTF - Super Serial

Description: Try to recover the flag stored on this website http://mercury.picoctf.net:2148/.

  1. The homepage looks like this:

  2. When visiting robots.txt we get the following:

  3. Strangely enough, if we visit /admin.phps we get an error:

  4. After searching what exactly .phps files are, we find [this] article:

    PHP files will get interpreted by the Web server and PHP executable, and you will never see the code behind the PHP file. If you make the file extension .PHPS, a properly-configured server will output a color-formated version of the source instead of the HTML that would normally be generated.

  5. Based on that, we can infer that our server is configured to have .phps files, since there is a /admin.phps directory, so we can try see if that works on the /index.php by visiting /index.phps:

  6. We have 3 things of interest on the above code:
    1. A new script: cookie.php.
    2. Another script: authentication.php.
    3. A setcookie method which includes serialization.
  7. After visiting the source code for each page, i.e., /cookie.phps and /authentication.phps, we see that the latter has an object of the class access_log which has the log_file attribute and uses the __toString method to read that log and get its content:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
     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);
         }
    

    We know that our flag is under ../flag, therefore, if we have an access_log object equal to that would be really handy.

  8. On the cookie.phps code we have the following code:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
     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);
         }
     }
    

    The .$perm variable represents our flag and it is shown when a deserialization error occurs. Thus, our goal is to trigger such an error.

  9. If we go to the /authentication directory and manually add the login cookie giving it a random value we get the following:

  10. So we managed to invoke a deserialization error. The next step is to find a way to properly serializes the cookie with its value as ../flag. We can replicate the serialization process based on index.phps code: setcookie("login", urlencode(base64_encode(serialize($perm_res))). We can try serializing a simple string and check it gets deserialized when we pass it as a cookie:

    W3 PHP Online Compiler.

  11. It successfully deserialized our cookie. Instead of just a string, we need an object of class access_log whose log_file attribute will be equal to ../flag:

  12. If we now pass that string as the value of the cookie login, we will get the flag back:

Resources

This post is licensed under CC BY 4.0 by the author.