У меня есть сайт PHP, где люди могут заполнять справочные билеты. Это позволяет им загружать скриншоты для своего билета. Я разрешаю загружать gif, psd, bmp, jpg, png, tif. После получения загрузки скрипт PHP игнорирует расширение файла. Он идентифицирует тип файла, используя только информацию MIME, которая для этих типов файлов всегда хранится в первых 12 байтах файла.
Кто-то загрузил несколько GIF-файлов, которые при просмотре в браузере в браузере сказали, что это неверно, и мой антивирусный сканер предупредил меня, что это была инъекция (или что-то в этом роде). См. Ниже для zip-файла, содержащего эти GIF-файлы.
Я не думаю, что проверка информации заголовка достаточно. Я слышал, что изображение может быть полностью допустимым, но также содержать код эксплойта.
Поэтому у меня есть два основных вопроса:
Обновление: все, спасибо за ответ. Я пытаюсь посмотреть на сервере для загруженных GIF-файлов. Я буду обновлять этот пост, если найду их.
Обновление 2: Я нашел GIF для всех, кого это интересует. Я поместил их в zip-файл, зашифрованный паролем «123». Он расположен здесь (будьте осторожны, есть несколько кнопок «Загрузить» на этом хостинговом сайте – некоторые из них предназначены для рекламы) http://www.filedropper.com/badgifs . Мой защищенный вирус 5060.gif отмечен как троянец (TR / Graftor.Q.2). Я должен отметить, что эти файлы были загружены до того, как я осуществил проверку MIME первых 12 байтов. Итак, теперь я в безопасности для этих конкретных. Но я все равно хотел бы знать, как обнаружить эксплойт, скрывающийся за правильным типом MIME.
Важное пояснение: меня беспокоит только риск для ПК, который загружает эти файлы, чтобы посмотреть на них. Файлы не являются риском для моего сервера. Они не будут выполнены. Они сохраняются с использованием чистого имени (шестнадцатеричный хэш-вывод) с расширением «.enc», и я сохраняю их на диск в зашифрованном состоянии с помощью фильтра fwrite:
// Generate random key to encrypt this file. $AsciiKey = ''; for($i = 0; $i < 20; $i++) $AsciiKey .= chr(mt_rand(1, 255)); // The proper key size for the encryption mode we're using is 256-bits (32-bytes). // That's what "mcrypt_get_key_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC)" says. // So we'll hash our key using SHA-256 and pass TRUE to the 2nd parameter, so we // get raw binary output. That will be the perfect length for the key. $BinKey = hash('SHA256', '~~'.TIME_NOW.'~~'.$AsciiKey.'~~', true); // Create Initialization Vector with block size of 128 bits (AES compliant) and CBC mode $InitVec = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), MCRYPT_RAND); $Args = array('iv' => $InitVec, 'key' => $BinKey, 'mode' => 'cbc'); // Save encoded file in uploads_tmp directory. $hDest = fopen(UPLOADS_DIR_TMP.'/'.$Hash.'.enc', 'w'); stream_filter_append($hDest, 'mcrypt.rijndael-128', STREAM_FILTER_WRITE, $Args); fwrite($hDest, $Data); fclose($hDest);
Что касается первого вопроса , вы никогда не узнаете, не можете ли вы получить какие-либо журналы или изображения, о которых идет речь, потому что есть много вещей, которые эти эксплойты могут иметь целевые и в зависимости от того, какой целью является способ использования эксплойта в файл может быть совершенно другим.
Изменить: W32 / Graftor – это общее имя для программ, которые, как представляется, имеют трояноподобные характеристики.
5060.gif
файл 5060.gif
в шестнадцатеричном редакторе, я заметил, что программа на самом деле является переименованной программой Windows . Хотя это не эксплойт браузера и, таким образом, безвреден, если он фактически не открыт и не выполнен, вам нужно убедиться, что он не будет использоваться с типом MIME, определенным загрузчиком, потому что пользователь может все же быть обманут в открытии программы; см. ответ на второй вопрос.
Что касается второго вопроса : чтобы предотвратить запуск какого-либо кода эксплойта или пользователя, вам нужно убедиться, что все файлы хранятся с безопасным расширением в имени файла, поэтому они обслуживаются с правильным типом MIME. Например, вы можете использовать это регулярное выражение для проверки имени файла:
if(!preg_match ( '/\\.(gif|p(sd|ng)|tiff?|jpg)$/' , $fileName)){ header("415 Unsupported Media Type"); die("File type not allowed."); }
Также убедитесь, что вы обслуживаете файлы с правильным типом содержимого; убедитесь, что вы не используете тип содержимого, указанный с загруженным файлом, при обслуживании файла для пользователя. Если вы полагаетесь на Content-Type, заданный загрузчиком, файл может быть использован как text/html
или что-либо подобное, и он будет анализироваться браузером пользователей как таковой.
Обратите внимание, что это защищает только от вредоносных файлов, использующих уязвимости в браузере пользователей, исключая анализатор изображений.
Если вы пытаетесь предотвратить использование эксплойтов против сервера, вам нужно убедиться, что вы не позволяете парсеру PHP выполнять содержимое изображения и что библиотека изображений, которую вы используете для обработки изображения, не имеет каких-либо известных уязвимости.
Также обратите внимание, что этот код не защищает вас от изображений, содержащих эксплойт для парсера изображений, используемых браузером пользователей; для защиты от этого, вы можете проверить, соответствует ли getimagesize()
true, предложенный Jeroen.
Обратите внимание, что использование getimagesize()
метода getimagesize()
недостаточно, если вы не проверяете имена файлов и убедитесь, что файлы обслуживаются с правильным заголовком Content-Type
, потому что полностью допустимые изображения могут содержать HTML / PHP-код внутри комментариев.
Для этого вы можете использовать функцию getimagesize () . Если изображение недействительно, оно просто вернет false
.
if (getimagesize($filename)) { // valid image } else { // not a valid image }
Стоит отметить, что это тоже не на 100% безопасно, но это лучшее, что вы можете сделать, насколько я знаю.
Подробнее об этом читайте здесь .
Вы можете попробовать phpMussel на любом скрипте php, который принимает закачки. Файл будет сканироваться с использованием подписей ClamAV, а также некоторые внутренние эвристические подписи, которые специально предназначены для такого типа вторжений.
Я не знаю много о форматах изображений, но воссоздавая изображения, а затем сохраняя результат, я чувствую, что у меня есть хороший шанс устранить ненужные хитроумные вещи. Особенно, если вы разделите все метаданные, такие как комментарии и все другие типы дополнительных встроенных полей, которые поддерживают некоторые форматы изображений.
1) Вы никогда не узнаете, в чем проблема, если вы удалили .gif, и ваш A / V не записывал журнал.
Вопрос. До сих пор ли проблема .gif на сервере?
Вопрос: Вы проверили свои журналы A / V?
2) Существует множество различных возможных эксплойтов, которые могут иметь или не иметь ничего общего с форматом файла .gif. Вот один пример:
3) Чтобы уменьшить риск в этом примере, вам необходимо:
a) Загрузка файлов ( любых файлов) в безопасный каталог на сервере
б) Использовать только файлы с определенными суффиксами (.gif, .png и т. д.).
c) Будьте предельно параноидальными в отношении всего, что загружено на ваш сайт (особенно если вы разрешите другим пользователям загружать его с вашего сайта!)
На очень полезном совете, чтобы предотвратить проблемы с внедренным PHP, пришел из системного администратора моего хоста: у меня есть сайт, на котором люди могут загружать свой собственный контент. Я хотел убедиться, что каталог, в котором загружены загруженные изображения, не запускает никакого PHP. Таким образом, кто-то может даже опубликовать изображение под названием «test.php», и он все равно НИКОГДА не будет разбираться с PHP, если он был в каталоге загрузки. Решение было прост: в папке загруженный контент подан из следующего .htacess:
RewriteEngine On RewriteRule \.$ - [NC] php_flag engine off
Это отключит механизм PHP для этой папки, тем самым прекратив любую попытку запуска любого PHP для использования уязвимостей на стороне сервера.
Поздний ответ, но может быть полезен для кого-то. Вы можете попробовать такой подход:
//saves filtered $image to specified $path function save($image,$path,$mime) { switch($mime) { case "image/jpeg" : return imagejpeg(imagecreatefromjpeg($image),$path); case "image/gif" : return imagegif(imagecreatefromgif($image),$path); case "image/png" : return imagepng(imagecreatefrompng($image),$path); } return false; };