Уязвимости загрузки файлов

Уязвимости загрузки файлов

by moiseevrus

Contents

Что такое уязвимости загрузки файлов?

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

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

Каково влияние уязвимостей загрузки файлов?

Влияние уязвимостей загрузки файлов обычно зависит от двух ключевых факторов:

  • Какой аспект файла веб-сайт не может правильно проверить, будь то его размер, тип, содержимое и т. д.
  • Какие ограничения накладываются на файл после его успешной загрузки.

В худшем случае тип файла не проверяется должным образом, а конфигурация сервера позволяет выполнять определенные типы файлов (такие как .phpи .jsp) как код. В этом случае злоумышленник потенциально может загрузить файл кода на стороне сервера, который работает как веб-оболочка, фактически предоставляя ему полный контроль над сервером.

Если имя файла не проверено должным образом, это может позволить злоумышленнику перезаписать важные файлы, просто загрузив файл с таким же именем. Если сервер также уязвим для обхода каталогов , это может означать, что злоумышленники могут даже загружать файлы в непредвиденные места.

Неспособность убедиться, что размер файла находится в пределах ожидаемых пороговых значений, также может привести к атаке типа «отказ в обслуживании» (DoS), когда злоумышленник заполняет доступное дисковое пространство.

Как возникают уязвимости загрузки файлов?

Учитывая довольно очевидные опасности, веб-сайты в дикой природе редко имеют какие-либо ограничения на то, какие файлы пользователям разрешено загружать. Чаще всего разработчики реализуют то, что они считают надежной проверкой, которая либо изначально ошибочна, либо ее можно легко обойти.

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

В других случаях веб-сайт может попытаться проверить тип файла, проверив свойства, которыми злоумышленник может легко манипулировать с помощью таких инструментов, как Burp Proxy или Repeater.

В конечном счете, даже надежные меры проверки могут применяться непоследовательно в сети узлов и каталогов, образующих веб-сайт, что приводит к несоответствиям, которые можно использовать.

Далее в этом разделе мы научим вас использовать ряд этих недостатков для загрузки веб-шелла для удаленного выполнения кода. Мы даже создали несколько интерактивных, намеренно уязвимых лабораторий, чтобы вы могли попрактиковаться в том, чему научились, на реальных целях.

Как веб-серверы обрабатывают запросы на статические файлы?

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

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

Процесс обработки этих статических файлов практически не изменился. В какой-то момент сервер анализирует путь в запросе, чтобы определить расширение файла. Затем он использует это для определения типа запрашиваемого файла, обычно сравнивая его со списком предварительно настроенных сопоставлений между расширениями и типами MIME. Дальнейшие действия зависят от типа файла и конфигурации сервера.

  • Если этот тип файла не является исполняемым, например изображение или статическая HTML-страница, сервер может просто отправить содержимое файла клиенту в ответе HTTP.
  • Если тип файла является исполняемым, например файл PHP, и сервер настроен на выполнение файлов этого типа, он будет назначать переменные на основе заголовков и параметров в HTTP-запросе перед запуском сценария. Полученный результат затем может быть отправлен клиенту в ответе HTTP.
  • Если тип файла является исполняемым, но сервер не настроен на выполнение файлов этого типа, он обычно отвечает ошибкой. Однако в некоторых случаях содержимое файла все же может быть передано клиенту в виде обычного текста. Такие неправильные конфигурации иногда могут использоваться для утечки исходного кода и другой конфиденциальной информации. Вы можете увидеть пример этого в наших учебных материалах по раскрытию информации .

Кончик

Заголовок Content-Typeответа может дать ключ к пониманию того, какой файл, по мнению сервера, он обслужил. Если этот заголовок не был явно задан кодом приложения, он обычно содержит результат сопоставления расширения файла и типа MIME.

Теперь, когда вы знакомы с ключевыми понятиями, давайте посмотрим, как вы можете потенциально использовать такие уязвимости.

Использование неограниченной загрузки файлов для развертывания веб-шелла

С точки зрения безопасности наихудший возможный сценарий — это когда веб-сайт позволяет загружать скрипты на стороне сервера, такие как файлы PHP, Java или Python, а также настроен на их выполнение в виде кода. Это упрощает создание собственной веб-оболочки на сервере.

Веб-оболочка

Веб-оболочка — это вредоносный сценарий, который позволяет злоумышленнику выполнять произвольные команды на удаленном веб-сервере, просто отправляя HTTP-запросы на нужную конечную точку.

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

