PicoCTF - Super Serial
Description: Try to recover the flag stored on this website
http://mercury.picoctf.net:2148/
.
The homepage looks like this:
When visiting
robots.txt
we get the following:Strangely enough, if we visit
/admin.phps
we get an error: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.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
:- We have 3 things of interest on the above code:
- A new script:
cookie.php
. - Another script:
authentication.php
. - A
setcookie
method which includes serialization.
- A new script:
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 classaccess_log
which has thelog_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 anaccess_log
object equal to that would be really handy.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.If we go to the
/authentication
directory and manually add thelogin
cookie giving it a random value we get the following: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 onindex.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:It successfully deserialized our cookie. Instead of just a string, we need an object of class
access_log
whoselog_file
attribute will be equal to../flag
:If we now pass that string as the value of the cookie
login
, we will get the flag back: