В 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
Инсталлируем приложение.
Далее создаем администратора системы. Для тестирования уязвимости нам понадобится пользователь с возможностью загружать аттачи. Создаем его, и стенд готов.
Как ты уже знаешь, проблема кроется в загрузке всех прикрепленных к записи файлов. Создадим произвольную запись и загрузим к ней несколько файлов.
Обрати внимание на кнопку 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.
01: package com.atlassian.confluence.pages.actions; 02: ... 18: public class DownloadAllAttachmentsOnPageAction extends AbstractPageAwareAction { 19: AttachmentManager attachmentManager;
Чтобы сразу определить, где конкретно проблема, можно заглянуть в этот же файл, только в пропатченной версии, например 6.12.4.
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()));
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
.
82: public static String extractFileName(String pathname) { 83: if (pathname == null) 84: return null; 85: return (new File(pathname)).getName(); 86: }
Значит, проблема в имени. Посмотрим на содержимое класса DownloadAllAttachmentsOnPageAction
, а именно метод execute
.
31: public String execute() throws Exception { 32: List<Attachment> latestAttachments = this.attachmentManager.getLatestVersionsOfAttachments(getPage()); 33: for (Attachment attachment : latestAttachments) {
Сначала данные всех файлов попадают в массив latestAttachments
, затем функция for
перебирает его элементы и читает содержимое каждого файла. Обрати внимание, что создается объект типа File. Он указывает на временный файл, имя которого эквивалентно имени аттача.
Материалы из последних выпусков можно покупать отдельно только через два месяца после публикации. Чтобы продолжить чтение, необходимо купить подписку.
Подписка позволит тебе в течение указанного срока читать ВСЕ платные материалы сайта. Мы принимаем оплату банковскими картами, электронными деньгами и переводами со счетов мобильных операторов. Подробнее о подписке
1 год5690 р. Экономия 1400 рублей! |
1 месяц720 р. 25-30 статей в месяц |
Уже подписан?
Читайте также
Последние новости