Jump Ahead: Enum – User – Root – Resources
TL;DR;
To solve this machine, we begin by enumerating all ports. The ports returned are consistent with an Active Directory server, so we are likely dealing with an active directory domain. From the webserver on port 80
, we find a downloadable file that appears to be named according to a template. Fuzzing for more files using this template, we find several additional files. Enumerating the metadata, we get a list of potential usernames. Additionally, we go through the files, and find some useful information in a couple of them – including a default password. Using the password against the list of usernames, we are able to find credentials for the Tiffany.Molina
user. With tiffany’s credentials, we are able to log into SMB, and get user.txt
. From the files we previously downloaded, it mentioned a script, which we find, and learn it searches DNS records for entries that start with “web”, and attempts to connect to them. Using LDAP, we are able to add our own DNS record to attempt to get the machine to connect to us. After the machine attempts to connect to us as the ted.graves
user, we get his NTLM hash, which we are able to crack. From further enumeration, we find the svc_int
service account has constrained delegation enabled, which allows us to get a service ticket impersonating the administrator
user. Using psexec
, we are able to get a shell on the machine as NT Authority\SYSTEM
– allowing us to read root.txt
.
Enumeration
Like all machines, we begin by enumerating open ports – finding ports 53
, 80
, 88
,135
, 139
, 389
, 445
, 464
, 593
, 636
, 3268
, 3269
, 5985
, 9389
, 49667
, 49677
, 49678
, 49696
, and 49700
open.
$ sudo nmap -v -p- --min-rate 3000 $RHOST
[...]
$ sudo nmap -sV -A -oA enum/nmap/tcp-scripts -p 53,80,88,135,139,389,445,464,593,636,3268,3269,5985,9389,49667,49677,49678,49696,49700 $RHOST
# Nmap 7.91 scan initiated Sat Jul 3 20:01:40 2021 as: nmap -sV -A -oA enum/nmap/tcp-scripts -p 53,80,88,135,139,389,445,464,593,636,3268,3269,5985,9389,49667,49677,49678,49696,49700 10.129.178.146
Nmap scan report for 10.129.178.146
Host is up (0.048s latency).
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
80/tcp open http Microsoft IIS httpd 10.0
| http-methods:
|_ Potentially risky methods: TRACE
|_http-server-header: Microsoft-IIS/10.0
|_http-title: Intelligence
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2021-07-04 08:01:53Z)
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:<unsupported>, DNS:dc.intelligence.htb
| Not valid before: 2021-04-19T00:43:16
|_Not valid after: 2022-04-19T00:43:16
|_ssl-date: 2021-07-04T08:03:33+00:00; +7h00m00s 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-cert: Subject: commonName=dc.intelligence.htb
| Subject Alternative Name: othername:<unsupported>, DNS:dc.intelligence.htb
| Not valid before: 2021-04-19T00:43:16
|_Not valid after: 2022-04-19T00:43:16
|_ssl-date: 2021-07-04T08:03:34+00:00; +7h00m00s from scanner time.
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:<unsupported>, DNS:dc.intelligence.htb
| Not valid before: 2021-04-19T00:43:16
|_Not valid after: 2022-04-19T00:43:16
|_ssl-date: 2021-07-04T08:03:33+00:00; +7h00m00s 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:<unsupported>, DNS:dc.intelligence.htb
| Not valid before: 2021-04-19T00:43:16
|_Not valid after: 2022-04-19T00:43:16
|_ssl-date: 2021-07-04T08:03:34+00:00; +7h00m00s 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
49677/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
49678/tcp open msrpc Microsoft Windows RPC
49696/tcp open msrpc Microsoft Windows RPC
49700/tcp open msrpc Microsoft Windows RPC
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
OS fingerprint not ideal because: Missing a closed TCP port so results incomplete
No OS matches for host
Network Distance: 2 hops
Service Info: Host: DC; OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
|_clock-skew: mean: 6h59m59s, deviation: 0s, median: 6h59m59s
| smb2-security-mode:
| 2.02:
|_ Message signing enabled and required
| smb2-time:
| date: 2021-07-04T08:02:54
|_ start_date: N/A
TRACEROUTE (using port 139/tcp)
HOP RTT ADDRESS
1 48.48 ms 10.10.14.1
2 48.54 ms 10.129.178.146
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Sat Jul 3 20:03:36 2021 -- 1 IP address (1 host up) scanned in 116.31 seconds
From the list of ports, we can tell the machine is likely an Active Directory domain controller. Looking at the outputs of the nmap
scripts, we see LDAP reveals the FQDNs intelligence.htb
, and dc.intelligence.htb
. For now, we save those to our /etc/hosts
file. Enumerating port 80
with gobuster
and nikto
does not return many results that we can use to our advantage. RPC (port 135) allows anonymous authentication, however, we do not find anything of particular interest. Checking SMB for anonymous and guest access also appears to be disabled. Lastly, we use ldapsearch
to attempt to enumerate LDAP, however, we also do not get many results.
Getting User
Going to the webserver, we see a pretty simple webpage that has the machine name on it, and a lot of Lorem Ipsum text.
Looking around the page, we find a couple links for documents that we can download.
After clicking one of the links, we are presented a PDF file located in the documents/
directory. The text on the document is also Lorem Ipsum, so there is not much value in it. Opening the other document, we are given a similar PDF. One thing that we notice is that file names follow a template that includes a date in the format of “yyyy-mm-dd-upload.pdf”.
To test out this theory, we need to generate a file containing the months in two digit format, as well as a file for the days also in two digit format. Next, we use a tool like wfuzz
to try to bruteforce other files.
wfuzz
to find potential filesFrom the results, we see there are other valid files in the directory. As they may potentially contain sensitive information, we use bash
and wget
to enumerate and download all files it discovers. Additionally, we expand the year to be “2020” in case the webserver contains files from that year as well. After doing this, we have a lot of PDF files that were downloaded.
wget
to download hidden filesBefore we start looking at the content of the files, use use a tool like exiftool
to check the files for valuable metadata. After running the tool, we see a field named “Creator” that contains potential usernames. We extract these usernames, and save them to a file.
Since we have potential usernames, we use Impacket’s GetNPUsers.py
to try to check if any do not require Pre-Authentication to get a Kerberos Ticket-Granting Ticket (try to crack their password). Unfortunately, they all appear to have Kerberos Pre-Authentication enabled. Next, we attempt to read the PDFs, however, they appear to only contain Lorem Ipsum. Unfortunately, we do not know of another path forward, so we will continue reading all the files, until we have opened them all. Eventually, we find 2 valid files that contain useful information. “2020-12-30-upload.pdf” mentions that service accounts are not locked down, and that there is a script to check web services for outages. “2020-06-04-upload.pdf” contains the default password for newly created accounts.
Since we now have a potential password, we can use crackmapexec
to try to bruteforce account credentials. Doing so, we find tiffany.molina
has not changed their password, so we now have a valid set of credentials.
crackmapexec
to check for valid credentialsTrying the credentials to get a shell via WinRM is unsuccessful, so we move to SMB. Using Impacket’s smbclient.py
, we are able to enumerate shares, and find “C:\Users” is exported as a shared. From here, we are able to find user.txt
from Tiffany’s desktop.
Tiffany
, and finding user.txt
on her DesktopGetting Root
Looking at the “IT” share, we find a PowerShell script. Looking at it, it appears the script queries the Active Directory DNS for services whose names start with “web”, and tries to connect to them. If the connection fails, it emails Ted to notify him. From this, we assume it to be the script Ted created to check services for downtime.
Ted
‘s service check script, and reading itUsing the script’s DNS query, we replicate the same query on our machine using ldapsearch
. From the results, we see there is one web service named “web1”.
One thing we note when looking at the script, is that ted’s credentials are also sent when the script attempts to connect to the web service. If we are able to add our own DNS record, we should be able to get Ted’s NTLM hash. Since we only have access to LDAP, we will need to research if it is possible to add DNS records via LDAP. For this, we google “active directory ldap add dns records github”, and find this tool. Using the tool, we are able to add a DNS record that points to our machine (prefixing it with “web-” so the script will attempt to connect to it). Using ldapsearch
, we are able to verify the DNS record was added.
Setting up a simple listener on port 80, we verify the script does attempt to connect to our machine.
Next, to force the script to attempt to authenticate to our webserver (in order to get the NTLM hash), we can use responder
. As responder
can have some adverse effects if ran incorrect, we use the “-A” option to disable the automatic poisoning. For added safety, we also disable all the servers except the HTTP server. After we have it setup, we start responder
, and eventually get a connection with Ted
‘s credentials.
Ted
‘s NTLMv2 hashUsing hashcat
, are able to crack the hash to get Ted’s password.
Ted
‘s NTLMv2 hashSince we now have Ted’s password, we attempt to use it with SMB, however, we do not get any additional information than we had from using Tiffany’s account. Next, we use bloodhound-python
to enumerate the domain.
bloodhound-python
to enumerate Active DirectoryOnce we ran the python script, we can run bloodhound
to get the graphical interface to open. Once open, we drag the files into the interface to import the results. Once the results are imported, we start clicking the preset queries to find something that stands out. When we run the “Shortest Paths to Unconstrained Delegation Systems” query, we see ted.graves
is a member member of the “itsupport” group, which can read the Group Managed Service Account (GMSA) password for the svc_int
account.
Bloodhound
If we get access to this account, we will be able to delegate to the WWW
service on the domain controller, and impersonate another user.
Bloodhound
showing svc_int
can delegate to the domain serverIn order to get the GMSA password, we Google “gmsa password python”, and find this repo. We note the repo is owned by the machine creator, so we are likely on the right path. Using the script, we are able to get the NTLM hash for the svc_int
account.
svc_int
accountNow that we have credentials for the svc_int
account, we attempt to get a service ticket to impersonate the administrator
user, however, we are unable to because our clock skew is too great.
getST.py
To fix this, we can pull the server’s local time from the “Date” HTTP header, and use the timedatectl
command to set our local time to match it.
Once we have adjusted our time to match the domain controller’s, we are able to use Impacket’s getST.py
to get a Service Ticket as the administrator
user.
administrator
Now that we have an impersonated service ticket as administrator
to the dc.intelligence.htb
machine, we can attempt to get a local shell using Impacket’s psexec.py
. We get a shell as NT Authority\SYSTEM
, and can now read root.txt
from adminsitrator
‘s desktop.
administrator
, and reading user.txt
Thank you for taking the time to read my write-up. I am interested in other ways this machine has been solved. Feel free to reach out to me and we can discuss it. Thanks!