【安全】从mimikatz学习Windows安全之访问控制模型

前言

上次的文章分析了mimikatz的token模块,并简单介绍了windows访问控制模型的概念。在本篇文章中,主要介绍sid相关的概念,并介绍mimikatz的sid模块,着重分析sid::patch功能的原理。

SID简介

1. 安全标识符(SID)

在Windows操作系统中,系统使用安全标识符来唯一标识系统中执行各种动作的实体,每个用户有SID,计算机、用户组和服务同样也有SID,并且这些SID互不相同,这样才能保证所标识实体的唯一性

SID一般由以下组成:

“S”表示SID,SID始终以S开头

“1”表示版本,该值始终为1

“5”表示Windows安全权威机构

“21-1463437245-1224812800-863842198”是子机构值,通常用来表示并区分域

“1128”为相对标识符(RID),如域管理员组的RID为512

Windows也定义了一些内置的本地SID和域SID来表示一些常见的组或身份。
【安全】从mimikatz学习Windows安全之访问控制模型
2. AD域中的SID

在AD域中,SID同样用来唯一标识一个对象,在LDAP中对应的属性名称为objectSid:
【安全】从mimikatz学习Windows安全之访问控制模型
重点需要了解的是LDAP上的sIDHistory属性。

(1) SIDHistory

SIDHistory是一个为支持域迁移方案而设置的属性,当一个对象从一个域迁移到另一个域时,会在新域创建一个新的SID作为该对象的objectSid,在之前域中的SID会添加到该对象的sIDHistory属性中,此时该对象将保留在原来域的SID对应的访问权限。

比如此时域A有一个用户User1,其LDAP上的属性如下:
【安全】从mimikatz学习Windows安全之访问控制模型
此时我们将用户User1从域A迁移到域B,那么他的LDAP属性将变为:
【安全】从mimikatz学习Windows安全之访问控制模型
此时当User1访问域A中的资源时,系统会将目标资源的DACL与User1的sIDHistory进行匹配,也就是说User1仍具有原SID在域A的访问权限。

值得注意的是,该属性不仅在两个域之间起作用,它同样也可以用于单个域中,比如实战中我们将一个用户A的sIDHistory属性设置为域管的objectSid,那么该用户就具有域管的权限。

另一个实战中常用的利用,是在金票中添加Enterprise Admins组的SID作为sIDHistory,从而实现同一域林下的跨域操作,这个将在后面关于金票的文章中阐述。

(2) SID Filtering

SID Filtering简单的说就是跨林访问时目标域返回给你的服务票据中,会过滤掉非目标林中的SID,即使你添加了sIDHistory属性。SID Filtering林信任中默认开启,在单林中默认关闭
【安全】从mimikatz学习Windows安全之访问控制模型

mimikatz的sid模块

1. sid::lookup

该功能实现SID与对象名之间的相互转换,有三个参数:

/name:指定对象名,将其转换为SID

/sid:指定SID,将其转换为对象名

/system:指定查询的目标计算机
【安全】从mimikatz学习Windows安全之访问控制模型
其原理是调用LookupAccountName()和LookupAccountSid()来实现对象名和SID之间的相互转化,这类API底层是调用MS-LSAT协议(RPC),比如将对象名转换为SID,底层调用的是LsarLookupNames4()

【安全】从mimikatz学习Windows安全之访问控制模型
2. sid::query

该功能支持通过SID或对象名来查询对象的【安全】从mimikatz学习Windows安全之访问控制模型
这个功能其原理就是直接使用LDAP查询,通过sAMAccountName查询对应的objectSid,或者通过objectSid查询对应的sAMAccountName

其核心是调用Windows一系列的LDAP操作API,主要是ldap_search_s():
【安全】从mimikatz学习Windows安全之访问控制模型
3. sid::modify

该功能用于修改一个域对象的SID,可以使用的参数有三个:

/sam:通过sAMAccountName指定要修改SID的对象

/sid:通过objectSid指定要修改SID的对象

/new:要修改对象的新SID

