Bypass Disable Functions

Bypass Disable Functions

@cherepawwka

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

Bypass Disable Functions

Мы познакомимся с интересным инструментом, оперирующим функциями PHP putenv() и mail(), для того чтобы получить шелл на сервере.

Приступим!

Введение

Что такое file upload vulnerability?

File upload vulnerability — это уязвимость, возникающая в веб-приложениях, где существует возможность загрузки файла без достаточной проверки его системой безопасности (проверки таких вещей, как имя, тип, содержимое или размер). Неспособность должным образом применить ограничения на файлы может означать, что даже базовая функция загрузки изображений может использоваться для загрузки произвольных и потенциально опасных файлов.

Наличие уязвимости позволяет злоумышленнику загружать файлы с интерпретируемым кодом (скрипты, такие как .php, .aspx и т.п.) и запускать их на том же сервере, на котором работает легитимное веб-приложение.

File upload vulnerability

Каково влияние уязвимостей загрузки файлов?

Влияние уязвимостей загрузки файлов обычно зависит от двух ключевых факторов:

  1. Какой аспект файла веб-сайт не может правильно проверить;
  2. Какие ограничения накладываются на файл после его успешной загрузки.

В худшем случае должным образом не проверяется тип файла, а конфигурация сервера позволяет выполнять определенные типы файлов (такие как .php или .jsp). В этом случае злоумышленник потенциально может загрузить на веб-сервер файл с вредоносным кодом, который содержит функционал веб-шелла и фактически предоставлет ему полный контроль над сервером.

Если имя файла не проверяется должным образом, это может позволить злоумышленнику перезаписать важные файлы, просто загрузив файл с таким же именем (например, перезаписать файл .htaccess для обхода некоторых ограничений веб-приложения). Если сервер также уязвим для уязвимости обхода каталогов (Path Traversal), злоумышленник может попытаться загрузить файл в непредвиденные места (например, перезапись файла ~/.ssh/authorized_keys и добавить свой открытый ключ для авторизации на сервере по SSH со своим закрытым ключом).

Неспособность проверить размер файла может привести к атаке типа «отказ в обслуживании» (DoS), когда злоумышленник заполняет доступное дисковое пространство.

Как веб-серверы обрабатывают запросы на статические файлы?

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

Исторически веб-сайты почти полностью состояли из статических файлов, которые предоставлялись пользователям по запросу. В результате путь каждого запроса может быть точно сопоставлен с иерархией каталогов и файлов в файловой системе сервера. В настоящее время веб-сайты становятся все более динамичными, и путь запроса часто вообще не имеет прямого отношения к файловой системе (это можно будет видеть в реализуемом мной на Flask приложении). Тем не менее, веб-серверы по-прежнему обрабатывают запросы на некоторые статические файлы, включая .js, .css, изображения и т.д.

Процесс обработки этих статических файлов практически не изменился. В какой-то момент сервер анализирует путь в запросе, чтобы определить расширение файла. Затем он использует это для определения типа запрашиваемого файла, обычно сравнивая его со списком предварительно настроенных сопоставлений между расширениями и MIME-типами. Дальнейшие действия зависят от типа файла и конфигурации сервера:

  1. Если этот тип файла не является исполняемым, например изображение или статическая HTML-страница, сервер может просто отправить содержимое файла клиенту в ответе HTTP.
  2. Если тип файла является исполняемым, например, файл PHP, и сервер настроен на исполнение файлов этого типа, он будет назначать переменные на основе заголовков и параметров в HTTP-запросе перед запуском сценария. Полученный результат затем может быть отправлен клиенту в ответе HTTP.
  3. Если тип файла является исполняемым, но сервер не настроен на выполнение файлов этого типа, он обычно отвечает ошибкой. Однако в некоторых случаях содержимое файла все же может быть передано клиенту в виде обычного текста. Такие мисконфигурации иногда могут использоваться для утечки исходного кода и другой конфиденциальной информации. 

Примечание. Заголовок ответа Content-Type может дать ключ к пониманию того, какой файл, по мнению сервера, он обслужил. Если этот заголовок не был явно задан кодом приложения, он обычно содержит результат сопоставления расширения файла и типа MIME.

Подробнее об уязвимости загрузки файлов можно прочитать на PortSwigger Academy (обращу особе внимание на интересные лабораторные по внедрению шелла в изображение и эксплуатацию Race Condition).

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


Инструментарий

В данной статье будет рассмотрен пример, связанный с языком PHP.

