
Введение
Привет всем! Меня зовут Михаил Жмайло, я пентестер в команде CICADA8.
Символические ссылки присутствуют в Windows практически с момента его появления. Однако лишь немногие курсы по анализу защищенности смогут раскрыть весь их потенциал и позволят нам получить заветный LPE.
Моя статья подробно расскажет о символических ссылках, специфике работы с ними, а также наглядно покажет варианты их злоупотребления для получения LPE.
Что такое символическая ссылка?
Символическая ссылка позволяет указать от одного объекта на другой.
Буквально: симлинка example может указывать на файл 1.txt. И вы, обратившись к example, попадете в 1.txt.
В Windows есть разные виды символических ссылок. Рассмотрим их подробнее.
NTFS (Soft Link) - позволяет связать один файл с другим. Чтобы создать её, нужны права администратора или привилегия SeCreateSymbolicLinkPrivilege
, либо включённый Windows Developer Mode. Создать такую ссылку можно так:
#cmd.exe
mklink link.txt orig.txt
#winapi
BOOLEAN CreateSymbolicLinkA(
[in] LPCSTR lpSymlinkFileName,
[in] LPCSTR lpTargetFileName,
[in] DWORD dwFlags
);

Hard Link - также позволяет связать один файл с другим, но только в пределах одного диска. Для создания требуются права FILE_WRITE_ATTRIBUTES
. Есть нюанс - нельзя создавать ссылки на каталоги. Подробнее можно почитать здесь.
Создание:
# cmd.exe
mklink /H link.txt orig.txt
# ZwSetInformationFile
https://github.com/googleprojectzero/symboliclink-testing-tools/blob/00c0fe4cefcd2a62c887fe6117abc02bc98bb9fb/CommonUtils/Hardlink.cpp#L20

Registry Link - позволяет создавать ссылки от одного ключа реестра к другому.Для создания нужны права KEY_CREATE_LINK
+ KEY_CREATE_SUB_KEY
. Нельзя создавать ссылки, которые указывают из более низкого куста реестра в более высокий (например, HKCU\XXXX → HKLM\XXXX).
# Creation using NtCreateKey()
https://github.com/googleprojectzero/symboliclink-testing-tools/blob/main/CommonUtils/RegistrySymlink.cpp#L121

Как видите, почти все символические ссылки требуют достаточно привилегированного аккаунта. Однако как тогда мы можем повыситься с помощью симлинок? Неужели вариантов нет?
К счастью, мы изучили только основные и самые популярные типы симлинок. Есть еще два вида, которые чаще всего встречаются в эксплойтах.
NTFS Mount Point
Это символическая ссылка от одной папки к другой. Она может быть создана от имени низкопривилегированного пользователя. Каталог, который превращается в симлинку, должен быть пустым, и у нас должны быть права на запись в него.
Создание:
# cmd.exe
mklink /J Dir-link Directory
# DeviceIoControl()
https://github.com/googleprojectzero/symboliclink-testing-tools/tree/main/CreateMountPoint

Object Manager Symlink
Позволяет создавать символические ссылки в пространстве Object Manager.
Низкопривилегированный пользователь может создавать симлинки внутри пространств имен \RPC Control
и \BaseNamedObjects\Restricted
. Также можно попытаться создать символическую ссылку внутри \BaseNamedObjects
, при выполнении определённых условий.
Создание:
# NtCreateSymbolicLinkObject()
https://github.com/googleprojectzero/symboliclink-testing-tools/tree/main/NativeSymlink
# DefineDosDevice()
https://github.com/googleprojectzero/symboliclink-testing-tools/tree/main/CreateDosDeviceSymlink

Подробнее про Object Manager можно почитать здесь.
Чаще всего для достижения целей LPE будут использоваться именно символические ссылки вида NTFS Mount Point + Object Manager Symlink.
Пример Arbitrary File Deletion
Допустим, мы знаем, что над контролируемом нами файлом выполняется привилегированная операция, которая может привести к LPE. И, конечно же, мы хотим этим злоупотребить.

