ODT под прицелом. Как заставить документы OpenOffice запускать произвольные файлы

ODT под прицелом. Как заставить документы OpenOffice запускать произвольные файлы

Life-Hack [Жизнь-Взлом]/Хакинг

#Обучение 

Эксплуатируем CVE-2018-16858

  • Теория
  • Практика
  • Создаем вредоносный файл
  • Запускаем эксплоит
  • Неуязвимые версии
  • Заключение

Эксплуатируем CVE-2018-16858

Теория

Найденная уязвимость позволяет выполнить несанкционированный доступ к файловой системе, используя атаку обхода пути (path traversal attack). Это одна из самых часто встречающихся уязвимостей и канонический тип атаки. 

В данном случае злонамеренно модифицированный файл ODT может загрузить за пределами родительского каталога скрипт на Python, который получит доступ к файловой системе и выполнит любые указанные действия с правами текущего пользователя.Первым данную уязвимость обнаружил старший пентестер немецкой фирмы Cure53 - Алекс Инфур (Alex Infuhr). Он предал свою находку огласке, и LibreOffice пропатчили, однако все версии до 6.0.7 (крайне популярные сейчас) по-прежнему уязвимы.

Немного размытой остается ситуация с Apache OpenOffice. Отдельного патча нет, и текущая версия 4.1.6 уязвима до сих пор. Сторонняя компания ACROS Security включила в свой агент 0patch заплатку для данной уязвимости, но только в версиях OpenOffice и LibreOffice для Windows. Более подробно см. на их сайте.

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



Наш микропатч для LibreOffice и OpenOffice просто проверяет, что [в документе] нет типичных шаблонов для выполнения атаки «обход пути», таких как «../», «\..» или «..|».

Интересно, что некоторые антивирусы также ищут признаки эксплоита по всему документу, включая его текстовые поля и игнорируя формат. Например, «Антивирус Касперского» ругается даже на эту статью, если попытаться открыть ее черновик в OpenOffice как .odt или в MS Office как .docx.



Практика

Разберем суть уязвимости. Во время инсталляции LibreOffice в Windows также устанавливается интерпретатор Python 3. Он находится по известному адресу:

C:\Program Files\LibreOffice\program\python-core-3.5.5\bin 

Офисный пакет может исполнить Python-скрипт, если указать ссылку на него внутри документа и правильно сослаться на него.Документы .odt основаны на XML (как и .docx), поэтому их внутреннюю структуру легко изучать и модифицировать. Здесь открывается большой простор для разных вариантов атак, но в общем случае нам необходимо создать в документе какую-либо задачу, которая запустит скрипт на Python.

Вот тут и наступает самое интересное. Если подменить путь к исполняемому коду и он будет соответствовать правилам исполнения, то LibreOffice выполнит его, не проверяя путь к скрипту. Например, мы можем выйти за рамки рабочей директории, и ничего нам за это не будет… а вот жертве — будет!

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

Создаем вредоносный файл

Открываем LibreOffice и создаем документ .odt с помощью Writer. Теперь нам необходимо добавить вызов любого Python-скрипта. На помощь приходит событие OnMouseOver, которое возникает при простом наведении курсора мыши на гиперссылку в документе. Преимущество состоит в том, что жертве даже кликать никуда не придется: навести курсор на ссылку в документе можно и случайно, особенно если она занимает весь лист и такого же белого цвета.

Идем в меню «Вставка → Гиперссылка». Заполняем поле URL любой ссылкой (неважно какой). В дополнительных настройках, напротив «Фрейм:», в конце окна есть кнопка «События», которая вызывает настройки макроса. В поле «Назначения» выбираем «Мышь над объектом» (то, о чем и было сказано). И в поле «Существующие макросы» добавим createTable (находится в ветке «Макросы LibreOffice → pythonSample»). Назначаем нужное нам событие.



Теперь заполняем поле «Текст» и кликаем «Применить». На листе появляется гиперссылка, при наведении на которую исполняется макрос. В моем примере так открывается еще один документ с информацией о первом в виде таблицы и парой примеров из руководства.



Сохраняем документ и закрываем. Упрощенно ODT — это XML в ZIP, поэтому посетить «недра» нашего файла можно с помощью любого архиватора с поддержкой ZIP. Я использую WinRAR. Открываем ODT как архив и смотрим структуру.

В корневом каталоге нас интересует файл content.

Разархивируем его и откроем в любом текстовом редакторе (я использую Notepad++). В конце разметки (на скриншоте выделил это в отдельную строку) видно, что явно указывается скрипт, который будет исполняться. Имя ему TableSample.py



Располагается данный файл (как и все примеры скриптов) по пути: 

C:\Program Files\LibreOffice\share\Scripts\python\pythonSamples

Если открыть его и посмотреть на исходный код, то можно заметить, что название одной из двух функций (а именно createTable() ) совпадает со словами в теле content после названия выполняемого скрипта. Это значит, что в файле разметки указано не только название файла со скриптом, но и функция, которую необходимо выполнить!



Проведем эксперимент: заменим в TableSample.py функцию createTable() на insertTextIntoCell(), не вписывая ее параметры. При открытии файла получим ошибку с названием новой функции. 