Среди мер по защите от загрузки веб-шеллов разработчики применяют отключение опасных функций, которые могут исполнять команды операционной системы или запускать процессы. В PHP это такие функции, как system() или shell_exec(). При разработке приложений они часто отключаются с помощью директив PHP, определенных в файле конфигурации php.ini. Другие функции, возможно, менее известные (например dl(), которая позволяет динамически загружать расширение PHP), могут остаться незамеченными системным администратором и могут быть не отключены. Один из этапов осуществляется тестирования на проникновение веб-приложения — перечислить, какие функции включены (на случай, если какие-то из опасных функций разработчиком были забыты).

Что мы знаем про менее "очевидные функции"?

Одна из самых простых и не очень распространенных техник — злоупотребление функциями mail() и putenv(). Эта техника не нова, gat3way уже сообщал PHP о ней в 2008 году, но она работает и по сей день. С помощью функции putenv() мы можем изменить переменные среды, что позволит нам присвоить желаемое значение переменной LD_PRELOAD. LD_PRELOAD позволит нам предварительно загрузить библиотеку .so перед остальными библиотеками, так что, если программа использует функцию библиотеки (например, libc.so), она будет выполнять функцию, которая содержится в нашей библиотеке. Таким образом, мы можем захватывать или «перехватывать» функции, изменяя их поведение по своему усмотрению.

Об этой технике мы сегодня и поговорим подробнее. Для примера я буду использовать Chankro, инструмент для обхода disable_functions и open_basedir.

Через Chankro мы сгенерируем PHP-скрипт, который будет действовать как дроппер, создавая на сервере библиотеку .so и бинарный файл (например, meterpreter) или bash-скрипт (reverse shell). Затем ПО вызовет функции putenv() и mail() для запуска нашего вредоносного файла.

Установить инструмент можно следующим образом:

git clone https://github.com/TarlogicSecurity/Chankro.git
cd Chankro
python2 chankro.py --help

Запускаем его следующей командой:

python2 chankro.py --arch 64 --input c.sh --output shell.php --path /var/www/html

Пробежимся по аргументам:

  • --arch — архитектура системы жертвы (32 или 64);
  • --input — файл с полезной нагрузкой для исполнения;
  • --output — имя PHP-файла, который мы собираемся создать; это и есть тот файл, который нужно будет загрузить на уязвимый сайт;
  • --path — в этом параметре необходимо указать абсолютный путь, по которому находится наш загруженный PHP-файл. Например, если наш файл находится в папке uploads, то указываемый путь будет таким: DOCUMENTROOT + uploads (здесь DOCUMENTROOT - значение переменной окружения, по умолчанию для большинства веб-серверов — /var/www/html).
Использование инструмента для создания полезной нагрузки

Теперь при выполнении скрипта PHP на веб-сервере будут созданы необходимые файлы для выполнения нашей полезной нагрузки.


Практика

Для примера поломаем уязвимую машинку с платформы TryHackMe. Первым делам сканируем полученный IP-адрес при помощи nmap|rustscan, чтобы получить список открытых портов, служб на них и собрать первоначальную информацию о цели. Для этих целей я использую простой скрипт, о котором неоднократно рассказывал в прошлых статьях:

Открытые порты на целевом хосте

Видим, что открыты 22 и 80 порт. 22 порт (SSH) нас не интересует, так что приступим к изучению 80 (HTTP). Это веб-сервер, следовательно, запускаем Burp, настраиваем скоуп ресурсов и начинаем ручной обход приложения:

Главная страница приложения

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

Путь к функции загрузки файлов

Из демонстрируемой на странице информации можно сделать вывод, что приложение позволяет загружать только изображения (первый этап защиты). Что же, попробуем обойти фильтры.

Первым делом я создал папку с тремя файлами разных расширений: 2 картинки и один вредоносный PHP-скрипт:

Тестовые файлы

Начнём с попытки загрузить PHP-скрипт:

Попытка загрузки скрипта
Результат загрузки PHP-файла

Как мы видим, приложение вернуло 200 ответ. Возможно, тут вовсе нет никакого фильтра. Попробуем найти, куда загружается файл. Для этого профаззим директории при помощи ffuf:

Поиск директорий с ffuf

Результат потрясающий. Помимо вероятной папки загрузок мы также нашли файл, выводящий результат функции phpinfo(). Но к нему вернёмся позже, а сейчас продолжим изучать функцию загрузки.

Перейдём в директорию uploads и посмотрим её содержимое:

Листинг директории uploads

То, что нам доступен листинг, сильно облегчает задачу. Но нашего файла тут нет, следовательно, есть какая-то проверка. Давайте попробуем загрузить теперь файл GIF:

Результат загрузки файла
Файл в директории