Предположим, существует Windows-сервис, который удаляет файл C:\Temp\abc\file.txt.
Мы хотим подменить этот файл симлинкой так, чтобы удалился C:\Windows\controlled.txt, при этом мы работаем от лица низкопривилегированного аккаунта. У нас есть полные права на C:\Temp\abc и сам file.txt, но абсолютно нет никаких прав на controlled.txt.
Как действуем:
Создаём Object Manager симлинк из \RPC Control\file.txt на C:\Windows\Controlled.txt.
Создаём NTFS Mount Point от C:\Temp\abc (предварительно удалив все файлы из этой папки) на \RPC Control.
Видим успешное удаление C:\Windows\controlled.txt!
Как это работает?
Сначала высокопривилегированная служба, выполняющая операцию удаления, вызывает метод вроде DeleteFile() для файла C:\Temp\abc\file.txt. Однако вместо этого файла у нас стоит симлинка.
Каталог C:\Temp\abc указывает на \RPC Control. Таким образом, происходит обращение к \RPC Control\file.txt. Это тоже симлинка, только она указывает на C:\Windows\controlled.txt.
В результате служба последовательно проходит через две симлинки и, вместо того чтобы удалить нужный C:\Temp\abc\file.txt, удаляет C:\Windows\controlled.txt.
Вот так и выглядит эта уязвимость :)
Она называется произвольное удаление файлов (Arbitrary File Deletion).
Еще примеры злоупотребления
Итак, общая логика эксплуатации выглядит следующим образом.
Мы создаём две символические ссылки, после чего перенаправляем поток исполнения привилегированной службы на симлинк, заставляя её выполнять нужные нам операции над целевым файлом.

Примеры CVE с Arbitrary File Delete:
CVE-2020–0683 — Windows MSI Installer Elevation of Privilege
CVE-2023–21800 — Windows Installer EOP
CVE-2024–29404 — Razer EOP
Кроме удаления, существует копирование, создание, перемещение и перезапись. Ловите POC для демонстрации:
CVE-2024–26238 — Windows 10 PlugScheduler Arbitrary Create
CVE-2024–12754 — AnyDesk LPE Arbitrary Copy
CVE-2024–37726 — MSI Center Arbitrary Overwrite
CVE-2024–21111 — Oracle VirtualBox LPE
CVE-2020–1076 — Arbitrary file write in VaultSvc
Как найти такую уязвимость?
Самый простой способ найти такую уязвимость — использовать Process Monitor.
Для этого настройте параметры так, как сделал я, затем отслеживайте операции с файлами и проверяйте, какие из них вы можете заменить символической ссылкой.

Пример:
Когда я исследовал LPE в AnyDesk выяснилось, что привилегированная операция выполняется над файлом C:\users\<username>\AppData\Roaming\Microsoft\Windows\Themes\<wallpaper>.png
, над которым у нас был полный контроль, после чего файл копировался в C:\Windows\Temp\<wallpaper>.png
.

Затем вам нужно определить контекст, то есть от имени какого пользователя выполняется привилегированная операция.
В нашем случае это был NT AUTHORITY\SYSTEM, что и привело к получению LPE.

Итак, нам просто нужно инициировать привилегированную операцию с подконтрольным нами файлом, а затем заменить этот файл символической ссылкой. Но как триггерить подобные действия, которые будут исполнять процессы, работающие от лица системы или других High-Priv учеток?
Здесь я предлагаю несколько вариантов:
Отправку IOCTL-драйверу — можно попробовать вызвать метод драйвера, который работает с файлами, и указать путь до контролируемого нами файла.
Массовое создание COM-объектов — при инициализации COM-объекты могут обращаться к разным файлам, работая от имени NT AUTHORITY\SYSTEM.
Установку MSI-пакета — во время установки MSI-пакета могут использоваться различные файлы, некоторые из которых мы можем попробовать подменить симлинкой;
GUI/RPC/ALPC — наконец, можно попробовать взаимодействовать с целевым приложением через IPC-интерфейсы, которые оно предоставляет. Такой вариант был в LPE через AnyDesk. Привилегированная операция выполнялась при подключении пользователя к сессии.
Произвольное удаление файлов
Давайте подробнее рассмотрим эту уязвимость. Например, как произвольное удаление файлов раньше использовалось для злоупотреблением антивирусом : )

