четверг, ноября 15, 2007

XSS & PNG

Хоть это и кажется бредом но это возможно. Делается это простым дописыванием html-кода в конец PNG-файла. В итоге браузер выплёвывает текстовое содержимое файла наружу и код выполняется. Неудобств у этой атаки 3:

  1. Атакуемый должен обратится непосредственно к картинке, а не к страничке её содержащую. Например www.server.com/image1.png.
  2. Многие популярные движки хранят расширение файлов в базе, а сами файлы лежат переименованные в отдельной папке с одним и тем же расширением (например '.ext').
  3. Такие атаки проходят только с браузером Internet Explorer. Тот -же FireFox просто пишет что изображение повреждено.
Как видите ограничения хоть и есть, но они не слишком значительны(кроме второго). Теперь разберём всё на практике. Давайте напишем небольшой скрипт который будет отвечать за аплоад картинок на сервер и форму в которой пользователь будет выбирать какую картинку загрузить.

index.html:
<form enctype="multipart/form-data" action="upload.php" method="post">
Отправить этот файл: <input name="userfile" type="file" />
<input type="submit" value="Send File" />
</form>
upload.php:
<?php
// Изображения сохраняем в папку images
$upload_dir = "images/";
$upload_file = $upload_dir . basename($_FILES['userfile']['name']);
move_uploaded_file($_FILES['userfile']['tmp_name'], $upload_file);
?>
У нас есть самый простой аплоадер картинок. Теперь нарисуйте в любом редакторе картинку (например точку) и сохраните. Далее откройте эту картинку простым текстовым редактором и допишите в конец текст <script>alert(1)</script>. Если всё нормально то обратившись к этому изображению с помощью IE Вы увидите окошко с цифрой 1 и кишки картинки в виде обычного набора странных символов. Теперь нужно поставить фильтр на этот аплоад что бы он не пропускал опасные картинки. Давайте сделаем это на примере тега ''. Мы будем действовать следующим образом:
  1. Сохраним загруженное изображение
  2. Откроем как текстовый файл и возьмём внутренности
  3. В получившемся тексте будем искать <script
  4. Если данное выражение найдётся то удалим файл и сообщим об этом.
Вот код который нужно добавить в аплоадер после загрузки файла:
// Открываем файл для чтения
$handle = fopen($upload_file, "r");
// Читаем весь полностью
$file_text = fread($handle,filesize($upload_file));

fclose($handle);
// Если обнаружился <script
if (strpos($file_text,'<script')>-1)
{
// то удаляем этот файл и сообщаем пользователю
unlink($upload_file);
print 'XSS image!';
}
Теперь создайте ещё одно изображение только полностью безопасное и попробуйте загрузить его на сервер. У меня всё прошло нормально, а вот на загрузку опасного файла скрипт выругался. Естественно надо фильтровать не только тег но и тэги типа <embed>,<applet> и т.д.. Так же нужно не забывать о фильтрации полного слова javascript. А перед проверкой лучше текстовые внутренности перевести через функцию strtolower() так как могут попасться и <script></script> и JAvAscRIpT:alert(1)
И ещё. Не вздумайте проверять изображения на наличие '<' и '>' так как эти символы присутствуют в коде каждой картинки и каждое PNG-изображение будет считаться опасным. Удачи!