使用该功能是需要先使用sid::patch功能对xxxx进行patch(自然也需要先开启debug特权),需要在域控上执行。
【安全】从mimikatz学习Windows安全之访问控制模型
修改时的操作就很简单了,调用LDAP操作的API对域对象的objectSid进行修改,主要使用的是ldap_modify_s():从mimikatz学习Windows安全之访问控制模型(二)

【安全】从mimikatz学习Windows安全之访问控制模型
4. sid::add

该功能用来向一个域对象添加sIDHistoy属性,有两个参数:

/sam:通过sAMAccountName指定要修改的对象

/sid:通过objectSid指定要修改的对象

/new:要修改sIDHistory为哪个对象的SID,该参数可指定目标的sAMAccountName或objectSid,当指定名称时会先调用LookupAccountSid将其转换为SID

使用该功能也要先执行sid::patch,修改时同样是操作LDAP通过ldap_modify_s()修改,不再赘述
【安全】从mimikatz学习Windows安全之访问控制模型
5. sid::clear

该功能用来清空一个对象的sIDHistory属性

/sam:要清空sIDHistory的对象的sAMAccountName

/sid:要清空sIDHistory的对象的objectSid

【安全】从mimikatz学习Windows安全之访问控制模型
原理就是使用ldap_modify_s()将目标对象sIDHistory属性修改为空

6. sid::patch

对域控LDAP修改过程中的验证函数进行patch,需要在域控上执行,该功能没有参数

patch共分为两个步骤,如果仅第一步patch成功的话,那么可以使用sid::add功能,两步都patch成功的话才可以使用sid::modify功能
【安全】从mimikatz学习Windows安全之访问控制模型

sid::patch分析

sid::patch在系统版本 < Vista时,patch的是samss服务中ntdsa.dll的内存,更高版本patch的是ntds服务中ntdsai.dll的内存
【安全】从mimikatz学习Windows安全之访问控制模型
整个patch过程分为两步:

第一步patch的是SampModifyLoopb【安全】从mimikatz学习Windows安全之访问控制模型
我们以Windows Server 2012 R2环境为例来分析,首先我们需要找到NTDS服务所对应的进程,我们打开任务管理器选中NTDS服务,单击右键,选择“转到详细信息”就会跳转到对应进程,这里NTDS服务对应的进程是lsass.exe。
【安全】从mimikatz学习Windows安全之访问控制模型
1. 域控对LDAP请求的处理

大致分析一下域控对本地LDAP修改请求的过滤与处理流程,当我们修改objectSid和sIDHistory时,SampModifyLoopbackCheck()会过滤我们的请求,即使绕过该函数修改objectSid时,仍会受到SysModReservedAtt()的限制

侵入式切换到lsass进程并重新加载用户态符号表:
【安全】从mimikatz学习Windows安全之访问控制模型
给两个检查函数打断点
【安全】从mimikatz学习Windows安全之访问控制模型
此时我们修改一个用户的描述来触发LDAP修改请求
【安全】从mimikatz学习Windows安全之访问控制模型
命中断点后的调用栈如下:
【安全】从mimikatz学习Windows安全之访问控制模型
SampModifyLoopbackCheck()函数中存在大量Check函数,通过动态调试发现修改sIDHistoy的请求经过该函数后便会进入返回错误代码的流程。
【安全】从mimikatz学习Windows安全之访问控制模型
继续调试到下一个断点
【安全】从mimikatz学习Windows安全之访问控制模型
在SysModReservedAtt()执行结束后,正常的修改请求不会在jne处跳转,而当修改objectSid时会在jne处跳转,进入返回错误的流程
【安全】从mimikatz学习Windows安全之访问控制模型
2. Patch 1/2

当我们想要进行内存patch时,通常会寻找目标内存地址附近的一块内存的值作为标记,编写程序时首先在内存中搜索该标记并拿到标记的首地址,然后再根据偏移找到要patch的内存地址,然后再进行相应的修改操作。

mimikatz正是使用这种方法,其在内存中搜索的标记在代码中有明确的体现:

【安全】从mimikatz学习Windows安全之访问控制模型
我们将域控的ntdsai.dll拿回本地分析,在其中搜索标记41 be 01 00 00 00 45 89 34 24 83
【安全】从mimikatz学习Windows安全之访问控制模型
这一部分内容是在函数SampModifyLoopbackCheck()函数的流程中,我们可以使用windbg本地调试对比一下patch前后的函数内容