<?php echo file_get_contents('/path/to/target/file'); ?>

После загрузки отправка запроса на этот вредоносный файл вернет содержимое целевого файла в ответ.

Более универсальная веб-оболочка может выглядеть примерно так:

<?php echo system($_GET['command']); ?>

Этот сценарий позволяет вам передать произвольную системную команду через параметр запроса следующим образом:

GET /example/exploit.php?command=id HTTP/1.1

Использование ошибочной проверки загрузки файлов

В дикой природе маловероятно, что вы найдете веб-сайт, который не имеет никакой защиты от атак с загрузкой файлов, как мы видели в предыдущем лабораторном исследовании. Но то, что защита есть, не означает, что она надежна.

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

Неверная проверка типа файла

При отправке HTML-форм браузер обычно отправляет предоставленные данные в POSTзапросе с типом контента application/x-www-form-url-encoded. Это подходит для отправки простого текста, такого как ваше имя, адрес и т. д., но не подходит для отправки больших объемов двоичных данных, таких как весь файл изображения или документ PDF. В этом случае тип содержимого multipart/form-dataявляется предпочтительным подходом.

Рассмотрим форму, содержащую поля для загрузки изображения, предоставления его описания и ввода вашего имени пользователя. Отправка такой формы может привести к запросу, который выглядит примерно так:

POST /images HTTP/1.1
Host: normal-website.com
Content-Length: 12345
Content-Type: multipart/form-data; boundary=---------------------------012345678901234567890123456

—————————012345678901234567890123456
Content-Disposition: form-data; name=”image”; filename=”example.jpg”
Content-Type: image/jpeg

[…binary content of example.jpg…]

—————————012345678901234567890123456
Content-Disposition: form-data; name=”description”

This is an interesting description of my image.

—————————012345678901234567890123456
Content-Disposition: form-data; name=”username”

wiener
—————————012345678901234567890123456–

Как видите, тело сообщения разбито на отдельные части для каждого из входных данных формы. Каждая часть содержит Content-Dispositionзаголовок, который предоставляет некоторую основную информацию о поле ввода, к которому он относится. Эти отдельные части также могут содержать собственный Content-Typeзаголовок, сообщающий серверу MIME-тип данных, отправленных с использованием этого ввода.

Один из способов, которым веб-сайты могут попытаться проверить загрузку файлов, — это проверить, соответствует ли этот Content-Typeзаголовок, относящийся к вводу, ожидаемому типу MIME. Например, если сервер ожидает только файлы изображений, он может разрешить только такие типы, как image/jpegи image/png. Проблемы могут возникнуть, когда сервер неявно доверяет значению этого заголовка. Если дальнейшая проверка не выполняется, чтобы проверить, действительно ли содержимое файла соответствует предполагаемому типу MIME, эту защиту можно легко обойти с помощью таких инструментов, как Burp Repeater.

Предотвращение выполнения файлов в доступных пользователю каталогах

Хотя в первую очередь лучше предотвратить загрузку опасных типов файлов, второй линией защиты является предотвращение выполнения сервером любых сценариев, которые действительно проскальзывают через сеть.

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

GET /static/exploit.php?command=id HTTP/1.1
Host: normal-website.com

HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 39

<?php echo system($_GET[‘command’]); ?>

Такое поведение потенциально интересно само по себе, так как может привести к утечке исходного кода, но сводит на нет любую попытку создать веб-оболочку.

Такая конфигурация часто отличается в разных каталогах. Каталог, в который загружаются пользовательские файлы, вероятно, будет иметь гораздо более строгий контроль, чем другие места в файловой системе, которые считаются недоступными для конечных пользователей. Если вы сможете найти способ загрузить сценарий в другой каталог, который не должен содержать файлов, предоставленных пользователем, сервер все же может выполнить ваш сценарий.

Кончик

Веб-серверы часто используют это filenameполе в multipart/form-dataзапросах, чтобы определить имя и место, где должен быть сохранен файл.

Вы также должны отметить, что даже если вы можете отправлять все свои запросы на одно и то же доменное имя, это часто указывает на какой-либо обратный прокси-сервер, например, на балансировщик нагрузки. Ваши запросы часто будут обрабатываться дополнительными серверами за кулисами, которые также могут быть настроены по-другому.

Недостаточный черный список опасных типов файлов

