Цикл о том, как я нахожу уязвимости повышений привилегий в Windows приложениях, продолжается. В предыдущих сериях: Steam (CVE-2019-14743, CVE-2019-15316, CVE-2019-17180) и Origin (CVE-2019-19247, CVE-2019-19248). Но сегодня речь пойдет не об игровом лаунчере, а о прикладном программном комплексе ABBYY FinerReader.



Краткое содержание – я расскажу, как благодаря компоненту, проверяющему лицензию, за 10 минут можно поднять свои права с уровня пользователя до NT AUTHORITY\SYSTEM. Данной уязвимости был присвоен идентификатор CVE-2019-20383, ссылка на сайт ABBYY.

Разведка


Я скачал с сайта ABBYY пробную версию FineReader и быстро проверил ее на предмет того, а есть ли вообще смысл ковырять продукт на предмет повышения привилегий. Да, в состав продукта входит сервис, который, судя по названию «ABBYY network license server», связан с лицензиями и по-умолчанию запущен от пользователя NT AUTHORITY\SYSTEM. Я запустил ProcMon начал смотреть поведение сервиса.

Мое внимание привлек файл, расположенный по пути «C:\ProgramData\ABBYY\FineReader\15\Licenses\Licensing.cnt». Сервис что-то из него читает, что-то в него пишет, в общем файл выглядел интересным кандидатом для опытов. Рассмотрим папку «C:\ProgramData\ABBYY\FineReader\15\Licenses». Для данной папки действует наследованный ACL «Все-Полный доступ» от родительской папки («C:\ProgramData\ABBYY\FineReader\15»), а значит можно удалить все ее содержимое, включая файл «Licensing.cnt».

Сервис, обнаружив отсутствие файла, попытался его создать, причем немного странным образом. Он создал файл вида «tmpXXXX-YYYYYYYYY.tmp», записал в него какие-то данные, а затем переименовал его в «Licensing.cnt».

Вот лог ProcMon в котором эта операция выполняется дважды.



Сначала она происходит в 20:36, а затем в 20:46. Между этими временными отметками файл снова был удален, чтобы быть созданным снова.

Прямоугольником 1 обозначена ситуация, когда сервис обнаружил отсутствие файла. Прямоугольник 2 – создание временного файла. Прямоугольник 3 – переименование временного файла. Прямоугольник 4 – повторение операций через 10 минут.

Рассмотрим формат имени «tmpXXXX_YYYYYYYYY.tmp». В рамках одного запущенного процесса XXXX будет всегда постоянным, более того, на самом деле это идентификатор треда, который выполняет данные работы. YYYYYYYYY не остается постоянным, но если посмотрим на два соседних запуска (значения: 430210515 и 430810515), то появляется предположение, что это просто некоторая временная метка – разница между числами 600000 – удивительным образом совпадает с 10 минутами разницы. Еще несколько тестов подтверждают наше предположение.
Подведем итог этой части. Любой пользователь может удалить файл «C:\ProgramData\ABBYY\FineReader\15\Licenses\Licensing.cnt», далее он может в цикле очень часто запрашивать содержимое папки «C:\ProgramData\ABBYY\FineReader\15\Licenses» и в некоторый момент обнаружить там файл с именем «tmpXXXX_YYYYYYYYY.tmp». Теперь пользователь будет подготовлен, после удаления файла он точно будет знать, в какой момент и с каким именем будет создан файл в следующий раз.

Теперь мы поиграем с симлинками


Как создавать симлинки без прав администратора
В общем случае, для создания симлинка с одного файла на другой необходимы права администратора. Но эту необходимость можно обойти. Рассмотрим, например, создание симлинка с файла «C:\abc\1» на файл «C:\def\2».

Сначала создадим NTFS reparse point (другое название NTFS mount point) с папки «C:\abc» на «\RPC Control\". «\RPC Control\» – это не обычная папка в привычном нам понимании, ее нельзя посмотреть, например, в эксплорере. Это системная объектная директория, внутри которой находятся, например, именованные мьютексы, события и прочие подобные объекты. Почему для нее работает перенаправление через NTFS reparse point непонятно, скорее всего, дело в использовании одинаковых абстракций для папок в файловой системе и объектных директорий. Для создания репарс-поинта необходимо, чтобы папка-источник была пустой и были права на запись в эту папку у пользователя.

Из объектной директории можно создать симлинк на файл без прав администратора. Создадим симлинк вида "\RPC Control\1" <-> «C:\def\2». В итоге, при обращении к файлу «C:\abc\1», все действия будут перенаправлены на файл «C:\def\2».

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



Когда мы знаем точный момент следующей такой операции, мы можем создать следующие симлинки (имя исходной папки «C:\ProgramData\ABBYY\FineReader\15\Licenses\» пропустим):

tmpXXXX_YYYYYYYYA.tmp <-> C:\test\l1\proxy
tmpXXXX_YYYYYYYYB.tmp <-> C:\test\l1\proxy
tmpXXXX_YYYYYYYYC.tmp <-> C:\test\l1\proxy

tmpXXXX_YYYYYYYYZ.tmp <-> C:\test\l1\proxy


Где YYYYYYYYA, YYYYYYYYB, YYYYYYYYC, … YYYYYYYYZ – это различные временные метки в районе YYYYYYYYY+10минут (на случай, если временная метка слегка запоздает).

Далее создадим линк:

C:\test\l1\proxy <-> C:\test\l2\nope

Обратите внимание, что реально ни одного из этих файлов не существует. Это нужно, чтобы при обращении, например, к tmpXXXX_YYYYYYYYB.tmp, произошло два перенаправления и в результате сервис работал с файлом «C:\test\l2\nope».
Как только мы обнаружим создание файла «C:\test\l2\nope», тут же следует создать два новых симлинка:

C:\test\l1\proxy <-> C:\test\l2\payload
Licensing.cnt <-> C:\target\path


Сервис продолжит писать содержимое файла в «C:\test\l2\nope», но переименование будет производить, уже пройдя по новому симлинку. Таким образом, вместо переименования, например, «tmpXXXX_YYYYYYYYC.tmp» в «Licensing.cnt», реально будет переименован (перемещен) «C:\test\l2\payload» в «C:\target\path». Фактически мы можем разместить файл с любым содержимым по любому пути от имени пользователя NT AUTHORITY\SYSTEM.

Схематично это будет выглядеть так:



Цветом отмечено то, что реально будет выполняться из-за влияния симлинков.

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

На данный момент, согласно ABBYY, уязвимость закрыта.

Timeline


25.11.2019 — обнаружение уязвимости
26.11.2019 — запросил у производителя security-контакт
26.11.2019 — отправка отчета об уязвимости производителю
09.12.2019 — уязвимость подтверждена производителем
10.01.2020 — уязвимость исправлена
22.01.2020 — уязвимости присвоен CVE-2019-20383
19.02.2020 — публикация данной статьи

Проектов сейчас много и мы расширяем команду «Перспективного мониторинга». Мы ищем специалистов по исследованию исходных кодов, а также экспертов в анализе мобильных приложений. Хотите присоединиться к моей команде — пишите мне, Анастасии (Ana2121) или на почту info@amonitoring.ru

This article in english.