Итак, у нас есть антивирусная служба, работающая от имени NT AUTHORITY\SYSTEM.
Хакер помещает на диск устройства вредоносный файл EICAR.
Затем он запускает проверку Last Access TimeStamp в цикле, пытаясь определить, когда антивирус обратился к его файлу.
Антивирус получает доступ к файлу, определяет его как вредоносный и пытается удалить с диска.
Однако в этот момент хакер заменяет свой файл на символическую ссылку, которая с помощью комбинации NTFS Mount Point и Object Manager Symlink указывает на критически важный файл самого антивируса.
Таким образом, антивирус сам себя удаляет :)
Что можно сделать после того, как вы добились произвольного удаления файлов?
Есть более общий вариант — попробуйте удалить какую-либо библиотеку DLL, а затем записать на её место свою. Обратите внимание на механизмы Search Order Hijacking и DLL Redirection. Однако это чуть более сложный сценарий.
Рассмотрим более простой метод — злоупотребление механизмом Windows Installer Rollback. Этот способ позволяет получить системную оболочку, используя примитив произвольного удаления файлов.

Механизм основан на том, что мы удаляем папку C:\Config.msi, записываем туда собственные вредоносные MSI-файлы и запускаем механизм Rollback, что приводит к выполнению этих файлов. Вы можете подробнее изучить этот механизм в следующих CVE:
CVE-2023–27470 — Take Control Agent 7.0.41.1141 LPE;
CVE-2023–20178 — Уязвимость произвольного удаления файлов в Cisco Secure Client (проверено на версии 5.0.01242) и Cisco AnyConnect (проверено на версии 4.10.06079);
CVE-2022–30206 — Уязвимость повышения привилегий в Windows Print Spooler.
Честно говоря, я был довольно удивлён тем фактом, что тема злоупотребления символическими ссылками в значительной степени игнорируется в ведущих и самых популярных курсах по offensive security.Тем не менее, эта уязвимость крайне актуальна. Всего пару месяцев назад была зарегистрирована ещё одна CVE, связанная со злоупотреблением символическими ссылками. Ресерч можно прочитать здесь.
Arbitrary File Create/Copy и пару трюков
А что, если вы можете контролировать создание или копирование файлов?
В таком случае я предлагаю два варианта злоупотребления:
более общий: попробуйте записать новый конфигурационный файл для какой-либо службы, разместить скрипты в общесистемной автозагрузке или использовать механизм DLL Redirection (создание файлов с расширением .local);
чуть более сложный вариант: кроме того, существует потенциально уязвимая служба DiagHub, которая позволяет загружать произвольную библиотеку из каталога C:\Windows\System32. Попробуйте записать свою библиотеку в эту папку и затриггерить службу. Подробнее об этом можно прочитать здесь и здесь.


Однако во время эксплуатации вы можете столкнуться с определенной проблемой — целевое приложение проверяет файл перед его копированием или созданием. В таком случае обратите внимание на репозиторий BaitAndSwitch. Этот репозиторий позволит вам выполнить атаку типа Time of Check — Time of Use (TOCTOU). В чём она заключается?
Сначала мы также создаём символическую ссылку, но она указывает на легитимный файл, который проходит проверку.
При этом на этот легитимный файл устанавливается OpLock.
OpLock позволяет отслеживать запросы к проверяемому файлу.
Как только целевая служба запрашивает легитимный файл, срабатывает OpLock, и наша символическая ссылка меняется — вместо легитимного файла она начинает указывать на вредоносный.

