Сливаем Confluence. Как эксплуатировать path traversal и RCE в корпоративной вики

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

Баг в конце марта обнаружил латвийский исследователь Янис Крустс (Jānis Krusts) из IT Centrs. Ей присвоили номер CVE-2019-3398. Баг сводится к тому, что отсутствие фильтрации имен файлов в DownloadAllAttachmentsOnPageAction дает возможность атакующему выйти из временной директории и записать файл с произвольным содержимым в любую папку, доступную для записи.

Для проведения атаки требуется учетная запись с правами создания и редактирования записей. Уязвимы множество версий в разных ветках приложения. Все, что вышло аж с Confluence 2.0.0 вплоть до Confluence 6.6.12, уязвимо. Также проблемными оказались версии с 6.7.0 до 6.12.3, версии с 6.13.0 по 6.13.3, с 6.14.0 до 6.14.2 и с 6.15.0 по 6.15.2 включительно. Более детальный список можно посмотреть в официальной базе знаний.

 

Стенд

У Confluence простой инсталлятор, который работает в большинстве современных операционных систем. Для тестов я возьму Confluence 6.9.0. Если в качестве основной ОС у тебя Windows, то можно воспользоваться инсталлятором. Однако я рекомендую более универсальный метод — запустить контейнер Docker. Не забывай прокидывать необходимые порты.

$ docker run --rm --name=confluence.vh --hostname=conflvh -p 8090:8090 -p 8091:8091 atlassian/confluence-server:6.9.0

Инсталлируем приложение.

Установка Atlassian Confluence 6.9.0

Далее создаем администратора системы. Для тестирования уязвимости нам понадобится пользователь с возможностью загружать аттачи. Создаем его, и стенд готов.

Готовый стенд с Confluence 6.9.0
 

Детали уязвимости CVE-2019-3398

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

Загруженные файлы к посту блога в Confluence

Обрати внимание на кнопку Download All — она скачивает все файлы. Перед этим они любезно упаковываются в ZIP, который и отправляется пользователю. В моем случае ссылка имеет вид http://confluence.vh:8090/pages/downloadallattachments.action?pageId=65601. Из названия экшена видно, что за скачивание отвечает класс DownloadAllAttachmentsOnPageAction. Он расположен в файле confluence/WEB-INF/lib/confluence-6.9.0.jar. Для декомпиляции я воспользуюсь утилитой JD-GUI версии 1.5.

/com/atlassian/confluence/pages/actions/DownloadAllAttachmentsOnPageAction.java

01: package com.atlassian.confluence.pages.actions;
02:
...
18: public class DownloadAllAttachmentsOnPageAction extends AbstractPageAwareAction {
19:   AttachmentManager attachmentManager;

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

/confluence-6.12.4/com/atlassian/confluence/pages/actions/DownloadAllAttachmentsOnPageAction.java

19: public class DownloadAllAttachmentsOnPageAction extends AbstractPageAwareAction {
20:   AttachmentManager attachmentManager;
...
32:   public String execute() throws Exception {
33:     List<Attachment> latestAttachments = this.attachmentManager.getLatestVersionsOfAttachments(getPage());
34:     for (Attachment attachment : latestAttachments) {
35:       File tmpFile = new File(getTempDirectoryForZipping(), ConfluenceFileUtils.extractFileName(attachment.getFileName()));

/confluence-6.9.0/com/atlassian/confluence/pages/actions/DownloadAllAttachmentsOnPageAction.java

18: public class DownloadAllAttachmentsOnPageAction extends AbstractPageAwareAction {
19:   AttachmentManager attachmentManager;
...
31:   public String execute() throws Exception {
32:     List<Attachment> latestAttachments = this.attachmentManager.getLatestVersionsOfAttachments(getPage());
33:     for (Attachment attachment : latestAttachments) {
34:       File tmpFile = new File(getTempDirectoryForZipping(), attachment.getFileName());

Как видишь, второй параметр, который отвечает за имя аттача, в новой версии метода execute фильтруется при помощи extractFileName.

/confluence-6.12.4/com/atlassian/confluence/util/io/ConfluenceFileUtils.java

82:   public static String extractFileName(String pathname) {
83:     if (pathname == null)
84:       return null;
85:     return (new File(pathname)).getName();
86:   }

Значит, проблема в имени. Посмотрим на содержимое класса DownloadAllAttachmentsOnPageAction, а именно метод execute.

/com/atlassian/confluence/pages/actions/DownloadAllAttachmentsOnPageAction.java

31:   public String execute() throws Exception {
32:     List<Attachment> latestAttachments = this.attachmentManager.getLatestVersionsOfAttachments(getPage());
33:     for (Attachment attachment : latestAttachments) {

Сначала данные всех файлов попадают в массив latestAttachments, затем функция for перебирает его элементы и читает содержимое каждого файла. Обрати внимание, что создается объект типа File. Он указывает на временный файл, имя которого эквивалентно имени аттача.

Источник: xakep.ru

Ответить

Ваш адрес email не будет опубликован. Обязательные поля помечены *