
Созданный вручную шеллкод режима ядра Windows x64 для кражи токенов
Windows x64 собственноручно написанный шеллкод режима ядра для замены основного токена доступа выполняющегося процесса на токен процесса SYSTEM для повышения привилегий (EoP).
Windows 7/Windows Server 2008 R2 Build 7601Windows 8/Windows Server 2012 Build 9200Windows 8.1/Windows Server 2012 R2 Build 9600Windows 10 1507/TS1 Build 10240Windows 10 1511/TS2 Build 10586Windows 10 1607/RS1/Windows Server 2016 Build 14393Windows 10 1703/RS2 Build 15063Windows 10 1709/RS3 Build 16299Windows 10 1803/RS4 Build 17134Windows 10 1809/RS5/Windows Server 2019 Build 17763Windows 10 1903/19H1 Build 18362Windows 10 1909/19H2 Build 18363Windows 10 2004/20H1 Build 19041Windows 10 2009/20H2 Build 19042Windows 10 2104/21H1 Build 19043Windows 10 2110/21H2 Build 19044Предварительные требования для сборки этого проекта:
Visual Studio 2019(any edition will do fine)Windows 10 SDK, version 2004Windows 10 WDK, version 2004Python3Здесь следует отметить, что можно обойтись и просто наличием ассемблера (в этом проекте используется MASM), поскольку технически это всё, что нужно.
После установки вышеперечисленного достаточно открыть решение в Visual Studio и собрать его для целевой платформы x64.
После успешной сборки бинарные файлы можно найти в каталоге Bin в соответствующем подкаталоге разрядности.
Как вариант, можно загрузить готовый к развёртыванию позиционно-независимый шеллкод из Releases.
Пожалуйста, НЕ пытайтесь развернуть полезную нагрузку на машине, которая нужна вам для работы, если вы не уверены в том, как она работает.
За дополнительной информацией обращайтесь к документации Microsoft.
Для целей тестирования я настоятельно рекомендую использовать flare-kscldr для развёртывания шеллкода режима ядра на тестовой VM и руководство CodeMachine по настройке системы для разработки и отладки ядра для настройки Hyper-V Guest VM с полной поддержкой отладки ядра.
При желании можно также рассмотреть автоматизацию процесса с помощью kdbg-driver-vagrant, чтобы быстро поднять тестовую VM с полной отладкой ядра, используя Vagrant.

Как мне указал Дмитрий Олексюк(@d_olex), в коде есть довольно явные состояния гонки, связанные конкретно с:
nt!_EPROCESS, связанных между собой через двунаправленный циклический список, без использования какого-либо примитива синхронизации/механизма блокировкиВ настоящее время в них отсутствует какая-либо защита от изменений, которые могут происходить, пока мы с ними работаем.
Проблема ли это? Да, состояния гонки всегда проблематичны и могут вызывать всевозможное неопределённое поведение/неприятные багчеки.
Повлияет ли использование этой полезной нагрузки на стабильность моего эксплойта? Возможно.
Ну и каково исправление? Исправление состоит из двух шагов.
Часть 1 включает получение блокировки типа ожидания, такой как pushlock — nt!PspActiveProcessLock (указатель на pushlock) для эксклюзивного доступа с помощью nt!ExAcquirePushLockExclusive перед обходом списка процессов (обычную доставку APC ядра необходимо предварительно отключить) и nt!ExReleasePushLockExclusive для снятия блокировки после завершения работы со списком, после чего следует снова включить обычную доставку APC ядра.
Однако, поскольку эта глобальная переменная не экспортируется ядром nt, гораздо более корректным и безопасным подходом было бы использование nt!ZwQuerySystemInformation API с SYSTEM_INFORMATION_CLASS == SystemProcessInformation для поиска PID по ImageName и nt!PsLookupProcessByProcessId для получения VA структуры nt!_EPROCESS по PID.
Если вам, однако, любопытно, как ядро выполняет первое, я предложил бы вам посмотреть на nt!PsGetNextProcess в дизассемблере.
Часть 2 включает безопасные ссылки на объекты с помощью семейства nt!ObReferenceObject API для увеличения счётчика ссылок на объект процесса, чтобы его нельзя было удалить, пока мы явно не уменьшим его в конце после завершения работы с ним с помощью nt!ObDereferenceObject.
Обратите внимание, что ручное увеличение счётчика ссылок избыточно, поскольку вызов nt!PsLookupProcessByProcessId, если он успешен, делает это за нас.
Однако реализация этих исправлений потребовала бы поиска базового адреса ntoskrnl.exe и разрешения символов в нём путём обхода EAT для поиска указателей на функции с использованием какого-либо алгоритма хеширования строк, что в совокупности значительно увеличило бы размер полезной нагрузки.
Возможно, я когда-нибудь решу это реализовать или просто напишу на C и заспамлю вывод компилятора :)
Спасибо Дмитрию Олексюку(@d_olex) и Полу Л.(@am0nsec) за указание на ошибку(и) и предложение исправления.