Результат не заставил себя долго ждать. Сразу же мы замечаем изменения в ответе на веб-странице, а файл виден при листинге директории. Что же, тут у нас есть два пути: попытка инжектить шелл в изображение (в рамках этой задачи не сработает) и обход фильтров на бэкенде. Как уже стало понятно, мы будем обходить фильтры!

Начнем искать разницу в запросах и ответах сервера при загрузке обоих файлов:

Ключевая разница при загрузке файлов

Ключевые моменты я подсветил красным цветом. Есть 3 вероятных способа обойти защиту:

  1. Изменить расширение файла (может повлиять на невозможность дальнейшего исполнения файла);
  2. Изменить Content-Type;
  3. Изменить magic numbers.

Проделаем 2 первых трюка сразу:

Попытка загрузки файла с изменёнными полями
Результат

Методом исключения понимаем, что суть проверки файла на стороне сервера сводится к проверке его первых битов, чтобы выявить реальное расширение (так как остальные поля заведомо истинные, и вот почему):

Попытка загрузки GIF под видом PHP
Результат загрузки

Всё, что нам осталось сделать, — это имитировать PHP-скрипт под GIF путем добавления первых нескольких байт, свойственных для GIF:

Сигнатуры файлов расширения GIF

Я буду использовать второй вариант, так как он заведомо рабочий :)

Сделать это можно при помощи hexeditor (предустановлен на kali) на локальной машине, а можно и в Burp Repeater:

Добавление байт в нагрузку
Успешная загрузка файла
Загруженный шелл!

Мы успешно обошли все ограничения! Однако, этот шелл работать не будет:

Шелл не работает
Ответ нашего приложение, подтверждающий исполнение скрипта

Вернёмся в моменту фаззинга директорий и вспомним про phpinfo.php:

phpinfo.php

Функция phpinfo(), вывод которой мы видим на экране, выводит информацию о текущей конфигурации PHP, раскрывая большое количество чувствительной информации. Среди них есть информация о disable functions:

disable_finctions

В скрипте я использовал shell_exec, который сервер обрабатывать не будет. Поэтому и наш шелл не работает. Но к нашему счастью тут не запрещены putenv() и mail().

Мы можем воспользоваться инструментом, о котором ранее шла речь. Но для него нам также нужно знать директорию загрузки в веб-приложении. Однако для этих целей у нас есть... phpinfo!

Ищем переменную DOCUMENT_ROOT и забираем её значение:

DOCUMENT_ROOT
/var/www/html/fa5fba5f5a39d27d8bb7fe5f518e00db 

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

/var/www/html/fa5fba5f5a39d27d8bb7fe5f518e00db/uploads

Скрафтим полезную нагрузку:

Создание вредоносного файла

После создания шелла пытаемся загрузить его, перехватив запрос в Burp Proxy, чтобы изменить Magic Numbers:

Шелл до
Шелл после

Перехватываем ответ на наш запрос:

Успешная загрузка файла

Проверяем директорию uploads:

Открываем листенер:

Переходим в браузере из uploads в shell.php и... ничего не произошло. Чуть позже я осознал ошибку и немного исправил скрипт:

Измененная нагрузка

В данном случае я добавил shebang, вновь загрузил скрипт, заменил magic numbers и исполнил его, поймав обратную оболочку:

Обратная оболочка!

Здесь я оставлю ещё один очень полезный трюк по стабилизации оболочки, которым я неоднократно пользовался в статьях ранее, но никогда подробно не описывал. Оболочка, пойманная nc, крайне нестабильна, имеет некрасивый вывод и не даёт возможности перемещаться по вводимым командам, использовать стрелки выше/ниже для ориентирования в истории команд, работать с текстовыми редакторами и т.п.

Для того, чтобы стабилизировать оболочку, нужно сделать следующее:

1) Создаем псевдотерминал, перед этим узнав версию имеющегося python (whereis python, whih python):

python -c 'import pty; pty.spawn("/bin/bash")' 
python2 -c 'import pty; pty.spawn("/bin/bash")' 
python3 -c 'import pty; pty.spawn("/bin/bash")' 

2) Пишем export TERM=xterm — это даст нам доступ к командам терминов, таким как clear;

3) Ctrl + Z — бэкграундим оболочку;

4) stty raw -echo; fg; — отключаем эхо в командной строке и возвращаем nc на передний план.

Стабилизированная оболочка

Запущу nano, чтобы продемонстрировать, что такой функционал теперь доступен:

Использование nano
Использование nano

Важно. После завершения работы (убийства процесса или exit) необходимо написать reset в терминале, чтобы вернуться к нормальному CLI.


До новых встреч!

До новых встреч!

Report Page