Windows x64 内核模式手工制作的 shellcode,用于将正在执行的进程的主访问令牌替换为 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 下载可直接部署的位置无关 shellcode。
如果你不确定其工作原理,请不要尝试在你依赖其完成工作的机器上部署该 payload。
有关更多信息,请参阅 微软文档。
出于测试目的,我非常推荐使用 flare-kscldr 在测试 VM 上部署内核模式 shellcode,并使用 CodeMachine System setup for kernel development and debugging guide 设置一台具有完整内核调试支持的 Hyper-V Guest VM。
或者,你也可以考虑使用 kdbg-driver-vagrant 自动化该过程,并借助 Vagrant 快速启动一台支持完整内核调试的测试 VM。

正如 Dmytro Oleksiuk(@d_olex)向我指出的那样,代码中存在一些相当明显的竞争条件,具体涉及:
nt!_EPROCESS 结构,而未使用任何同步原语/锁定机制这些对象目前缺乏任何保护措施,无法防止在我们的处理过程中它们被修改。
这是一个问题吗?是的,竞争条件总是有问题的,可能导致各种未定义行为/错误检查(bugcheck)等令人不快的麻烦。
使用此 payload 会影响我的漏洞利用的稳定性吗?可能会。
那么,如何修复呢?修复分两步进行。
第 1 步涉及获取等待类型锁(如 Pushlocks)——nt!PspActiveProcessLock(pushlock 指针),以使用 nt!ExAcquirePushLockExclusive 进行独占访问,然后再遍历进程列表(在遍历之前需要禁用正常的内核 APC 投递);在使用完列表后,使用 nt!ExReleasePushLockExclusive 释放锁,此时应重新启用正常的内核 APC 投递。
然而,由于该全局变量不是由 nt 内核导出的,因此更好、更安全的方法是使用 nt!ZwQuerySystemInformation API,并指定 SYSTEM_INFORMATION_CLASS == SystemProcessInformation,从 ImageName 中找到 PID,再使用 nt!PsLookupProcessByProcessId 从 PID 获取 nt!_EPROCESS VA。
不过,如果你好奇内核是如何实现前一种方法的,我建议你在反汇编器中查看 nt!PsGetNextProcess。
第 2 步涉及使用 nt!ObReferenceObject 系列 APIs 安全地引用对象,以增加进程对象的引用计数,使其在我们处理完并通过 nt!ObDereferenceObject 显式递减之前不会被删除。
请注意,手动增加引用计数是多余的,因为调用 nt!PsLookupProcessByProcessId 如果成功,就会自动为我们完成这项工作。
然而,实施这些修复将需要找到 ntoskrnl.exe 的基地址,并通过遍历 EAT、使用某种字符串哈希算法解析其中的符号来找到函数指针,这些都会显著增加 payload 的体积。
我或许会决定在将来的某一天实现它,或者干脆用 C 编写,然后刷屏编译器输出 :)
感谢 Dmytro Oleksiuk(@d_olex)和 Paul L.(@am0nsec)指出错误并提出了修复建议。