Отлично! Сообщения об ошибках — это та обратная связь, которая поможет сделать правильный вызов «боевой нагрузки». Добавим параметры для insertTextIntoCell() и запустим снова. Теперь возникает другая ошибка. Она показывает, что параметры неверны, а значит, принимались на исполнение и проверялись. Довольно приятные новости! 



Идем дальше. Восстановим документ в первоначальное состояние и попробуем изменить путь к скрипту (для этого я просто скопировал скрипт на уровень выше, а в файле content перед именем скрипта добавил ../ ). 

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

В использовавшемся для примера TableSample.py никаких потенциально опасных функций нет, а вот в каком-то другом скрипте из стандартной подборки они могут быть. Алекс Инфур нашел такой — pydoc.py , который находится в C:\Program Files\LibreOffice\program\python-core-3.5.5\lib. В нем есть функция tempfilepager().  С ее помощью через вызов os.system() можно запустить любой исполняемый файл, причем с произвольными аргументами — достаточно передать их в строчку 

os.system(cmd + ' "' + filename + '"')



Чтобы все заработало, нам необходимо лишь прописать путь до скрипта и вызывать опасную функцию с нужными параметрами.



Запускаем эксплоит

Настал момент X! Мы открываем модифицированный документ ODT, курсор оказывается наведенным на скрытую ссылку, и происходит магия — без разрешения пользователя запускается произвольный файл (злобный пейлоад или простой калькулятор в качестве PoC).

Для OpenOffice строка будет выглядеть так:

<office:event-listeners><script:event-listener script:language="ooo:script" script:event-name="dom:mouseover" xlink:href="vnd.sun.star.script:../../../program/python-core-2.7.6/lib/pydoc.py$tempfilepager(1, calc.exe )?language=Python&location=share" xlink:type="simple"/>

В LibreOffice она же записывается так:

<office:event-listeners><script:event-listener script:language="ooo:script" script:event-name="dom:mouseover" xlink:href="vnd.sun.star.script:../../../program/python-core-3.5.5/lib/pydoc.py$tempfilepager(1, calc.exe )?language=Python&location=share" xlink:type="simple"/>

Вот и вся разница.

Неуязвимые версии

После проделанных опытов я начал изучать заплатку этой уязвимости. В LibreOffice версии 6.0.7 я заметил ошибку, которая стала возникать при запуске скрипта, до этого работавшего в LibreOffice 6.0.6.2. Она ссылается на строку 998 файла pythonscript.py, расположенного в папке: 

C:\Program Files\LibreOffice\program



Как видно на скриншоте, функция getScript() просит параметр scriptUri. Как раз в этом параметре и возникает ошибка в строке

mod = self.provCtx.getModuleByUrl(fileUri) 

Та же самая ошибка возникает в OpenOffice, если эксплуатационный файл сконфигурирован неправильно (неверно указан путь к скрипту). Эта ошибка возникала и когда я пытался вызвать скрипт на удаленной машине по SMB-протоколу в формате \\\server\pydoc.py

Изучив код

pythonscript.py, я увидел, что функция scriptURI2StorageUri() (214-я строка файла) претерпела кардинальные изменения. Теперь она проверяет, находится ли скрипт в рабочей директории или нет. Выглядит этот фрагмент так:

# base path to the python script location
sBaseUri = self.m_baseUri + "/"
xBaseUri = self.m_uriRefFac.parse(sBaseUri)
# path to the .py file + "$functionname, arguments, etc
xStorageUri = self.m_uriRefFac.parse(scriptURI)
sStorageUri = xStorageUri.getName().replace( "|", "/" );
# path to the .py file, relative to the base
sFileUri = sStorageUri[0:sStorageUri.find("$")]
xFileUri = self.m_uriRefFac.parse(sFileUri)
if not xFileUri:
message = "pythonscript: invalid relative uri '" + sFileUri+ "'"
log.debug( message )
raise RuntimeException( message )
# absolute path to the .py file
xAbsScriptUri = self.m_uriRefFac.makeAbsolute(xBaseUri, xFileUri, True, RETAIN)
sAbsScriptUri = xAbsScriptUri.getUriReference()
# ensure py file is under the base path
if not sAbsScriptUri.startswith(sBaseUri):
message = "pythonscript: storage uri '" + sAbsScriptUri + "' not in base uri '" + self.m_baseUri + "'"
log.debug( message )
raise RuntimeException( message )
ret = sBaseUri + sStorageUri

Более подробное сравнение приводится на скриншоте.



Сама функция tempfilepager() никак не изменилась вплоть до LibreOffice v.6.2.1 (на момент написания статьи — последняя из стабильных). Строчку обращения к операционной системе по заданным параметрам все так же можно использовать. Если удастся обойти запрет на указание местоположения файла, то можно будет эксплуатировать очередную уязвимость, изменив лишь название папки на python-core-3.5.

Заключение

Мы разобрали уязвимость CVE-2018-16858, эксплуатация которой считается очень легкой. Проблема в том, что дырявые версии LibreOffice продолжают широко использоваться, а OpenOffice не пропатчен до сих пор. Поэтому не откладывай обновление LibreOffice и озаботься дополнительным уровнем защиты для OpenOffice.

Источник


Report Page