Это первый приём, который вы можете использовать при эксплуатации произвольного копирования или создания файлов.
Второй приём — перезапись DACL. Он применялся при создании POC для LPE в AnyDesk.
У нас был следующий случай: мы могли произвольно копировать любые системные файлы в папку C:\Windows\Temp, но файлы копировались вместе со своими исходными DACL, из-за чего мы не могли их читать.
Поэтому мы просто заново создавали целевые файлы в папке C:\Windows\Temp, и уязвимая служба невольно выполняла операцию произвольной перезаписи вместо копирования. И в этом случае использовался уже оригинальный DACL, то есть тот, который имели созданные нами файлы. И мы без проблем могли читать свои файлы.

Подробнее об этом можно почитать здесь
Arbitrary File Overwrite/Move
Стоит отметить, что если вы добились примитива перемещения или перезаписи файлов, то методы эксплуатации практически не будут отличаться от методов, используемых при произвольном копировании или создании. Точно также рассмотрите возможность записи DLL-библиотек или использования DiagHub.
Однако и здесь есть пару приколов. Вы знали, что операция переименования может привести к перемещению файла? Давайте разберём подробнее.
Предположим, у нас есть какая-то привилегированная служба, которая выполняет операцию переименования из C:\abc\private.txt в C:\xyz\public.txt.
В данном случае мы контролируем оба файла: private.txt и public.txt.

В этом случае мы можем создать две символические ссылки: одна будет называться private.txt, а вторая — public.txt. И они будут указывать на те файлы, которые мы хотим переместить.
Например, private.txt будет указывать на вредоносную DLL-библиотеку C:\hack\pwn.dll, которую мы хотим записать по пути C:\LegitService\Legit.dll.
Соответственно, public.txt должна указывать на C:\LegitService\Legit.dll.
Таким образом, когда служба попытается переименовать C:\abc\private.txt в C:\xyz\public.txt, на самом деле, она переименует C:\hack\pwn.dll в C:\LegitService\Legit.dll.
Подробнее об этой замечательной технике можно прочитать здесь.
Arbitrary Directory Creation
Существуют и более изощренные методы.
Например, когда вы можете контролировать создаваемую папку. В таком случае можно попробовать развить эту возможность до Arbitrary File Read.

В этом случае вам нужно создать папку со специальным именем, например, c_1337.nls, и преобразовать её в NTFS Mount Point, указывающий на нужный файл. Да, именно на файл, а не на каталог — мы будем работать со службой National Language Support, которая использует специальный системный вызов, позволяющий преобразовать символическую ссылку NTFS Mount Point в файл.
После этого мы триггерим службу National Language Support, и целевой файл будет смапплен в общую память. Всё, что останется сделать, — найти нужный файл в памяти по его характерному имени.
Вы можете найти пример POC здесь, а оригинальное исследование — здесь.
Обход UAC через симлинки
Также вы можете использовать символические ссылки, чтобы обойти UAC!
Стоит отметить, что этот метод работает только на системах с процессорами Intel. Чтобы его использовать, необходимо найти папку ShaderCache, удалить из неё все файлы, создать NTFS Mount Point, а затем всего-навсего добиться примитива произвольной перезаписи и записать свою DLL.

Вы можете найти оригинальное исследование — здесь.
Пару слов про защиту
Как можно защититься от злоупотребления символическими ссылками?
Я вижу два варианта:
-
RedirectionTrust — система не будет переходить по символическим ссылкам, которые создал пользователь с более низким уровнем целостности (IL)
POC для поиска механизма RedirectionTrust в работающих процессах.
2. Имперсонация — ваша служба должна использовать токен низкопривилегированного пользователя для выполнения операций с файлами. Вы можете использовать чужой токен с помощью специальных функций, например, ImpersonateLoggedOnUser().
Также обратите внимание на этот блокировщик эксплойтов
Заключение
Спасибо, что дочитали мою статью. Надеюсь, материал поможет вам в изучении способов злоупотребления символическими ссылками :)