首先我们找到lsass.exe的基址并切换到该进程上下文:
【安全】从mimikatz学习Windows安全之访问控制模型
使用lm列出模块,可以看到lsass进程中加载了ntdsai.dll,表明此时我们可以访问ntdsai.dll对应的内存了
【安全】从mimikatz学习Windows安全之访问控制模型
我们直接查看SampModifyLoopbackCheck()函数在内存中的反汇编
【安全】从mimikatz学习Windows安全之访问控制模型
为了对比patch前后的区别,我们使用mimikatz执行sid::patch,然后再查看函数的反汇编。如下图所示,箭头所指处原本是74也就是je,而patch后直接改为eb即jmp,使流程直接跳转到0x7ffc403b2660
【安全】从mimikatz学习Windows安全之访问控制模型
而0x7ffc403b2660处的代码之后基本没有条件检查的函数了,恢复堆栈和寄存器后就直接返回了,这样就达到了绕过检查逻辑的目的

  1. Patch 2/2

同理,按照mimikatz代码中的标记搜索第二次patch的位置0f b7 8c 24 b8 00 00 00
【安全】从mimikatz学习Windows安全之访问控制模型
查看ModSetAttsHelperPreProcess()处要patch的内存,patch前如下图所示
【安全】从mimikatz学习Windows安全之访问控制模型
patch完成后内存如下图,其实本质是让SysModReservedAtt()函数失效,在内存中寻找到标记后偏移-6个字节,然后将验证后的跳转逻辑nop掉
【安全】从mimikatz学习Windows安全之访问控制模型
4. 解决patch失败的问题

由于mimikatz中内存搜索的标记覆盖的windows版本不全,所以经常会出现patch失败的问题。例如在我的Windows Server 2016上,第二步patch就会失败,这种情况多半是因为mimikatz中没有该系统版本对应的内存patch标记
【安全】从mimikatz学习Windows安全之访问控制模型
此时我们只需要将目标的ntdsai.dll拿下来找到目标地址
【安全】从mimikatz学习Windows安全之访问控制模型
然后修改为正确的内存标记和对应的偏移地址即可,如果新增的话记得定义好版本号等信息
【安全】从mimikatz学习Windows安全之访问控制模型
此时重新编译后就可以正常patch了
【安全】从mimikatz学习Windows安全之访问控制模型

【安全】从mimikatz学习Windows安全之访问控制模型
此时test1将具有域管权限,我们可以利用这个特性来留后门
【安全】从mimikatz学习Windows安全之访问控制模型
2. 域内“影子账户”

假设我们此时拿到了域控,然后设置一个普通域用户的SID为域管的SID
【安全】从mimikatz学习Windows安全之访问控制模型
此时我们这个用户仍然只是Domain Users组中的普通域成员
【安全】从mimikatz学习Windows安全之访问控制模型
但该用户此时已经具有了域管的权限,例如dc【安全】从mimikatz学习Windows安全之访问控制模型
并且此时也可以用该用户的账号和密码登录域控,登录成功后是administrator的session。但该操作很有可能造成域内一些访问冲突(猜测,未考证),建议在生产环境中慎用

3. 跨域

通常我们拿到一个域林下的一个子域,会通过黄金票据+SIDHistory的方式获取企业管理员权限,控制整个域林

除了这种方法,我们也可以直接修改当前子域对象的sIDHistory属性,假设我们现在拿到一个子域域控,通过信任关系发现存在一个父域,此时我们无法访问父域域控的CIFS
【安全】从mimikatz学习Windows安全之访问控制模型
但我们给子域域管的sIDHistory属性设置为父域域管的SID
【安全】从mimikatz学习Windows安全之访问控制模型
此时就可以访问父域域控的CIFS了:
【安全】从mimikatz学习Windows安全之访问控制模型
【安全】从mimikatz学习Windows安全之访问控制模型
最后

网安资料详细

版权声明:玥玥 发表于 2021-08-20 22:32:17。
转载请注明:【安全】从mimikatz学习Windows安全之访问控制模型 | 女黑客导航