๐ Super Serial
A detailed write-up of the Web challenge 'Super Serial' from PicoCTF - 2021
๐ Challenge Overview
Category Details Additional Info ๐ Event PicoGym Event Link ๐ฐ Category Web ๐ ๐ Points 500 Out of 500 total โญ Difficulty ๐ก Medium Personal Rating: 4/10 ๐ค Author madStacks Profile ๐ฎ Solves (At the time of flag submission) 7.240 solve rate ๐ Date 20-02-2025 PicoGym ๐ฆพ Solved By mH4ck3r0n3 Team:
๐ Challenge Information
Try to recover the flag stored on this website http://mercury.picoctf.net:25395/
๐ฏ Challenge Files & Infrastructure
Provided Files
1
Files: None
๐ Initial Analysis
First Steps
Initially, the website appears as follows:
with a login screen. Initially, I thought it might be an
SQL Injection
, but after trying some classic payloads, nothing happened. Since itโs a blackbox challenge, I decided to inspect the page source, but I didnโt find anything interesting. There was just aform
withaction="index.php"
. So, I tried checking forrobots.txt
:and this returned a positive result. As we can see, thereโs a
Disallow: /admin.phps
, but.phps
seemed strange. The first question I asked myself was, “Is this some sort of typo?” But I quickly answered this myself. Indeed, after trying to visit the route/index.phps
, I discovered that by adding the finals
, it was possible to see thephp
code:up to this point, nothing too strange, except for that
serialize()
which immediately made me think of anInsecure Deserialization
. I also noticed that arequire_once("cookie.php");
was specified, so I tried visiting the route/cookie.phps
and got the source:it also references another file with a
.php
extension, namelyauthentication.php
, so I tried reading the source the same way with/authentication.phps
:Now that I have the source code of the challenge, we can move to the code analysis phase. The first vulnerable part can be found in
cookie.php
:
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); } }
here, as we can see, there is a check to see if the
login
cookie is set (in the rest of the code, the login cookie is set only if the login is successful, either as aguest
or as anadmin
). So, if the cookie exists, it is URL-decoded, base64-decoded, and then deserialized. Therefore, this cookie should be a serializedpermissions
object, especially since theis_guest()
andis_admin()
functions, which belong to thepermission
class, are called afterward. Finally, if any exception is thrown or any type of error occurs, thereโs acatch
block that prints the error and the$perm
object (which should be thepermission
class object). However, as we can see:
1 2 3 4
function \__toString() { return $u.$p; }
the
permission
class implements themagic method __toString()
. This method defines the behavior of the object when any type of casting to a string is performed. In this case, it concatenatesusername
andpassword
, so when a casting is done, as we saw in the previousif
statement, it will print$u.$p
. This behavior can be exploited by causing any kind of error during the deserialization of the object in thetry
block. In the challenge hints, we are told that the flag is located at the route../flag
, so keep that in mind because it will become useful shortly when analyzing the new vulnerable code. The other file that contains vulnerable code isauthentication.php
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
class access_log { blic $log_file; nction \__construct($lf) { his->log_file = $lf; nction \__toString() { turn $this->read_log(); nction append_to_log($data) { le_put_contents($this->log_file, $data, FILE_APPEND); nction read_log() { turn file_get_contents($this->log_file); } require_once("cookie.php"); if(isset($perm) && $perm->is_admin()){ sg = "Welcome admin"; og = new access_log("access.log"); og->append_to_log("Logged in at ".date("Y-m-d")."\n"); } else { sg = "Welcome guest"; }
Trying to visit the page, we only get a
Welcome Guest
, as we can see from the code above:Disregarding this, regarding the vulnerable code above, we can definitely say that it can be exploited in some way to read
../flag
, as I believe itโs the only way and thosefile_get_contents
functions will certainly be useful for something. The other vulnerable part is therequire_once("cookie.php")
, as it will invoke the check seen earlier, which is vulnerable to deserialization of a malicious object. However, with an object of thepermission
class, we cannot do anything, unfortunately. Fortunately, we have another class available:access_log
, with which we can serialize a malicious object. Indeed, we can exploit the serialization of the object to set the attribute$log_file = "../flag"
, so when theread_log()
function is called, we could read the../flag
file instead of theaccess.log
file. However, this is only possible because of the previously seen check, as without that check, we wouldnโt be able to achieve deserialization, let alone read the output of the../flag
file. In fact, by deserializing a maliciousaccess_log
object with$log_file = "../flag"
, and setting it as thelogin
cookie, it will enter theif
statement, but when it calls$perm->is_guest()
, we will get an error, because we are not using an object of thepermission
class, which has theis_guest()
function declared, but rather using an object of theaccess_log
class, which doesnโt have that function. This will lead to thecatch
, and thatโs where the magic happens. In fact, as we can see, theaccess_log
object also declares the magic method__toString()
, which calls theread_log()
function. So when the exception occurs, it will printDeserialization error. File content passed to the $log_file parameter
, because it will cast the object to a string, call theread_log()
function, which will grab the content of the../flag
file using thefile_get_contents()
function and print it.
๐ฌ Vulnerability Analysis
Potential Vulnerabilities
- PHP Insecure Deserialization
๐ฏ Solution Path
Exploitation Steps
Initial setup
Once the vulnerability and how to exploit it are understood, we need to figure out how to create the malicious serialized object. We could do this manually, because by doing a couple of searches, we can understand how the
serialize()
function in PHP serializes objects and by what criteria it does so. For example (a little spoiler, the final serialized object is the following:O:10:"access_log":1:{s:8:"log_file";s:7:"../flag";}
). In this case,O:10
indicates the number of characters inaccess_log
(which is the class of the object to be serialized). Next, we find:1:
which indicates the number of parameters the class has. Inside the curly braces, we finds:8:"log_file";s:7:"../flag";
wheres
represents the type (String
),8
is the number of characters inlog_file
, and following the same logic, we find the value we want to pass to thelog_file
attribute, in this case, obviously../flag
. However, as we can see, itโs better not to go crazy and write it manually. Letโs move on to the exploitation phase to see how to proceed thinking outside the box.
Exploitation
The
serialize()
function produces an output like the one we saw earlier, right? This function takes an object to serialize, and in this case, we want to serialize the object of theaccess_log
class, correct? So, a much simpler approach would be to copy theaccess_log
class into a.php
file, or directly use https://onlinephp.io/, instantiate it with the attribute$log_file = "../flag"
, and serialize it to obtain the serialized object output (even though in the code analyzed earlier, as we mentioned, when it is deserialized, it first decodes fromurlencode
, then frombase64
, and then deserializes it). So, to get the correct output, we can simply reverse the encoding order and follow the process described earlier. To recap and make it clearer, Iโll leave you a screenshot of the code to obtain the serialized object:Once serialized, all we have to do is open
ChromeDevTools
, add thelogin = Malicious Serialized Object
cookie, and visit the/authentication.php
route to obtain the flag.
Flag capture
๐ ๏ธ Exploitation Process
Approach
The automatic exploit serializes the object by passing
"../flag"
in the constructor to set$log_file = "../flag"
. Once the malicious serialized object is built, it is set in thelogin
cookie aslogin=malicious_serialized_object
and a request is made usingPHP cURL
, extracting the flag from the response using a regex.
๐ฉ Flag Capture
Flag
Proof of Execution
๐ง Tools Used
Tool Purpose PHP Exploit ChromeDevTools Web Testing
๐ก Key Learnings
New Knowledge
I have learned to exploit the PHP vulnerability related to object deserialization.
Time Optimization
Replicating the class of the vulnerable object right from the start and serializing it while modifying the necessary attributes that we need.
Skills Improved
- Binary Exploitation
- Reverse Engineering
- Web Exploitation
- Cryptography
- Forensics
- OSINT
- Miscellaneous
๐ References & Resources
Learning Resources
๐ Final Statistics
Metric | Value | Notes |
---|---|---|
Time to Solve | 00:20 | From start to flag |
Global Ranking (At the time of flag submission) | Challenge ranking | |
Points Earned | 500 | Team contribution |
Created: 20-02-2025 โข Last Modified: 20-02-2025 *Author: mH4ck3r0n3 โข Team: *