Ваш сайт тоже позволяет заливать всё подряд?

Советы, готовые решения, заготовки - то что помогает при создании сайтов.
Ответить
Аватара пользователя
ukhov
Модератор
Модератор
Сообщения: 1343
Зарегистрирован: 04 янв 2011, 21:19

Ваш сайт тоже позволяет заливать всё подряд?

Сообщение ukhov »

Один французский «исследователь безопасности» этим летом опубликовал невиданно много найденных им уязвимостей типа arbitrary file upload в разных «написанных на коленке», но популярных CMS и плагинах к ним. Удивительно, как беспечны бывают создатели и администраторы небольших форумов, блогов и интернет-магазинчиков. Как правило, в каталоге, куда загружаются аватары, резюме, смайлики и прочие ресурсы, которые пользователь может загружать на сайт — разрешено выполнение кода PHP; а значит, загрузка PHP-скрипта под видом картинки позволит злоумышленнику выполнять на сервере произвольный код.

Выполнение кода с правами apache — это, конечно, не полный контроль над сервером, но не стоит недооценивать открывающиеся злоумышленнику возможности: он получает полный доступ ко всем скриптам и конфигурационным файлам сайта и через них — к используемым БД; он может рассылать от вашего имени спам, захостить у вас какой-нибудь незаконный контент, тем подставив вас под абузы; может, найдя параметры привязки к платёжной системе, отрефандить все заказы и оставить вас без дохода за весь последний месяц. Обидно, правда?

Как ему это удастся?

Вы не проверяете загружаемые файлы вообще?

Клинический случай: вы скопировали из мануала по PHP строчку

Код: Выделить всё

move_uploaded_file($_FILES["file"]["tmp_name"], "upload/" . $_FILES["file"]["name"]);
и так её и оставили в продакшн-коде.

Так я могу заливать вообще любые файлы, причём не только в каталог upload, а куда угодно — могу указать в качестве имени файла ../index.html и заменить вашу главную страницу своей. Обидно, правда?

Добавьте хотя бы вызов basename() для $_FILES["file"]["name"]. В последней версии PHP, судя по моим экспериментам, $_FILES["file"]["name"] и так возвращает только basename от переданного в HTTP-запросе значения filename; но осторожность тут лишней не будет.

Вы проверяете, является ли файл картинкой?

Перед тем, как сохранить загруженный файл в upload/, вы вызываете getimagesize(), чтоб убедиться, что загружена именно картинка. К превеликому удовольствию «исследователей безопасности», PHP позволяет вставлять выполнимый код в любое место любого файла, игнорируя всё, что не заключено в теги <? ?>. Я могу взять фотографию своего любимого котика, дописать в её конец что-нибудь навроде

Код: Выделить всё

<?php passthru($_GET['c']); ?>
и залить под именем pwn.php. Тогда getimagesize() подтвердит вам, что в файле JPEG-картинка, потому что анализирует только заголовки; и моя «фотография с припиской» пройдёт проверку.

Вы проверяете mime-type?

Почему нельзя доверять полю «mime», возвращаемому getimagesize(), понятно: оно берётся на основании заголовка файла. Тем более нельзя доверять $_FILES["file"]["type"] — ничто не мешает мне передать в HTTP-запросе «Content-Type: image/jpeg» перед PHP-скриптом. Это кажется банальным, но люди действительно на это полагаются. Вот я только что видел проверку

Код: Выделить всё

if(substr($_FILES["file"]["type"], 0, 6)=="image/") {/* сохранить файл */}
в одном самоуверенном проекте. Они, поди, считают изящным и хитроумным то, что смогли одной проверкой покрыть все возможные типы картинок! Но не стоит у них заимствовать этот «передовой опыт».

Вы проверяете расширение?

В другом самоуверенном проекте я только что видел проверку

Код: Выделить всё