Один из наиболее очевидных способов предотвратить загрузку пользователями вредоносных скриптов — занесение в черный список потенциально опасных расширений файлов, таких как .php. Практика занесения в черный список изначально ошибочна, поскольку трудно явно заблокировать все возможные расширения файлов, которые могут использоваться для выполнения кода. Такие черные списки иногда можно обойти, используя менее известные альтернативные расширения файлов, которые все еще могут быть исполняемыми, такие как .php5.shtml, и так далее.

Переопределение конфигурации сервера

Как мы обсуждали в предыдущем разделе, серверы обычно не будут выполнять файлы, если они не были настроены для этого. Например, прежде чем сервер Apache выполнит файлы PHP, запрошенные клиентом, разработчикам может потребоваться добавить в свой /etc/apache2/apache2.confфайл следующие директивы:

LoadModule php_module /usr/lib/apache2/modules/libphp.so
AddType application/x-httpd-php .php

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

Точно так же разработчики могут настраивать каталоги на серверах IIS с помощью web.configфайла. Сюда могут входить такие директивы, как следующие, которые в данном случае позволяют предоставлять пользователям файлы JSON:

<staticContent>
<mimeMap fileExtension=".json" mimeType="application/json" />
</staticContent>

Веб-серверы используют файлы конфигурации такого типа, если они есть, но обычно вам не разрешен доступ к ним с помощью HTTP-запросов. Однако иногда вы можете обнаружить серверы, которые не могут помешать вам загрузить собственный вредоносный файл конфигурации. В этом случае, даже если нужное вам расширение файла занесено в черный список, вы можете обманным путем заставить сервер сопоставить произвольное пользовательское расширение файла с исполняемым типом MIME.

Скрытие расширений файлов

Даже самые исчерпывающие черные списки потенциально можно обойти с помощью классических методов запутывания. Допустим, код проверки чувствителен к регистру и не может распознать, что exploit.pHpна самом деле это .phpфайл. Если код, который впоследствии сопоставляет расширение файла с типом MIME, не чувствителен к регистру, это несоответствие позволяет вам скрыть вредоносные файлы PHP после проверки, которые в конечном итоге могут быть выполнены сервером.

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

  • Предоставьте несколько расширений. В зависимости от алгоритма, используемого для разбора имени файла, следующий файл может интерпретироваться либо как файл PHP, либо как изображение JPG:exploit.php.jpg
  • Добавьте конечные символы. Некоторые компоненты удаляют или игнорируют конечные пробелы, точки и тому подобное:exploit.php.
  • Попробуйте использовать кодировку URL (или двойную кодировку URL) для точек, косой черты и обратной косой черты. Если значение не декодируется при проверке расширения файла, но позже декодируется на стороне сервера, это также может позволить вам загружать вредоносные файлы, которые в противном случае были бы заблокированы:exploit%2Ephp
  • Добавьте точку с запятой или символы нулевого байта в URL-кодировке перед расширением файла. Если проверка написана на языке высокого уровня, таком как PHP или Java, но сервер обрабатывает файл, используя низкоуровневые функции, например, на C/C++, это может привести к расхождениям в том, что считается концом имени файла: exploit.asp;.jpgилиexploit.asp%00.jpg
  • Попробуйте использовать многобайтовые символы Юникода, которые могут быть преобразованы в нулевые байты и точки после преобразования или нормализации Юникода. Такие последовательности, как xC0 x2ExC4 xAEили xC0 xAEмогут быть переведены, x2Eесли имя файла проанализировано как строка UTF-8, но затем преобразовано в символы ASCII перед использованием в пути.

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

exploit.p.phphp

Это всего лишь небольшая часть из множества способов, которыми можно запутать расширения файлов.

Неправильная проверка содержимого файла

Вместо того, чтобы неявно доверять Content-Typeуказанному в запросе, более безопасные серверы пытаются проверить, действительно ли содержимое файла соответствует ожидаемому.

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

Точно так же некоторые типы файлов могут всегда содержать определенную последовательность байтов в своем заголовке или нижнем колонтитуле. Их можно использовать как отпечаток пальца или подпись, чтобы определить, соответствует ли содержимое ожидаемому типу. Например, файлы JPEG всегда начинаются с байтов FF D8 FF.

Это гораздо более надежный способ проверки типа файла, но даже он не является надежным. Используя специальные инструменты, такие как ExifTool, можно легко создать многоязычный файл JPEG, содержащий вредоносный код в своих метаданных.

Использование условий гонки при загрузке файлов

