Безопасность загружаемых изображений

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

XSS через картинки

AcdSee

Многие знают, что графические изображения формата jpg и tiff содержат в себе не только саму картинку, но и специальные данные, в которых хранятся комментарии, имя автора, дата создания, название фотокамеры и даже наличие или отсутствие факта использования вспышки при съемке. Эта информация носит название метаданных; она автоматически вставляется в заголовки изображения многими цифровыми камерами и сканерами. Существует два вида метаданных: EXIF (Exchangeable Image File) и IPTC. Эту информацию можно изменить с помощью специальных программ для работы с изображениями, например AcdSee.

Большинство опенсорсных фото-галерей умеют читать метаданные. Однако некоторые из них некорректно обрабатывают эту информацию, совершенно не проверяя, что находится внутри EXIF-заголовков. Это позволяет внедрить злонамеренный JS-код прямо в метаданные jpg-изображения и успешно выполнить его, если метаданные выводятся при просмотре изображений, т.е. возникает угроза XSS-атак.

Рассмотрим аспекты реализации на примере Coppermine Photo Gallery 1.3.2. В этой версии фото-галереи была допущена ошибка, позволяющая проводить активные XSS-атаки, подобно той, которую я описал выше. Итак, откроем нашу картинку с помощью AcdSee. Справа мы видим панель со свойствами изображения, выбираем вкладку EXIF и редактируем поле Camera Model. Далее записываем туда любой JavaScript или HTML код, например такой:

<script>alert(“XSS!”)</script>

Закрываем программу и закачиваем измененную картинку в фото-галерею. Теперь при просмотре изображения в фото-галерее вылетает алерт.

Чтобы устранить данную уязвимость, необходимо прогнать входящие метаданные через PHP-функцию htmlspecialchars(). Вот код, реализующий безопасное чтение всех EXIF-заголовков изображения:

<?php
$exif = exif_read_data('picture.jpg', 0, true);
echo "picture.jpg:<br>\n";
        foreach ($exif as $key => $section)
        {
                 foreach ($section as $name => $val)
                 {
                 echo htmlspecialchars("$key.$name: $val")."<br>\n";
                 }
         }
?>

Выполнение произвольного кода

Теперь перейдем к самому вкусному – выполнению произвольного кода. Множество ленивых администраторов пытаются обезопасить свои сайты путем ограничений в конфигурации PHP, при этом допуская довольно старую уязвимость – include bug. Казалось бы, ну, что можно приинклудить, когда стоит open_basedir? Да, конечно можно поискать лог-файлы, куда записывается наша активность, с целью выполнения кода, предварительно обратившись к web-серверу с запросом:

index.php?c=<?php system($cmd); ?>

Однако лог-файлы порой очень сложно найти и на самом деле гораздо проще воспользоваться следующим способом. Техника взлома заключается в том, что хакер указывает в качестве параметра, который передается в функцию include(), картинку, содержащую PHP-код в метаданных EXIF. Данный вид атак имеет место, если на атакуемом сайте есть форум, позволяющий загружать аваторы с локального компьютера.

Итак, допустим у нас есть незамысловатый скрипт следующего содержания:

<?php
include($_GET['file']);
?>

Теперь отредактируем метаданные картинки, которую мы впоследствии зальем в папку avators. Открываем изображение с помощью AcdSee, снова правим EXIF-информацию:

<?php system("dir"); die; ?>

AcdSee

В итоге, видим листинг файлов и папок, если на удаленной машине стоит Windows. Короче говоря, можно выполнять абсолютно любые команды, если, конечно, конфигурация PHP это позволяет. Я имею в виду, что должен быть отключен safe_mode и запреты на выполнение определенных команд, например, system(), passthru() и другие. Но если даже стоят и эти ограничения, то в любом случае злоумышленнику ничего не мешает открыть файл, в котором, например, хранятся настройки для подключения к БД или другие конфигурационные файлы.
Стоит отметить, что вставить PHP-код, при этом не нарушив целостность картинки, можно не только в JPG, но и в GIF-изображения благодаря уязвимости в функции getimagesize(). Дело в том, что эта функция воспринимает GIF-изображения даже со вставленным в нее PHP-кодом, так как для этой функции содержание картинки предполагает наличие любых символов. Например, если передать в getimagesize() файл с расширением .php, который представляет собой обычное GIF-изображение, но с дописанным PHP-кодом внутри, то данная функция не вызовет ошибки. Более того, если аплоад организован таким образом, что расширение файлов не меняется, то мы получим полноценный веб-шелл. Подробнее об этом можно почитать здесь.

Защита

Существует несколько способов защиты против различного рода кода, вставленного в изображения. Прежде всего необходимо парсить содержимое картинки и выявлять признаки, свойственные PHP/HTML/JS-коду. Это могут быть тэги, объявления переменных, вызов каких-либо часто используемых функций и др. Также можно попробовать изменить размер изображения или его формат, что приведет к ошибке, если в содержание внедрен код. Защититься от прямого просмотра можно путем использования специального скрипта, который будет извлекать картинки в BLOB или base64 из базы данных. Интересный вариант был предложен в одном из комментариев к статье, ссылку на которую я дал выше. Предлагается использовать скрипт, который будет накладывать рандомную XOR-маску на картинки, что также обезопасит от прямого выполнения, так как любой код, внедренный в изображение, станет невалидным. В БД в этом случае нужно хранить саму маску и путь до файла. Однако воспринимать всерьез этот метод все-таки не стоит, так как XOR обратимая операция, поэтому злоумышленник, узнав ключ, также сможет наложить XOR-маску, что сделает код выполнимым.

Также рекомендую почитать:


9 комментариев

  1. Kuzya, 17. мая 2008, 22:07

    Мля, круто =) Буду знать ещё больше =) Респект.

     
  2. c0nst, 18. мая 2008, 1:41

    Года 2 назад писал об уязвимости, в результате которой заливал шелл вместе с картинкой. Тогда еще мало что было написано по теме, приходилось разбираться самому)

     
  3. Prad, 19. января 2009, 15:41

    На мой взгляд очень познавательная статья, но старания будут напрасны, если с загружаемого изображения будет создан образ(например ImageCreateFromJpeg), а потом при помощи imagecopyresampled будет создано новое изображение и это новое изображение будет сохранено в качестве загруженого изображения, а загруженно — удалено.

     
  4. Аноним, 20. января 2009, 16:33

    ну работает

     
  5. kolpeex, 20. января 2009, 16:53

    Найти инклуд-баг в нынешнее время достаточно сложно.

     
  6. Raz0r, 21. января 2009, 0:39

    смотря где искать и как искать

     
  7. 1, 29. декабря 2009, 3:30

    > графических изображений
    Тавтология)

     
  8. Raz0r, 29. декабря 2009, 14:50

    сорри )

     
  9. Echo, 27. января 2010, 0:03

    Спасибо за инфу…. Раньше никогда не придавал особово значения загружаемым через Upload изображениям… Пользовался банальной проверкой разширения через PHP… Что касается инклюда, я никогда не использую переменные в качестве параметра функции…

     

Write a comment: