Загрузка файлов на сервер
Что такое Upload files, или почему не работает
copy («c:\images\sample.jpg», «http://mysite.ru/uploads/sample.jpg «)
Что происходит, когда пользователь выбрал файл на своем диске, и нажал на кнопку «Send file»? Браузер отсылает файл на сервер, где php-интерпретатор помещает его в свою временную директорию, присваивая ему случайное имя и выполняет скрипт, указанный в поле action.
Как должен выглядеть upload.php?
Для работы с загруженными файлами лучше всего использовать встроенные функции is_uploaded_file() и move_uploaded_file(), которые проверяют, был ли загружен файл, и помещают его в указанную папку соответственно. Более детальную информацию Вы можете найти на страницах руководства. Не стоит изобретать велосипед и работать самому с временными файлами, копировать их, удалять. Это уже сделано до Вас и для Вас.
Настройка сервера
Я все сделал правильно, но у меня что-то не работает. Может, у меня неправильно сконфигурирован сервер?
Если Вы «все сделали правильно», но Ваш код неработает, или работает неправильно, не спешите отчаиваться. Возможно проблема не в Ваших руках, а в неверных настройках сервера. Вот список директив, которые имеют отношения к загрузке файлов:
Do not use Apache 2.0 and PHP in a production environment neither on Unix nor on Windows.
Небольшие пояснения, к этому рецепту: вышеописанная проблема, когда загруженные на сервер архивы не распаковываются и картинки не отображаются, может возникать из-за того, что используется веб-сервер Russian Apache. Директива CharsetDisable отключает модуль charset-processing module, т.е. никакой перекодировки при скачивании файлов, находящихся в данной папке, происходить не будет. Директива CharsetRecodeMultipartForms выключает перекодировку данных, переданных методом POST с заголовком Content-Type: multipart/form-data. Т.е. двоичные данные, переданные с такой настройкой, будут оставлены в первоначальном виде, а все остальное наполнение сайта будет перекодировано согласно текущим настройкам сервера.
Но при этом могут возникнуть осложнения: будьте готовы к тому, что в некоторых случаях текстовые части запросов вам придется перекодировать самостоятельно. Вот что по этому поводу говорится в документации:
Используйте директиву CharsetRecodeMultipartForms, которая появилась в PL23, но при этом вам все-равно придется перекодировать вручную текстовые части запросов. Для этого можно использовать Russian Apache API, доступное в других модулях или Russian Apache Perl API, доступное из mod_perl.
Один из примеров определения кодировки вы можете найти тут: http://tony2001.phpclub.net/detect_charset/detect.phps
Самая свежая документация по Russian Apache находится на его официальном сайте: http://apache.lexa.ru/.
Не забывайте, что после любой смены конфигурации, Вам необходимо перезапустить Ваш веб-сервер.
Дополнительные возможности
Загрузка нескольких файлов одновременно
Пример формы загрузки нескольких файлов:
И не забудьте увеличить post_max_size, если предполагается много файлов
Автоматическая загрузка файлов на сервер
Хранение файлов в базе данных mySQL
Помните, что скрипт отображающий ваш HTML никак не связан со скриптом, который должен выводить изображение. Это должны быть два различные приложения.
Хранение картинок в базе не является хорошем стилем. Гораздо удобней хранить в базе лишь пути к файлам изображений.
Получение свойств изображения.
Загрузка файлов, имеющих русско-язычное название
Отображения статуса загрузки (Progress bar)
Необходимо учитывать, что до полной загрузки файла, PHP не может оперировать ни размером файла, ни процентом его загрузки. Только когда файл уже находится на сервере PHP, то он получает возможность обращаться к информации. Если вам все-таки крайне необходимо реализовать такую возможность, воспользуйтесь Java-аплетом.
Права на файлы
Проблемы с правами на сервере (upload_tmp_dir)
В Unix-подобных операционных системах каждой папке, файлу, ссылке выставлены соответствие права доступа. Они могут выглядеть как rwx-rw-r- или же как число 754.
Доступность файла или каталога зависят от идентификатора пользователя и идентификатора группы, в которую он входит. Режим в целом описывается в терминах трех последовательностей, по три буквы в каждой:
r Право на чтение. (4)
w Право на запись. (2)
x Право на выполнение (поиск в каталоге). (1)
Пример реализации загрузки картинок на сервер.
Оригинал статьи находится на сайте PHP Club
FoggyK / Lesson_6PHP.md
Принципы загрузки фалов через форму
Функционал, отвечающий за отправку файлов на сервер, реализуется довольно просто. Как и в примерах из предыдущих уроков, за это отвечает специальное поле формы. Но ее настройка имеет некоторые особенности.
Если ваша форма содержит поля, отвечающие за загрузку файлов, то элементу
Использование поля загрузки файлов
При нажатии кнопки откроется проводник файловой системы. В нем можно перемещаться по директориям компьютера. Интерфейс интуитивно понятен любому пользователю. Все что нужно сделать — это найти нужный файл и нажать кнопку «Открыть». Отметим, что выбирать нужные документы и файлы может только сам пользователь. Явное указание атрибута value с именем или расположением какого-либо файла не приведет к успеху.
Чтобы выбранный файл был загружен при отправке формы, полю необходимо добавить атрибут name с уникальным значением.
Множественный выбор и блокировка поля
Принципы загрузки файлов
Загрузка файла на сервер может быть выполнена как с помощью веб-формы, расположенной на странице сайта, так и прямым программным запросом. Для PHP-интерпретатора способ передачи файла не имеет значения. Спецификация HTTP-протокола приводит эти операции к единообразному виду.
Перемещение загруженного файла
Как говорилось выше, загружаемые файлы размещаются во временной директории сервера и автоматически удаляются PHP-интерпретатором после выполнения текущего запроса. Их можно сохранить, переместив в другое место. Использовать стандартные функции copy() или rename() крайне нежелательно.
С помощью функции is_uploaded_file() вы можете проверить, является ли файл загруженным в текущем запросе. Она принимает всего один параметр — имя файла, а возвращает результат логического типа.
Важно
PHP позволяет изменять местоположение загруженных файлов с помощью обычных функций копирования или перемещения. Однако это довольно опасно. Существует ряд ухищрённых атак, основанных на таком недальновидном подходе.
Пример загрузки файла на сервер
Upload файлов, и все с этим связанное
Что такое Upload files, или почему не работает:
Даже если у Вас в распоряжении всего один компьютер, на котором совмещен и сервер и рабочая станция, не стоит забывать о том, что php использует технологию клиент/сервер. Файл, который мы хотим загрузить, как правило, находится на машине клиента, т.е. пользователя, обыкновенного посетителя сайта. Место назначения — сервер. Для того чтобы совершить процесс передачи файла, нам понадобиться следующая форма:
При этом в поле action должен быть указан URL Вашего php-скрипта, который в дальнейшем будет заниматься обработкой загружаемых файлов. Скрытое поле MAX_FILE_SIZE должно предшествовать полю выбора файла, и содержать максимально допустимый размер файла в байтах. Его назначение — проверка размера файла еще до момента отправки файла на сервер. Это должно избавить пользователя от длительной и безрезультатной загрузки файла на сервер и образования лишнего трафика, но не стоит особо полагаться на это ограничение, так как его легко обойти.
Что происходит, когда пользователь выбрал файл на своем диске, и нажал на кнопку «Send file»? Браузер отсылает файл на сервер, где php-интерпретатор помещает его в свою временную директорию, присваивая ему случайное имя и выполняет скрипт, указанный в поле action.
Как должен выглядеть upload.php?
Для работы с загруженными файлами лучше всего использовать встроенные функции is_uploaded_file и move_uploaded_file, которые проверяют, был ли загружен файл, и помещают его в указанную папку соответственно. Более детальную информацию Вы можете найти на страницах руководства. Не стоит изобретать велосипед и работать самому с временными файлами, копировать их, удалять. Это уже сделано до Вас и для Вас.
Настройка сервера
Я все сделал правильно, но у меня что-то не работает. Может, у меня неправильно сконфигурирован сервер?
Если Вы «все сделали правильно», но Ваш код неработоспособен, или работает неправильно, не спешите отчаиваться. Возможно проблема не в Ваших руках, а в неверных настройках сервера. Вот список директив, которые имеют отношения к загрузке файлов:
Небольшие пояснения, к этому рецепту: вышеописанная проблема, когда загруженные на сервер архивы не распаковываются и картинки не отображаются, может возникать из-за того, что используется веб-сервер Russian Apache. Директива CharsetDisable отключает модуль charset-processing module, т.е. никакой перекодировки при скачивании файлов, находящихся в данной папке, происходить не будет. Директива CharsetRecodeMultipartForms выключает перекодировку данных, переданных методом POST с заголовком Content-Type: multipart/form-data. Т.е. двоичные данные, переданные с такой настройкой, будут оставлены в первоначальном виде, а все остальное наполнение сайта будет перекодировано согласно текущим настройкам сервера.
Но при этом могут возникнуть осложнения: будьте готовы к тому, что в некоторых случаях текстовые части запросов вам придется перекодировать самостоятельно. Вот что по этому поводу говорится в документации:
Используйте директиву CharsetRecodeMultipartForms, которая появилась в PL23, но при этом вам все-равно придется перекодировать вручную текстовые части запросов. Для этого можно использовать Russian Apache API, доступное в других модулях или Russian Apache Perl API, доступное из mod_perl.
Один из примеров определения кодировки вы можете найти тут: http://tony2001.phpclub.net/detect_charset/detect.phps
Самая свежая документация по Russian Apache находится на его официальном сайте: http://apache.lexa.ru/.
Не забывайте, что после любой смены конфигурации, Вам необходимо перезапустить Ваш веб-сервер.
is_uploaded_file
(PHP 4 >= 4.0.3, PHP 5, PHP 7, PHP 8)
is_uploaded_file — Определяет, был ли файл загружен при помощи HTTP POST
Описание
Такие проверки особенно полезны, если существует вероятность того, что операции над файлом могут показать его содержимое пользователю или даже другим пользователям той же системы.
Список параметров
Имя проверяемого файла.
Возвращаемые значения
Возвращает true в случае успешного выполнения или false в случае возникновения ошибки.
Примеры
Пример #1 Пример использования функции is_uploaded_file()
Смотрите также
User Contributed Notes 14 notes
Note that calling this function before move_uploaded_file() is not necessary, as it does the exact same checks already. It provides no extra security. Only when you’re trying to use an uploaded file for something other than moving it to a new location.
To expand on what nicoSWD stated about this function.
In any case where the script is modified to unlink(), rename() or otherwise modify the file that IS NOT move_uploaded_file() will not have the upload checked.
Likewise, most file operations are cached in PHP, therefore there should be minimal performance hit running is_uploaded_file before move_uploaded_file, since it will usually used a cached result for the latter.
Here’s an example of a switch:
//include code to copy tmp file to final location here.
>else <
switch($HTTP_POST_FILES[‘userfile’][‘error’]) <
case 0: //no error; possible file attack!
echo «There was a problem with your upload.»;
break;
case 1: //uploaded file exceeds the upload_max_filesize directive in php.ini
echo «The file you are trying to upload is too big.»;
break;
case 2: //uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the html form
echo «The file you are trying to upload is too big.»;
break;
case 3: //uploaded file was only partially uploaded
echo «The file you are trying upload was only partially uploaded.»;
break;
case 4: //no file was uploaded
echo «You must select an image for upload.»;
break;
default: //a default error, just in case! 🙂
echo «There was a problem with your upload.»;
break;
>
//if file is not rejected by the filter, continue normally
if (is_uploaded_file($userfile)) <
Just looked at what I posted again and found several mistakes of the major and minor sort. That’s what I get for posting before I finish my coffee. This should work better (i.e. should work in the first place):
Here is my code for file handler, i hope it help to all:
?>
Next a part of code to use the class
Anyways, the problem was that PHP used %TEMP% to determine the destination for the uploaded file, and %TEMP% used the all-capitals version of the path. Changing it to use titlecase instead + restarting Apache fixed the problem.
The example brought out does not work as supposed to:
Regarding the comment of info at metaltoad dot net
@ 19-Feb-2003 04:03
The syntax should be (much shorter and neater):
Regarding topcat’s suggested change, I am split on doing that. I don’t like showing users errors that may give them more information than they should have (or show that I haven’t provided for that particular error). But I want to know when there are errors that fall to the default case so I can fix my code. What I will typically do is write them to the error log something like this modification to metaltoad’s post (takes into account the possibility of multi-line errors which error_log doesn’t handle well):
Руководство по Unrestricted File Upload
В этой статье говорится о том, как нарушения пользовательского ввода данных и неправильное управление сервером открывают лазейки для проникновения в систему хакеров. Они, таким образом, способны разместить вредоносный контент, начиная с Unrestricted File Upload и заканчивая выводом из строя веб-приложений.
Что такое Unrestricted File Upload?
«Загрузить» или «Перетащить файл для загрузки» — пользователь, возможно, видел эти две надписи, независимо от того, настраивает ли он свое фото в профиле или просто подает заявку на работу.
Разработчики скриптов File Upload HTML позволяют своим пользователям загружать файлы на веб-сервер с помощью этих кнопок. Однако подобная простота может быть не до конца надежной, если не будут проверены те файлы, которые загружаются.
Уязвимость загрузки файлов является одной из основных проблем веб-приложений. На многих веб-серверах эта проблема полностью исходит от цели, что позволяет злоумышленнику загрузить файл с вредоносными кодами в нем, который, таким образом, может быть запущен на сервере.
Влияние Unrestricted File Upload
Последствия, которые несет в себе данная уязвимость загрузки файлов, различаются для каждого отдельного веб-приложения, поскольку они зависят от того, как загруженный файл обрабатывается приложением и где он хранится.
Таким образом, «дыра в защите» может привести к следующему:
Тем не менее, эта уязвимость была зарегистрирована с оценкой CVSS “7,6” и высокой степенью опасности:
Итак, теперь читатель знает о концепции загрузки файлов и о том, почему это происходит, и даже о тех последствиях, с которыми может столкнуться разработчик, если проверки не будут реализованы должным образом. Таким образом, стоит попробовать копнуть поглубже и узнать, как использовать эту проблему загрузки файлов всеми возможными способами.
Для этого раздела было разработано базовое веб-приложение с некоторыми PHP-скриптами, которое является уязвимым.
Базовая загрузка файлов
Бывают случаи, когда разработчики не знают о последствиях уязвимости загрузки файлов, и поэтому они с легкостью пишут базовые PHP-скрипты для выполнения своих задач. Но эта снисходительность открывает врата для крупных атак и потерь данных.
Необходимо проверить скрипт, который принимает загруженные файлы из основной HTML-формы загрузки файлов на веб-странице.
Из приведенного выше фрагмента кода пользователь может понять, что разработчик не реализовал никаких условий проверки ввода, то есть сервер не будет смотреть на расширение файла, тип контента или какие–либо конкретные аргументы и просто принимает все, что загружается.
Настала пора использовать это вышеописанное веб-приложение, создав PHP-бэкдор, применяя лучший msfvenom one-liner в качестве:
Пользователю нужно скопировать и вставить выделенный код в свой текстовый редактор и сохранить его с расширением PHP. В данном случае пользователь сохранил это как “ Reverse.php” на рабочем столе.
Теперь, вернувшись в приложение, он нажмет на тег Browse и выберет Reverse.php с рабочего стола.
Итак, пора нажать кнопку загрузки, которая и загрузит этот файл на веб-сервер.
На приведенном выше изображении пользователь может увидеть, что его файл был успешно загружен. Таким образом, он сможет проверить то же самое, щелкнув по тексту “here”.
Но стоит подождать, прежде чем нажать на этот текст. Следует загрузить фреймворк Metasploit и запустить мульти-обработчик с помощью:
Теперь, когда пользователь нажмет здесь на текст, будет получен сеанс meterpreter. Человек захватил сервер жертвы.
Ограничение по типу контента
До сих пор пользователь был сосредоточен только на том, что разработчик не проверяет файлы и что уязвимым является именно веб-приложение. Но что, если проверки реализуются, являются ли они базовыми или основными – неважно, приложение все равно будет страдать от уязвимости загрузки файлов?
Пора ответить и на этот вопрос.
Человек, возвращаясь в свое уязвимое веб-приложение, попробует загрузить файл Reverse.php вновь.
Ой!! На этот раз пользователь столкнулся с предупреждением, что принимаются только файлы формата “PNG”.
Но почему это произошло? Стоит сделать один шаг назад и загрузить Reverse.php снова, на этот раз включив burpsuite и захватив текущий HTTP-запрос.
На приведенном ниже изображении в мониторе burpsuite пользователь может увидеть, что тип контента здесь выглядит как «application/x-php».
Так что же это за тип контента? Сущность «Content-Type» в заголовке указывает внутренний тип носителя содержимого сообщения.
Иногда веб-приложения используют этот параметр для того, чтобы распознать файл как допустимый. Например, они принимают только файлы с «Content-Type» типа «text/plain». Так что вполне возможно, что разработчик использует эту штуку для проверки своего приложения.
Следует попробовать обойти эту защиту, изменив данный параметр content-type на «image / png» в заголовке запроса.
Пользователь нажмет кнопку Вперед и проверит реакцию приложения.
На приведенном выше изображении можно увидеть, что пользователь успешно обошел эту меру безопасности. Снова повторив тот же процесс, он запустит мульти-обработчик в фоновом режиме, прежде чем нажмет на текст “here”.
Отлично! Сервер жертвы вновь в руках пользователя.
Настала пора проверить его бэкенд-код, чтобы точнее понимать, почему все это произошло.
Double Extension File Upload
Переходя в следующий раздел, при повторной попытке манипулировать типом содержимого в заголовке запроса, как в случае с “image/png”, пользователь на этот раз потерпел неудачу.
На приведенном ниже изображении можно увидеть, что приложение вернуло пользователя обратно на экран с ошибкой загрузки файла формата “PNG”.
Таким образом, все это может произойти только из-за того, что приложение проверяет расширение файла или допускает только файлы с форматом “.png «, которые будут загружены на веб-сервер. Это ограничивает загрузку других файлов.
Стоит проверить код разработчика:
Здесь он устанавливает три новые переменные:
Многие способы могут помочь пользователям обойти это ограничение, но наиболее распространенным и предпочтительным методом является реализация “двойного расширения”, которое таким образом скрывает реальную природу файла, вставляя несколько расширений с его именем, что создает путаницу для параметров безопасности.
Например, Reverse.php.png выглядит как изображение png, которое является данными, а не приложением, но когда файл загружается с двойным расширением, он будет выполняться как php-файл, что и является приложением.
Здесь был переименован предыдущий файл, то есть Reverse.php в Reverse.php.png.
На приведенном ниже изображении можно увидеть, что, когда пользователь нажал на кнопку «Загрузить», его загрузка была выполнена успешно.
Отлично! Пользователь снова обошел эту меру безопасности. Следует включить фреймворк Metasploit обратно, как это делалось ранее, а затем нажать на текст «here», чтобы получить сеанс meterpreter.
Интересно, почему все это произошло?
Это происходит из-за одной из основных причин: неправильной настройки сервера. Веб-сервер может быть неправильно сконфигурирован со следующей небезопасной настройкой, которая, в свою очередь, включает двойное расширение и делает веб-приложение уязвимым для подобного типа атак.
Примечание:
Чтобы сделать возможной атаку двойного расширения,“$ » следует удалить из конца строк защищенной конфигурации с помощью:
Обход проверки размера изображения
Возможно, пользователь уже видел приложения, которые ограничивают размер файла, то есть они не позволяют загружать файл больше определенного размера. Эту проверку можно обойти легко, загрузив полезную нагрузку наименьшего размера.
Так что в данном случае человек не смог загрузить Reverse.php, так как он был размером более 3 КБ, что, таким образом, не удовлетворяло условий разработчика. Стоит проверить бэкенд-код:
Так что настала пора попробовать вызвать одну из самых маленьких полезных нагрузок, simple-backdoor.php из каталога webshells, и перенести ее на рабочий стол.
Теперь пришло время установить на ней двойное расширение, на этот раз пользователь сделает из файла gif.
Стоит подождать, ведь перед загрузкой этого файла нужно установить еще одну вещь, то есть добавить магическое число для GIF-изображений, чтобы, если сервер не проверит расширение, а вместо этого проверит заголовок файла, пользователя не поймали. Таким образом, в случае “gif” магическое число будет равно “GIF89” или “GIF89a”, в принципе, можно использовать любой из двух предложенных вариантов.
На приведенном ниже изображении можно увидеть, что пользователь успешно загрузил файл на веб-сервер.
Он нажмет на текст «here» и проверит, что все прошло успешно.
Отлично!! Пользователь успешно обошел и эту меру безопасности. Теперь следует попробовать захватить кое-какие конфиденциальные данные.
Blacklisted Extension File Upload
Итак, до сих пор пользователя ждал успех только потому, что разработчик проверял все, кроме php-файла, скажем, с помощью недопустимого условия или с помощью какого-либо конкретного аргумента.
Но вот, на этот раз человек столкнулся с тем, что разработчик внес в черный список, «php» или «PHP extensions».
Аналогично, когда пользователь пытался обойти раздел загрузки файла всеми возможными способами, будь то его тип контента или двойное расширение, он каждый раз терпел неудачу и получал следующий ответ:
Далее он попытался сделать то же самое, переименовав файл из “ Reverse.php” в “ Reverse.РНР”.
И как только он нажал на кнопку загрузки, она была выполнена.
Теперь стоит проверить, работает ли файл или нет. Когда пользователь нажал на текст “here”, его перенаправили на новую страницу, но файл не был выполнен.
Так почему же все это произошло? Пользователь обошел «охрану», это должно было сработать.
Это произошло, потому что веб-сервер цели не был настроен для выполнения файлов расширения PHP, т.е. пользователь обошел защиту веб-приложений, но сервер не смог запустить данный файл.
Итак, чтобы открыть файлы с желаемым расширением, нужно загрузить «htaccess»:
Настала пора сделать это:
Пользователь изменит его на all в каталоге /var / www/.
Теперь перезапустит сервер apache с помощью:
Отлично!! После успешной загрузки стоит попробовать снова отправить туда файл полезной нагрузки.
Пользователь нажмет на кнопку загрузки, но на этот раз, прежде чем кликнуть на текст “here”, следует снова настроить фреймворк Metasploit, как это делалось ранее.
Круто!! На приведенном ниже изображении можно увидеть, что пользователь также успешно обошел эту проверку черным списком, и новый сеанс meterpreter был установлен.
Митигирование
Важно! Информация исключительно в учебных целях. Пожалуйста, соблюдайте законодательство и не применяйте данную информацию в незаконных целях.











