if(substr($_FILES["file"]["name"], -3)=="jpg" || substr($_FILES["file"]["name"], -3)=="gif" || substr($_FILES["file"]["name"], -3)=="png") {/* сохранить файл */}
Особенность Apache — что когда он встречает файлы с незнакомыми расширениями, он эти расширения «откусывает» и ищет знакомые расширения перед ними. Поэтому если я залью файл pwn.php.omgif, то он пройдёт проверку, но Apache увидит в нём PHP-скрипт, потому что для расширения omgif не зарегистрирован ни mime-type, ни модуль-обработчик.

Вы проверяете «нехорошие» расширения?

В третьем самоуверенном проекте я видел проверку

Код: Выделить всё

if(strpos($_FILES["file"]["name"], ".php")===FALSE) {/* сохранить файл */}
— мол, если в имени файла хоть где-нибудь встретилось расширение .php, значит файл не годится. Но не надо забывать, что по умолчанию интерпретатор PHP вызывается ещё и для расширений .phtml и .php3, а некоторые хостеры включают его и для других расширений — порой даже для .html, .js, .jpg и так далее, чтобы вставлять в статические ресурсы какой-нибудь SEO-код, или отслеживать статистику хитов. (Можете сами проверить, сколько гугл находит вопросов «как мне сделать, чтоб выполнялся PHP-код в JPEG-файлах?») Кроме того, если злоумышленнику удастся загрузить свой .htaccess, то он сможет исполнять PHP-код в файлах с любыми расширениями — даже в самом этом файле .htaccess. В общем, будьте бдительны.

Вы проверяете расширение правильно?

Предположим, вы убедились, что имя файла заканчивается на .jpg (вместе с точкой!) Можно ли быть уверенным, что PHP-код в нём не будет выполняться? Учитывая предыдущий пункт — скорее всего можно, но гарантии нет. Может случиться, что злоумышленник (или криворукий админ) как-то повредил /etc/mime.types, так что расширение .jpg окажется незарегистрированным, и Apache станет анализировать расширение перед ним. Может случиться, что /etc/mime.types стал недоступен из-за chroot. Может случиться, что злоумышленник (или криворукий админ) забросил в каталог upload/ такой .htaccess, который позволяет выполнять PHP-код во всех файлах подряд.

Кроме того, до недавних версий PHP можно было загрузить файл с именем «pwn.php\0.jpg», который при сохранении на диск превращался бы в «pwn.php», потому что для системных вызовов строка с именем файла заканчивается на \0, а для функций PHP это обычный допустимый в строке символ. В таком случае проверка расширения тоже ничего не гарантировала бы.

И что же делать?

Исчерпывающий чеклист попытались составить на stackoverflow. Если коротко:
а) запретите явно выполнение PHP в каталоге, куда сохраняются пользовательские файлы;
б) переименовывайте пользовательские файлы в неподконтрольные пользователям имена;
в) если возможно, пересохраняйте картинки при помощи GD, чтобы удалить ненужные метаданные и непрошенные приписки в конце файла.

Источник: http://habrahabr.ru/post/148999/
Аватара пользователя
alexei
Разработчик
Разработчик
Сообщения: 836
Зарегистрирован: 21 янв 2010, 19:44

Re: Ваш сайт тоже позволяет заливать всё подряд?

Сообщение alexei »

Зачем статью копировать сюда? Почти все разработчики должны читать хабр.
Alazaur
Разработчик
Разработчик
Сообщения: 1001
Зарегистрирован: 16 окт 2011, 20:25

Re: Ваш сайт тоже позволяет заливать всё подряд?

Сообщение Alazaur »

Хотел бы я посмотреть что это за "самоуверенные проекты", складывается такое впечатление, что автор сам эти "проверки из самоуверенных проектов" придумал, во всяком случае переименовывают загружаемые файлы уж точно все, хотя бы для того чтобы имена файлов не совпадали, да и пересохраняют при помощи GD тоже наверно все, опять же даже не ради безопасности, а чтоб картинка соответствовала формату. Статья из пальца высосана ИМХО)
Ответить