Веб-безопасность/Уязвимости FileUpload: различия между версиями
(→Задания) |
Lgeek19 (обсуждение | вклад) (→Стенды) |
||
(не показаны 2 промежуточные версии 2 участников) | |||
Строка 154: | Строка 154: | ||
print("А я - index.php!"); | print("А я - index.php!"); | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | После подключения sub.php, содержимого этого файла доступно в index.php. | + | После подключения sub.php, содержимого этого файла доступно в index.php. Есть также include. Отличия между require() и include() таковы, что require() возвращает FATAL ERROR, если файл не найден, include() же возвращает только WARNING. |
+ | |||
==Полезные константы== | ==Полезные константы== | ||
* __DIR__ — полный путь к директории, в которой находится текущий сценарий | * __DIR__ — полный путь к директории, в которой находится текущий сценарий | ||
Строка 336: | Строка 337: | ||
=Стенды= | =Стенды= | ||
− | * http://easy.stands.prak.seclab.cs.msu.ru | + | Внимание: сначала определите, в какой директории лежит файл. |
− | * http://type.stands.prak.seclab.cs.msu.ru | + | * http://easy.stands.prak.seclab.cs.msu.ru (Создайте php-файл с web shell одним из способов, описанных в презентации. Загрузите его на сайт. Перейдите по ссылке для просмотра изображения и получите флаг с помощью web shell-а). |
+ | * http://type.stands.prak.seclab.cs.msu.ru (Подключите Burp suite. Загрузите web shell. Перехватите запрос к серверу и замените Content type, соответствующий изображению.) | ||
=Ссылки= | =Ссылки= | ||
− | * [https://drive.google.com/file/d/1Jep20CuBfcfKAeStwnHgR0gCf-O2Wgd0/view?usp=sharing | + | * [https://drive.google.com/file/d/1Jep20CuBfcfKAeStwnHgR0gCf-O2Wgd0/view?usp=sharing Презентация] |
+ | * [https://disk.yandex.ru/i/iyE_cBCrH2VWUg Видео] | ||
* [https://www.php.net/ https://www.php.net/] - сайт PHP | * [https://www.php.net/ https://www.php.net/] - сайт PHP | ||
* [https://htmlacademy.ru/tutorial/php https://htmlacademy.ru/tutorial/php] - учебник PHP | * [https://htmlacademy.ru/tutorial/php https://htmlacademy.ru/tutorial/php] - учебник PHP |
Текущая версия на 11:24, 14 октября 2023
Содержание
Введение
Загрузка файлов пользователями - довольно частая часть функциональности веб-приложения (аватарки, хостинг файлов, посылка вложений вместе с сообщениями и т. д.). Небезопасная реализация этого механизма может приводить к очень серьезным уязвимостям. Загрузка файлов необходима многим сервисам, таким как файлообменники, социальные сети, онлайн-конверторы и редакторы.
Самый простой способ реализации механизма загрузки файлов - просто создавать на файловой системе сервера файл с таким же содержимым как файл, отправленный пользователем (проще говоря, "класть" присланный пользователем файл куда-то на файловую систему сервера). После загрузки файл либо доступен пользователю по прямой ссылке (т. е. определенные URL-адреса отображаются на загруженные файлы и существует URL, обращение к которому ведет к отдаче загруженного файла), либо как то еще обрабатывается веб-приложением. Само веб-приложение во многом состоит из файлов на диске, поэтому добавление файлов на сервер может быть небезопасным, так как (в общем случае) может изменить логику работы приложения. Соответственно, могут появляться следующие уязвимости:
- Remote Code Execution
- перезапись или удаление файлов
- Local File Read, SSRF
- Denial of Service
- Information Disclosure
- XSS
PHP
PHP (PHP: Hypertext Preprocessor) — скриптовый язык общего назначения, интенсивно применяемый для разработки веб-приложений.
Привет, мир!
Простейшая программа, выводящая надпись "Привет, мир!":
<?php print("Привет, мир!");
Каждый скрипт должен начинаться с <?php
и желательно (но не всегда обязательно) на ?>
. Пример кода, где ?>
обязателен:
<html>
<head>
<title>Наша первая php страница</title>
</head>
<body>
<h1><?php print("Привет, мир"); ?></h1>
</body>
</html>
Переменные
В синтаксисе PHP имя переменной записывается латинскими символами, но первым символом всегда должен быть знак доллара $, после чего идёт имя. Не допускается начинать имя переменной с цифры, а также использовать любые значения, кроме букв алфавита и знака подчеркивания.
Правильные переменные:
$age
$favorite_color
$name2
Неправильные переменные:
age
$42
$my-age
Переменные бывают нескольких типов:
$favorite_color = "green"; // строка
$favorite_number = 42; // целое число
$favorite_float_number = 0.5; // число с плавающей точкой
$favorite_bool = true; // boolean
Числа можно складывать, вычитать, делить, умножать опреаторы стандартные, как и во всех языках: +, -, *, /, % - плюсь, минус, умножить, делить (деление не целочисленное), остаток от деления.
Конкатенация
Конкатенация - "cклейка" нескольких строчек в одну.
<?php
$united_string = "Мой любимый цвет - " . $favorite_color . ", а любимое число - " . $favorite_number;
print($united_string);
В коде выше $favorite_number - число. Поэтому данная переменная приводится к типу данных "строка", после чего уже происходит конкатенация.
Ввод данных
Данная функциональность редко используется, но нам это нужно было для решения задач на лекии. readline - функция ввода данных:
<?php
$line = readline();
print($line);
Массивы
Массив — структура данных, хранящая набор значений (элементов массива), идентифицируемых по индексу.
В обычных массивах в PHP индекс значение - целое число. Нумеруются массивы с 0:
<?php
$fav_shows = ["game of thrones", "american horror story", "walking dead"];
В ассоциативных массивах в качестве индекса может использоваться не только число. Например, строка:
<?php
$user = ['age' => 42, 'name' => 'Иннокентий', 'fav_shows' => ["game of thrones", "american horror story", "walking dead"] ];
Условный оператор
Синтаксис: if (условие):
if ($gender == "мужчина") {
print("Приветствую тебя, мой Господин!");
} else if ($gender == "женщина") {
print("Приветствую тебя, о Госпожа!");
} else {
print("Не хватает гендеров.");
}
- оператор присваивания: =
- операторы сравнения: ==, ===, !=, !==, >, <, <=, >=
- and, or - логические и и или соответственно
Циклы
Синтаксис while: while (условие_остановки):
<?php
$i = 0;
while ($i < 10) {
print($i);
$i = $i + 1;
}
Синтаксис for: for (команда,_выполняемая_до_цикла; условие_осатновки; команда,_выполняемая_в_ конце_каждой_операции):
<?php
for ($x = 0; $x < 10; ++$x) {
print($x);
}
Для асоциативных массивах есть цикл foreach:
<?php
$user = [
'Имя' => 'Евгений',
'Возраст' => '27',
'Род занятий' => 'Программист'
];
foreach ($user as $key => $value) {
print($key . ': ');
print($value . '<br>');
}
Функции
Синтаксис: имя_функции(аргументы_функции):
function is_even($number) {
if ($number % 2 != 0) {
return false;
} else {
return true;
}
}
if (is_even(3)) {
print("3 - четное число");
} else {
print("3 - нечетное число");
}
Подключение файлов
Чтобы не писать всё в одном файле, используется команда require. Содержимое файла sub.php:
<?php
print("Привет, я содержимое из sub.php!");
Содержимое файла index.php:
<?php
require 'sub.php';
print("А я - index.php!");
После подключения sub.php, содержимого этого файла доступно в index.php. Есть также include. Отличия между require() и include() таковы, что require() возвращает FATAL ERROR, если файл не найден, include() же возвращает только WARNING.
Полезные константы
- __DIR__ — полный путь к директории, в которой находится текущий сценарий
- __FILE__ — полный путь к текущему сценарию
- $_COOKIE — ассоциативный массив, содержащий куки
- $_SESSION — ассоциативный массив, содержащий информацию о сессии
- $_POST — ассоциативный массив, содержащий данные, полученные после POST запроса
- $_GET — ассоциативный массив, содержащий данные, полученные после GET запроса
Примеры
1. Пусть есть сайт с формой: Клиент:
<form name="feedback" method="POST" action="form.php">
<label>Ваше имя: <input type="text" name="name"></label>
<label>Ваш email: <input type="text" name="email"></label>
<label>Сообщение: <textarea name="message"></textarea></label>
<input type="submit" name="send" value="Отправить">
</form>
При получении формы сервером, данные из неё можно получить следующим образом: Сервер:
<?php
if (isset($_POST)) {
print("Имя: " . $_POST['name']);
print("<br>Email: " . $_POST['email']);
print("<br>Сообщение: " . $_POST['message']);
}
2. Другой пример - отправка формы: Клиент:
<form name="file_upload" method="POST" action="form.php" enctype="multipart/form-data">
<label>Ваш аватар: <input type="file" name="avatar"></label>
<input type="submit" name="send" value="Отправить файл">
</form>
Работать с файлом ожно следующим образом: Сервер:
<?php
if (isset($_FILES['avatar'])) {
$file = $_FILES['avatar'];
print("Загружен файл с именем " . $file['name'] . " и размером " . $file['size'] . " байт");
}
Если не переместить файл в постаянную папку - файл будет удален:
$current_path = $_FILES['avatar']['tmp_name'];
$filename = $_FILES['avatar']['name'];
$new_path = dirname(__FILE__) . '/' . $filename;
move_uploaded_file($current_path, $new_path);
SQL
Так же можно работать с базами данных. mysqli_connect - функция для подключения к mysql-серверу, mysqli_query - отправка sql-запроса:
<?php
$link = mysqli_connect("localhost", "root", "");
$sql = 'INSERT INTO cities SET name = "Санкт-Петербург"';
$result = mysqli_query($link, $sql);
if ($result == false) {
print("Произошла ошибка при выполнении запроса");
}
web shell
Простейшим примером является загрузка файла с расширением .php на сайт, работающий на PHP (в качестве проверки можно попробовать обратиться по адресу cite.com/index.php и не получить ошибки). По умолчанию PHP-сайты работают так что пользователь обращается по URL к файлу (URL сайта, начиная с первого /, отображаются на определенную директорию на сервере, она называется web root) и, если этот файл имеет расширение php (или другое расширение из предопределенного списка расширений для PHP-файлов), то содержимое этого файла выполняется как код на PHP, вывод этого кода возвращается пользователю в ответе (кстати, так работает не только PHP, но и ASP.NET Web Forms, JSP, ASP). В результате, если пользователь может загрузить на сайт файл c расширением .php и обратиться к нему по URL (т. е. этот файл будет создан где-то внутри web root), то, если сервер специально не настроен чтобы файлы из директории для загрузок не выполнялись, PHP-код в нём будет выполнен. Соответственно, загрузив на уязвимый сайт файл shell.php
с кодом
42 * 66613; <?php system('ls -lsa'); ?>
и, получив ссылку на него (к примеру, /uploads/5c8e82bb8ad66/attack.php), обратится по ней, то в результате этот PHP-код выполнится и в ответе сервера будет произведение чисел 42 и 66613, а также список всех файлов в длинном формате (функция PHP system работает так же как одноимённая функция библиотеки Си - то есть выполняет команду shell). В итоге атакующий получает выполнение произвольного кода на сервере (RCE).
Обход методов защиты и атака
Валидация имени файла
Черный список ресширений
Обходится с помощью использования двойных расширений (shell.php.png
) или малоизвестный расширений (.php5
, .phtml
, .shtml
, .htaccess
). Кроме того, возможна инъекция нулевого байта (shell.php%00.jpg
) или регистрозависимость при проверке (PHp3
, .aSp
).
Белый список расширений
Спасает от использования атакующим малоизвестных и регистрозависимых расширений, но все ещё обходится с помощью двойных расширений или инъекции нулевого байта.
Санитайзеры
Оставляет большую степень свободы. Например, если санитайзер удаляет вхождения подстрок типа .php
, то использования имени файла вида shell.p.phphp
позволяет после загрузки получить файл с именем shell.php
.
Валидация Content-Type
Обходится изменением заголовка Content-Type, например, с помощью перехватывающего прокси (burp suite). Соответсвенно, в запросе
POST / HTTP/1.1 Host: easy.fu.khashaev.ru Content-Length: 200 Content-Type: multipart/form-data; boundary=----WebKitFormBoundary ------WebKitFormBoundary Content-Disposition: form-data; name="file"; filename="info.php" Content-Type: text/php <?php phpinfo(); ?> ------WebKitFormBoundary--
строчка Content-Type: text/php
может быть заменена на строчку Content-Type: image/png
.
Прочее
.htaccess - конфигурационный файл веб-сервера Apache, позволяющий управлять работой веб-сервера и настройками сайта с помощью различных параметров (директив) без изменения основного конфигурационного файла веб-сервера.
Server Side Includes - язык для динамической «сборки» веб-страниц на сервере из отдельных составных частей и выдачи клиенту полученного HTML-документа. Имеет расширения .shtml, .stm или .shtm. Например, при загрузке и вызове file.shtml, содержащего код
<!-- #exec cmd="ls" -->
атакующему будет выведен список файлов данной директории.
Static HTML
При возможности загрузить на сервис статический HTML, создается HTML-страница, содержащая вредоносный код (например, крадущего cookie), и ссылка на этот файл отправляется жертве.
Path Traversal
Атака, основанная на использовании специфически составленных имен файлов (например, ../config.ini
), позволяющих выйти за пределы директории хранения файлов. Может привести к переписыванию исходных фалов веб-приложения, конфигурационных или системных файлов.
Атака возможна, если не используется функция basename
(возвращает последний компонент имени из указанного пути) или её аналог.
Filename XSS
Сервис уязвим к XSS, если допускается имя файла вида <script>alert(1)</script>
.
Полиглоты
Полиглотами называют файлы, которые могут быть корректно распознаны как файлы разных типов. Можно встраивать
Структура JPEG
Все jpeg-файлы имеют схожую структуру. Рассмотрим в качестве примера изображение
В hex-редакторе оно выглядит следующим образом
В структуре jpeg-файлов содержатся служебные маркеры, состоящие из двух байт и всегда начинающиеся с FF.
- FF D8 - маркер начала jpeg-файла;
- FF DA - маркер начала секции Start of Scan:
- в двух байтах хранится длинна заголовка изображения [00 0C];
- заголовок изображения [03 01 00 02 11 03 11 00 3F 00];
- непосредственно информацию о самом изображении;
- FF D9 - маркер конца jpeg-файла.
Image Magic
ImageMagick — набор программ для чтения и редактирования файлов множества графических форматов, свободное и кроссплатформенное ПО. Может использоваться с языками Perl, C, C++, Python, Ruby, PHP, Node.js, Pascal, Java, Delphi, в скриптах командной оболочки или самостоятельно. ImageMagick обладает широким набором возможностей (конвертация, маскирование, увеличение контрастности и т.п.) и поддерживает работу с различными типами файлов, но так же в нем находили различные уязвимости:
- RCE [CVE-2016-3714]
- SSRF [CVE-2016-3718]
- File deletion [CVE-2016-3715]
- File moving [CVE-2016-3716]
- Local File Read [CVE-2016-3717]
CVE - Common Vulnerabilities and Exposures - база данных общеизвестных уязвимостей информационной безопасности.
Был создан сайт ImageTragick, посвященный описанию некоторых уязвимостей ImageMagic.
Пример.
Допустим, что есть некоторый онлайн-сервис, позволяющих переводить файлы в разные форматы, использующий библиотеку ImageMagic. Тогда, создав файл exploit.mvg с содержанием
push graphic-context viewbox 0 0 640 480 fill 'url(https://example.com/ image.jpg " ; | ls "-la)' pop graphic-context
и выполнив запрос на преобразование файла, аналогичный команде
$ convert exploit.mvg out.png
атакующий получит список всех файлов директории.
Стенды
Внимание: сначала определите, в какой директории лежит файл.
- http://easy.stands.prak.seclab.cs.msu.ru (Создайте php-файл с web shell одним из способов, описанных в презентации. Загрузите его на сайт. Перейдите по ссылке для просмотра изображения и получите флаг с помощью web shell-а).
- http://type.stands.prak.seclab.cs.msu.ru (Подключите Burp suite. Загрузите web shell. Перехватите запрос к серверу и замените Content type, соответствующий изображению.)
Ссылки
- Презентация
- Видео
- https://www.php.net/ - сайт PHP
- https://htmlacademy.ru/tutorial/php - учебник PHP
- http://www.php.su/php/?php - ещё один учебник
- Полиглоты
- Валидация структурных типов