G
Gidroponika
Введение
Если во время пентестов система или приложение позволяет загружать любые файлы, то задача, связанная с получением доступа к серверу и выполнением вредоносного кода, упрощается. С другой стороны, если есть ограничения и фильтр загружаемых файлов по расширению, то сначала нужно обойти эту проверку. В этой статье мы поговорим о том, как в веб-приложениях обрабатывают и проверяют файлы, загружаемые на сервер, а также методы обхода этих проверок.
Фильтрация на стороне клиента
В этом случае проверка происходит в браузере средствами JavaScript, VBScript или HTML5 перед отправкой файлов на сервер. Программисты используют этот метод для того, чтобы оптимизировать взаимодействие пользователя с приложением и быстро выдать ответ на уровне браузера.
Обход фильтрации на стороне клиента
В основном этот класс фильтров можно обойти двумя способами: посредством отключения JavaScript или изменения HTTP-запросов, формируемых в браузере, перед отсылкой серверу.
Пример:
3. function Validate(oForm) {
4. var arrInputs = oForm.getElementsByTagName("input");
5. for (var i = 0; i < arrInputs.length; i++) {
6. var oInput = arrInputs;
7. if (oInput.type == "file") {
8. var sFileName = oInput.value;
9. if (sFileName.length > 0) {
10. var blnValid = false;
11. for (var j = 0; j < _validFileExtensions.length; j++) {
12. var sCurExtension = _validFileExtensions[j];
13. if (sFileName.substr(sFileName.length - sCurExtension.length, sCurExtension.length).toLowerCase() == sCurExtension.toLowerCase()) {
14. blnValid = true;
15. break;
16. }
17. }
18.
19. if (!blnValid) {
20. alert("Sorry, " + sFileName + " is invalid, allowed extensions are: " + _validFileExtensions.join(", "));
21. return false;
22. }
23. }
24. }
25. }
26.
27. return true;
28. }
29. </script>
Как показано выше, JavaScript обрабатывает запрос перед отсылкой на сервер. Внутри кода происходит проверка, принадлежит ли расширение файла графическому формату (jpg, jpeg, bmp, gif, png). Этот метод фильтрации можно обойти после изменения содержимого запроса и самого файла на вредоносный код с расширением, способствующим выполнению этого кода.
Рисунок 1: Результат проверки файла на предмет присутствия расширения из списка графических форматов
Как показано на рисунке, загрузчик файлов приостанавливает отправку запроса, если мы пытаемся загрузить php-файл напрямую.
Рисунок 2: Запрос, формируемый во время загрузки файла
Мы смогли обойти эту проверку посредством загрузки изображения через браузер, последующего изменения расширения в запросе, который будет отсылаться на сервер, а также изменения содержимого файла. Мы поменяли расширения с .jpeg на .php и заменили содержимое файла на вредоносный код.
Проверка на стороне сервера
Более тщательная проверка имени файла происходит во время загрузки на сервер. В этом случае анализ расширения может выполняться множеством способов, но основных два: проверка по черному и белому спискам.
В черном списке находятся расширения файлов, которые не принимаются к загрузке ни при каких обстоятельствах, например, php, aspx. В случае с белым списком ситуация полностью противоположная. В этом перечне находятся только те расширения файлов, которые разрешены для загрузки на сервер, например, jpg, jpeg, gif.
Обход проверки на стороне сервера
Некоторые типы проверок можно обойти при помощи загрузки файла с не очень популярным расширением или используя различные трюки во время загрузки.
В случае с обходом черного списка можно попробовать загрузить файлы со следующими расширениями: pht, phpt, phtml, php3, php4, php5, php6.
Обход белого списка осуществляется при помощи некоторых трюков, как, например, добавление пустого байта в имя файла (shell.php%00.gif) или использование двойного расширения (shell.jpg.php).
В некоторых случаях проверку можно обойти при помощи расширений с измененным регистром одного из символов: pHp, Php, phP.
Пример:
3. echo "Sorry, only JPG, JPEG, PNG & GIF files are allowed.";
В коде выше показан пример кода загрузчика файлов, принимающего лишь несколько расширений (jpg, jpeg, gif). Далее рассмотрим пример обхода различных типов проверок.
Пример обхода черного списка
Рисунок 3: Обход фильтра при помощи загрузки файла с непопулярным расширением
На рисунке выше показан обход проверки при помощи загрузки файла с расширением .php5, который принимается сервером Apache и далее запускается автоматически как обычный php-файл.
Пример обхода белого списка
Рисунок 4: Обход фильтра при помощи загрузки файла с двойным расширением
На рисунке выше показано, как можно обойти белый список через загрузку php-файла с двойным расширением.
Проверка заголовка CONTENT-TYPE
В этом методе сервер проверяет содержимое файла на предмет присутствия корректного MIME-типа, который можно увидеть в HTTP-запросе. Например, некоторые загрузчики картинок проверяют, чтобы в заголовке Content-Type присутствовал тип image.
Обход проверкиContent-Type
Этот класс фильтров можно обойти посредством изменения в файле shell.php или shell.aspx содержимого параметра Content-Type на значение «image/png», «image/jpeg» или «image/gif».
Пример:
3. $mimetype = mime_content_type($_FILES['file']['tmp_name']);
4. if(in_array($mimetype, array('image/jpeg', 'image/gif', 'image/png'))) {
5. move_uploaded_file($_FILES['file']['tmp_name'], '/uploads/' . $_FILES['file']['name']);
6. echo 'OK';
7.
8. } else {
9. echo 'Upload a real image';
10. }
В коде выше мы видим, что проверяется MIME-тип, являющийся частью заголовка Content-Type, у файла, загружаемого на сервер. В данном случае загрузчик принимает только файлы со следующими типами: image/jpeg, image/gif и image/png. Мы можем легко обойти этот фильтр, изменив поле Content-Type во время загрузки исполняемого файла на тот MIME-тип, который принимается веб-сервером.
Рисунок 5: Пример измененного поля Content-Type при загрузке php-скритпа
Проверка заголовка CONTENT-LENGTH
В этом случае сервер проверяет размер содержимого заголовка Content-Length у загружаемого файла и не допускает загрузку файлов, у которых этот размер превышает определенное значение. Хотя этот метод не настолько популярен, но может использоваться в некоторых загрузчиках.
Обход проверкиCONTENT-LENGTH
Этот фильтр обходится при помощи загрузки вредоносного кода очень небольшого размера в зависимости от того, какое максимальное значение используется при сравнении веб-сервером. Максимальное значение можно выяснить через загрузку нескольких файлов различного размера с целью выяснения, какие файлы будут приниматься, а какие нет.
Пример:
3. }
В коде выше загрузчик не принимает файлы более 30 байт. Как было сказано выше, этот фильтр можно обойти при помощи загрузки вредоносного кода очень маленького размера.
Рисунок 6: Пример обхода фильтра по заголовку CONTENT-LENGTH
Если во время пентестов система или приложение позволяет загружать любые файлы, то задача, связанная с получением доступа к серверу и выполнением вредоносного кода, упрощается. С другой стороны, если есть ограничения и фильтр загружаемых файлов по расширению, то сначала нужно обойти эту проверку. В этой статье мы поговорим о том, как в веб-приложениях обрабатывают и проверяют файлы, загружаемые на сервер, а также методы обхода этих проверок.
Фильтрация на стороне клиента
В этом случае проверка происходит в браузере средствами JavaScript, VBScript или HTML5 перед отправкой файлов на сервер. Программисты используют этот метод для того, чтобы оптимизировать взаимодействие пользователя с приложением и быстро выдать ответ на уровне браузера.
Обход фильтрации на стороне клиента
В основном этот класс фильтров можно обойти двумя способами: посредством отключения JavaScript или изменения HTTP-запросов, формируемых в браузере, перед отсылкой серверу.
Пример:
- <script type="text/javascript">
3. function Validate(oForm) {
4. var arrInputs = oForm.getElementsByTagName("input");
5. for (var i = 0; i < arrInputs.length; i++) {
6. var oInput = arrInputs;
7. if (oInput.type == "file") {
8. var sFileName = oInput.value;
9. if (sFileName.length > 0) {
10. var blnValid = false;
11. for (var j = 0; j < _validFileExtensions.length; j++) {
12. var sCurExtension = _validFileExtensions[j];
13. if (sFileName.substr(sFileName.length - sCurExtension.length, sCurExtension.length).toLowerCase() == sCurExtension.toLowerCase()) {
14. blnValid = true;
15. break;
16. }
17. }
18.
19. if (!blnValid) {
20. alert("Sorry, " + sFileName + " is invalid, allowed extensions are: " + _validFileExtensions.join(", "));
21. return false;
22. }
23. }
24. }
25. }
26.
27. return true;
28. }
29. </script>
Как показано выше, JavaScript обрабатывает запрос перед отсылкой на сервер. Внутри кода происходит проверка, принадлежит ли расширение файла графическому формату (jpg, jpeg, bmp, gif, png). Этот метод фильтрации можно обойти после изменения содержимого запроса и самого файла на вредоносный код с расширением, способствующим выполнению этого кода.
![GS1poXPtuZg.jpg](/proxy.php?image=https%3A%2F%2Fpp.userapi.com%2Fc847221%2Fv847221778%2F106dbe%2FGS1poXPtuZg.jpg&hash=4235acc8f65f037a0765959971298792)
Рисунок 1: Результат проверки файла на предмет присутствия расширения из списка графических форматов
Как показано на рисунке, загрузчик файлов приостанавливает отправку запроса, если мы пытаемся загрузить php-файл напрямую.
![3McL4opxIPA.jpg](/proxy.php?image=https%3A%2F%2Fpp.userapi.com%2Fc847221%2Fv847221778%2F106dc7%2F3McL4opxIPA.jpg&hash=607ea6955f5eb12ecdde943aa25932cb)
Рисунок 2: Запрос, формируемый во время загрузки файла
Мы смогли обойти эту проверку посредством загрузки изображения через браузер, последующего изменения расширения в запросе, который будет отсылаться на сервер, а также изменения содержимого файла. Мы поменяли расширения с .jpeg на .php и заменили содержимое файла на вредоносный код.
Проверка на стороне сервера
Более тщательная проверка имени файла происходит во время загрузки на сервер. В этом случае анализ расширения может выполняться множеством способов, но основных два: проверка по черному и белому спискам.
В черном списке находятся расширения файлов, которые не принимаются к загрузке ни при каких обстоятельствах, например, php, aspx. В случае с белым списком ситуация полностью противоположная. В этом перечне находятся только те расширения файлов, которые разрешены для загрузки на сервер, например, jpg, jpeg, gif.
Обход проверки на стороне сервера
Некоторые типы проверок можно обойти при помощи загрузки файла с не очень популярным расширением или используя различные трюки во время загрузки.
В случае с обходом черного списка можно попробовать загрузить файлы со следующими расширениями: pht, phpt, phtml, php3, php4, php5, php6.
Обход белого списка осуществляется при помощи некоторых трюков, как, например, добавление пустого байта в имя файла (shell.php%00.gif) или использование двойного расширения (shell.jpg.php).
В некоторых случаях проверку можно обойти при помощи расширений с измененным регистром одного из символов: pHp, Php, phP.
Пример:
- if($imageFileType != "jpg" && $imageFileType != "png" && $imageFileType != "jpeg"
3. echo "Sorry, only JPG, JPEG, PNG & GIF files are allowed.";
В коде выше показан пример кода загрузчика файлов, принимающего лишь несколько расширений (jpg, jpeg, gif). Далее рассмотрим пример обхода различных типов проверок.
Пример обхода черного списка
![UycRbXkFcD4.jpg](/proxy.php?image=https%3A%2F%2Fpp.userapi.com%2Fc847221%2Fv847221778%2F106dd0%2FUycRbXkFcD4.jpg&hash=a178e39841e69f29dbfbe42a452d73ab)
Рисунок 3: Обход фильтра при помощи загрузки файла с непопулярным расширением
На рисунке выше показан обход проверки при помощи загрузки файла с расширением .php5, который принимается сервером Apache и далее запускается автоматически как обычный php-файл.
Пример обхода белого списка
![A3iTfs2FEoQ.jpg](/proxy.php?image=https%3A%2F%2Fpp.userapi.com%2Fc847221%2Fv847221778%2F106dd9%2FA3iTfs2FEoQ.jpg&hash=ab6877a355b6343b37f131151afe8c34)
Рисунок 4: Обход фильтра при помощи загрузки файла с двойным расширением
На рисунке выше показано, как можно обойти белый список через загрузку php-файла с двойным расширением.
Проверка заголовка CONTENT-TYPE
В этом методе сервер проверяет содержимое файла на предмет присутствия корректного MIME-типа, который можно увидеть в HTTP-запросе. Например, некоторые загрузчики картинок проверяют, чтобы в заголовке Content-Type присутствовал тип image.
Обход проверкиContent-Type
Этот класс фильтров можно обойти посредством изменения в файле shell.php или shell.aspx содержимого параметра Content-Type на значение «image/png», «image/jpeg» или «image/gif».
Пример:
- <?php
3. $mimetype = mime_content_type($_FILES['file']['tmp_name']);
4. if(in_array($mimetype, array('image/jpeg', 'image/gif', 'image/png'))) {
5. move_uploaded_file($_FILES['file']['tmp_name'], '/uploads/' . $_FILES['file']['name']);
6. echo 'OK';
7.
8. } else {
9. echo 'Upload a real image';
10. }
В коде выше мы видим, что проверяется MIME-тип, являющийся частью заголовка Content-Type, у файла, загружаемого на сервер. В данном случае загрузчик принимает только файлы со следующими типами: image/jpeg, image/gif и image/png. Мы можем легко обойти этот фильтр, изменив поле Content-Type во время загрузки исполняемого файла на тот MIME-тип, который принимается веб-сервером.
![iymgLhTgE8c.jpg](/proxy.php?image=https%3A%2F%2Fpp.userapi.com%2Fc847221%2Fv847221778%2F106de2%2FiymgLhTgE8c.jpg&hash=07211579ea09c071fe19de4c9d0747e3)
Рисунок 5: Пример измененного поля Content-Type при загрузке php-скритпа
Проверка заголовка CONTENT-LENGTH
В этом случае сервер проверяет размер содержимого заголовка Content-Length у загружаемого файла и не допускает загрузку файлов, у которых этот размер превышает определенное значение. Хотя этот метод не настолько популярен, но может использоваться в некоторых загрузчиках.
Обход проверкиCONTENT-LENGTH
Этот фильтр обходится при помощи загрузки вредоносного кода очень небольшого размера в зависимости от того, какое максимальное значение используется при сравнении веб-сервером. Максимальное значение можно выяснить через загрузку нескольких файлов различного размера с целью выяснения, какие файлы будут приниматься, а какие нет.
Пример:
- if ($_FILES["fileToUpload"]["size"] > 30) {
3. }
В коде выше загрузчик не принимает файлы более 30 байт. Как было сказано выше, этот фильтр можно обойти при помощи загрузки вредоносного кода очень маленького размера.
Рисунок 6: Пример обхода фильтра по заголовку CONTENT-LENGTH