Пишу, по большей части, про историю, свою жизнь и немного про программирование.

Защита от внедрения PHP-кода в картинки (JPEG, GIF, PNG)

На «Хабре» всплыла тема атаки, старой как мир — заливаем на сайт картинку, у которой внутри (в поле комментариев) есть ПХП-код, потом всякими трюками этот код запускаем. Валидатор картинок на сайте такую картинку пропускает — это вполне валидная картинка.

Во всех форматах принятых в вебе, есть поле, позволяющее вставить такие данные. В JPEG есть специальные секции APPn и COM, в PNG — iTXt, tEXt и можно создавать произвольные секции, в GIF — блоки расширений, в SVG можно использовать обычный XML-комментарий.

В качестве абсолютного метода защиты на «Хабре» предлагается пропустить картинку через какую-либо графическую программу, чтобы убедиться, что все дополнительные данные исчезли. Мне кажется, плохой способ — медленный, а в случае JPEG это ещё и скажется на качестве.

Можно ещё попробовать вырезать все секции файла, куда можно запихнуть текстовую информацию, но это не спасёт от файлов, где ПХП вставлен прямо в графическую часть, так, чтобы детектор валидности картинки (в ПХП для этого обычно используют getimagesize) не спотыкался на файле.

Мне кажется, я придумал более удачный метод защиты.

В загруженный файл можно добавить первой секцией (сразу после заголовка) свой собственный кусок ПХП-кода с вызовом __halt_compiler эта специальная конструкция останавливает интерпретатор в этой точке и всё остальное содержимое файла дальше не интерпретируется:

# смотрим что внутри файла
bolk@Bolk ~ $ hexdump -Cn128 sample.jpg 
00000000  ff d8 ff e0 00 10 4a 46  49 46 00 01 01 00 00 01  |......JFIF......|
00000010  00 01 00 00 ff fe 00 1a  3c 3f 70 68 70 20 5f 5f  |........<?php __|
00000020  68 61 6c 74 5f 63 6f 6d  70 69 6c 65 72 28 29 3b  |halt_compiler();|
00000030  ff db 00 43 00 02 02 02  02 02 01 02 02 02 02 03  |...C............|
00000040  02 02 03 03 06 04 03 03  03 03 07 05 05 04 06 08  |................|
00000050  07 09 08 08 07 08 08 09  0a 0d 0b 09 0a 0c 0a 08  |................|
00000060  08 0b 0f 0b 0c 0d 0e 0e  0f 0e 09 0b 10 11 10 0e  |................|
00000070  11 0d 0e 0e 0e ff db 00  43 01 02 03 03 03 03 03  |........C.......|

# запускаем
bolk@Bolk ~ $ php sample.jpg
????JFIF??

Т. е. на экран выводится бинарный заголовок JPEG, первая секция, а потом интерпретатор дальше просто не идёт. Будет дальше ход хакера или нет, он не проинтерпретируется.

17 комментариев
Artjom Kurapov (kurapov.name) 2012

Остаётся открытым вопрос как этот самый код внедрить в нужное место, «после заголовка»

aktuba 2012

А не проще заливать картинки в папку, в которой запрещена обработка php?

Евгений Степанищев (bolknote.ru) 2012

Комментарий для kurapov.name:

Остаётся открытым вопрос как этот самый код внедрить в нужное место, «после заголовка»

Это же просто совсем. Код что ли написать? :)

Евгений Степанищев (bolknote.ru) 2012

Комментарий для aktuba:

А не проще заливать картинки в папку, в которой запрещена обработка php?

Есть масса уязвимостей при которых удаётся выполнить только локальный код. Что-то вроде:

$file = ’pages/’ . $_GET[’page’];
if (is_file($file)) include $file;

При этом мы можем залить на такой хостинг картинку в коде и подключить её через указание somepage.php?page=../../userimages/hack.jpg

Artjom Kurapov (kurapov.name) 2012

Комментарий для Евгения Степанищева:

Это же просто совсем. Код что ли написать? :)

Да, для меня это не тривиально.. Или это вне зависимости от формата можно где-то с десятого-двадцатого символа просто врезать произвольный текст?

Евгений Степанищев (bolknote.ru) 2012

Комментарий для kurapov.name:

Примерно такой алгоритм, ага.

ibnteo.klava.org/ 2012

Ну давайте теперь и в видео файлы вставлять PHP код, и в текстовые. Лучший метод защиты, это настроить сервер так, чтобы нельзя было запускать такой вредоносный код.

Евгений Степанищев (bolknote.ru) 2012

Комментарий для Евгения Степанищева:

Подскажете как настроить сервер таким образом? И обратите внимание на этот вот мой коментарий: http://bolknote.ru/all/3703#n35672

Василий Топоров 2012

Правильно ли я понимаю, что практически любой сайт, на котором можно заливать картинки, потенциально уязвим? Если мы просто используем стандартные функции php для работы с графикой и файлами).

Karsonito 2012

Комментарий для Василий Топоров:

Все зависит от реализации и настроек сервера.
Способов взломать много, нужно смотреть конкретный пример.

Евгений Степанищев (bolknote.ru) 2012

Комментарий для Василий Топоров:

Правильно ли я понимаю, что практически любой сайт, на котором можно заливать картинки, потенциально уязвим? Если мы просто используем стандартные функции php для работы с графикой и файлами).

Нет, конечно. Всё зависит от сочетания факторов. Например, см. мой комментарий выше: http://bolknote.ru/all/3703#n35672 Если есть возможность залить какие-то файлы и такой промах со стороны программиста — уязвимость есть. Или может быть некорректно настроен Апач (там некоторые настройки по-умолчанию могут дать уязвимость).

masterspammer (masterspammer.livejournal.com) 2012

Я правильно понял, что эта защита от двух разных но схожих дыр?

  1. запуск кода на выполнение вебсервером (если его настройки удаётся обмануть).
  1. включение кода картинки как модуля/библиотеки (если удалось залить «злой» код только в виде картинки).
Евгений Степанищев (bolknote.ru) 2012

Комментарий для masterspammer.livejournal.com:

Да, правильно.

НЕГЕНГ 2013

<html>

Евгений Степанищев (bolknote.ru) 2013

Комментарий для НЕГЕНГ:

Ещё один тупой.

Авакян Овсеп 2014

Спасибо автору за статью. Метод интересный ) Сам столкнулся с такой проблемой, но решить ее хочу на уровне веб сервера. Если с Apache все более-менее понятно (там можно использовать настройки .htaccess), то как быть с Nginx? Кто-нибудь писал конфигурацию для запрета выполнения кода из определенного каталога?

Евгений Степанищев (bolknote.ru) 2014

Комментарий для Авакян Овсеп:

Написать ему там пустой location.