Современные фреймворки более защищены от подобных атак. Как правило, они не загружают файлы напрямую в предполагаемое место назначения в файловой системе. Вместо этого они принимают меры предосторожности, такие как загрузка во временный изолированный каталог и случайное имя, чтобы избежать перезаписи существующих файлов. Затем они выполняют проверку этого временного файла и передают его в место назначения только после того, как это будет сочтено безопасным.

Тем не менее, разработчики иногда реализуют собственную обработку загрузки файлов независимо от какой-либо платформы. Мало того, что это довольно сложно сделать хорошо, это также может привести к опасным условиям гонки, которые позволяют злоумышленнику полностью обойти даже самую надежную проверку.

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

Эти уязвимости часто очень незаметны, что затрудняет их обнаружение во время тестирования черного ящика, если вы не можете найти способ утечки соответствующего исходного кода.

Условия гонки при загрузке файлов на основе URL

Подобные условия гонки могут возникать в функциях, которые позволяют загружать файл, указав URL-адрес. В этом случае сервер должен получить файл через Интернет и создать локальную копию, прежде чем он сможет выполнить какую-либо проверку.

Поскольку файл загружается с использованием HTTP, разработчики не могут использовать встроенные механизмы своей платформы для безопасной проверки файлов. Вместо этого они могут вручную создавать свои собственные процессы для временного хранения и проверки файла, которые могут быть не такими безопасными.

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

Чтобы упростить подобные атаки, вы можете попробовать увеличить время, затрачиваемое на обработку файла, тем самым удлинив окно для перебора имени каталога. Один из способов сделать это — загрузить файл большего размера. Если он обрабатывается фрагментами, вы потенциально можете воспользоваться этим, создав вредоносный файл с полезной нагрузкой в ​​начале, за которой следует большое количество произвольных байтов заполнения.

Эксплуатация уязвимостей загрузки файлов без удаленного выполнения кода

В примерах, которые мы рассматривали до сих пор, мы могли загружать сценарии на стороне сервера для удаленного выполнения кода. Это наиболее серьезное последствие небезопасной функции загрузки файлов, но эти уязвимости все же можно использовать другими способами.

Загрузка вредоносных клиентских скриптов

Хотя вы, возможно, не сможете выполнять сценарии на сервере, вы все равно сможете загружать сценарии для атак на стороне клиента. Например, если вы можете загружать файлы HTML или изображения SVG, вы потенциально можете использовать <script>теги для создания сохраненных полезных данных XSS.

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

Эксплуатация уязвимостей в парсинге загружаемых файлов

Если кажется, что загруженный файл надежно хранится и обслуживается, в крайнем случае можно попытаться использовать уязвимости, характерные для синтаксического анализа или обработки файлов разных форматов. Например, вы знаете, что сервер анализирует файлы на основе XML, такие как Microsoft Office .docили .xlsфайлы, это может быть потенциальным вектором для атак с внедрением XXE .

Загрузка файлов с помощью PUT

Стоит отметить, что некоторые веб-серверы могут быть настроены на поддержку PUTзапросов. Если соответствующие средства защиты отсутствуют, это может предоставить альтернативный способ загрузки вредоносных файлов, даже если функция загрузки недоступна через веб-интерфейс.

PUT /images/exploit.php HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-httpd-php
Content-Length: 49

<?php echo file_get_contents(‘/path/to/file’); ?>

Кончик

Вы можете попробовать отправить OPTIONSзапросы на разные конечные точки, чтобы проверить, есть ли какие-либо, которые рекламируют поддержку PUTметода.

Как предотвратить уязвимости загрузки файлов

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

  • Проверьте расширение файла по белому списку разрешенных расширений, а не по черному списку запрещенных. Гораздо проще угадать, какие расширения вы хотите разрешить, чем угадать, какие из них может попытаться загрузить злоумышленник.
  • Убедитесь, что имя файла не содержит подстрок, которые можно интерпретировать как каталог или последовательность обхода ( ../).
  • Переименовывайте загруженные файлы, чтобы избежать конфликтов, которые могут привести к перезаписи существующих файлов.
  • Не загружайте файлы в постоянную файловую систему сервера, пока они не будут полностью проверены.
  • Насколько это возможно, используйте устоявшуюся структуру для предварительной обработки загружаемых файлов, а не пытайтесь писать собственные механизмы проверки.

Статья является переводом portswigger.net

You may also like

Leave a Comment