TryHackMe - Enterprise Walkthrough
cat /etc/intro
Today, we're going to cover Enterprise on TryHackMe. This room is rated as Hard and is free which means non-subscribers can try their hand at this box.
Enterprise was a great machine to go through as the path to SYSTEM was pretty clear. What I enjoyed was the little bit of OSINT that was required to get the foothold in the domain.
To start, we found an Atlassian page that suggested the company moved to GitHub. From the organization's GitHub, there was a staff member who pushed a commit with their credentials contained in a script. From there, the discovered credentials were used in a Kerberoasting attack to get cleartext credentials for a service account that had RDP access. Using an RDP session, there was a service we could modify to execute a Nishang shell to get a reverse shell running as SYSTEM.
Without further ado - let's jump in!
Enumeration
Initial nmap Scan
As always, we kick off our assessment with an nmap scan. We do so with a pretty basic scan which includes default scripts and service versions.
Looking over our results, there are some that stick out and should be enumerated a bit further. We will highlight those ports below.
# Nmap 7.80 scan initiated Mon Oct 10 22:45:49 2022 as: nmap -T4 -p- -sC -sV -oA scans/enterprise.initial -vvv 10.10.27.176
Nmap scan report for 10.10.27.176
Host is up, received syn-ack (0.21s latency).
Scanned at 2022-10-10 22:45:50 EDT for 892s
Not shown: 65505 closed ports
Reason: 65505 conn-refused
PORT STATE SERVICE REASON VERSION
53/tcp open domain? syn-ack
| fingerprint-strings:
| DNSVersionBindReqTCP:
| version
|_ bind
80/tcp open http syn-ack Microsoft IIS httpd 10.0
| http-methods:
| Supported Methods: OPTIONS TRACE GET HEAD POST
|_ Potentially risky methods: TRACE
|_http-server-header: Microsoft-IIS/10.0
|_http-title: Site doesn't have a title (text/html).
88/tcp open kerberos-sec syn-ack Microsoft Windows Kerberos (server time: 2022-10-11 02:55:59Z)
135/tcp open msrpc syn-ack Microsoft Windows RPC
139/tcp open netbios-ssn syn-ack Microsoft Windows netbios-ssn
389/tcp open ldap syn-ack Microsoft Windows Active Directory LDAP (Domain: ENTERPRISE.THM0., Site: Default-First-Site-Name)
445/tcp open microsoft-ds? syn-ack
464/tcp open kpasswd5? syn-ack
593/tcp open ncacn_http syn-ack Microsoft Windows RPC over HTTP 1.0
636/tcp open tcpwrapped syn-ack
3268/tcp open ldap syn-ack Microsoft Windows Active Directory LDAP (Domain: ENTERPRISE.THM0., Site: Default-First-Site-Name)
3269/tcp open tcpwrapped syn-ack
3389/tcp open ms-wbt-server syn-ack Microsoft Terminal Services
| rdp-ntlm-info:
| Target_Name: LAB-ENTERPRISE
| NetBIOS_Domain_Name: LAB-ENTERPRISE
| NetBIOS_Computer_Name: LAB-DC
| DNS_Domain_Name: LAB.ENTERPRISE.THM
| DNS_Computer_Name: LAB-DC.LAB.ENTERPRISE.THM
| DNS_Tree_Name: ENTERPRISE.THM
| Product_Version: 10.0.17763
|_ System_Time: 2022-10-11T02:58:25+00:00
| ssl-cert: Subject: commonName=LAB-DC.LAB.ENTERPRISE.THM
| Issuer: commonName=LAB-DC.LAB.ENTERPRISE.THM
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2022-10-10T02:37:10
| Not valid after: 2023-04-11T02:37:10
| MD5: bfd6 483e 3756 8c3a 0ac1 0f8b 91eb 1138
| SHA-1: 79ff 8792 db4e 3fd0 8f9c 678c 9868 b7c7 c69e a29f
| -----BEGIN CERTIFICATE-----
| MIIC9jCCAd6gAwIBAgIQI3PufLaSDqhKkqsJfjTTWDANBgkqhkiG9w0BAQsFADAk
| MSIwIAYDVQQDExlMQUItREMuTEFCLkVOVEVSUFJJU0UuVEhNMB4XDTIyMTAxMDAy
| MzcxMFoXDTIzMDQxMTAyMzcxMFowJDEiMCAGA1UEAxMZTEFCLURDLkxBQi5FTlRF
| UlBSSVNFLlRITTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJvQek2p
| 6gzRWIzSvxuD9sdrZaGg+HjRD7FxTqEWN4+odx+M8FpSesPrtRL4NcKktT8QJSCy
| lJZ4zh7mO2iZUQmVe8EeFLRvj8NzpAEKps3zghPLyLAUsGqcJduJK5JnXTJgbDGV
| akFaYXYqk30BPgSYqoibsE/8iD52EiRb0kmmFiLujjwe4Z+ZmUqJSrrqEv4t6iEM
| k8W+CvS6wbu2llAsXrAd/M1pxchCNAD4xx5+147uK7dF2NvXjmF7YBW4g+I09wJH
| yFLdboABOKyK8LexIVIh3BD6oPFMGzKp4bDZ61OIJgFEkSbkBPw2H3EdTUCaj2Pp
| 2PiGbaCrDJcg6AkCAwEAAaMkMCIwEwYDVR0lBAwwCgYIKwYBBQUHAwEwCwYDVR0P
| BAQDAgQwMA0GCSqGSIb3DQEBCwUAA4IBAQAvzSiOfiv6NqGCNaFjQYCnpiJLcTcX
| Px18nJBvgFKy6IYiCTyq8lwTaFE/LMAAl8UwI+5RsgdXnbsVnaioXm1VFrsNZ++c
| i1pD3oXL8PJk98+hSe7lDESwujG9J3MkkVG6UQQIEmC4EP/c6Cmqbw4YFhwItv++
| XaC3oyRQPHG0hI0DPkJ9hbv7PMJ41OYSFo8uCiyQ/5+kLGcZdtuhOAd2pZErvs8Q
| 7uJfF0eQKeK+1MnJkxk0RnApq5dUTZm17wsxpkZkylJhzD3hT1Ok9TgKl1+eXiPX
| lcJn8UtX6/deoZ848A2WF2OHjJ6hHDI2llxWdB0JJomNrgC/ZLtf2DcK
|_-----END CERTIFICATE-----
|_ssl-date: 2022-10-11T02:58:41+00:00; +1s from scanner time.
5357/tcp open http syn-ack Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Service Unavailable
5985/tcp open http syn-ack Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
7990/tcp open http syn-ack Microsoft IIS httpd 10.0
| http-methods:
| Supported Methods: OPTIONS TRACE GET HEAD POST
|_ Potentially risky methods: TRACE
|_http-server-header: Microsoft-IIS/10.0
|_http-title: Log in to continue - Log in with Atlassian account
8473/tcp filtered vp2p no-response
9389/tcp open mc-nmf syn-ack .NET Message Framing
47001/tcp open http syn-ack Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
49664/tcp open msrpc syn-ack Microsoft Windows RPC
49665/tcp open msrpc syn-ack Microsoft Windows RPC
49666/tcp open msrpc syn-ack Microsoft Windows RPC
49668/tcp open msrpc syn-ack Microsoft Windows RPC
49670/tcp open ncacn_http syn-ack Microsoft Windows RPC over HTTP 1.0
49671/tcp open msrpc syn-ack Microsoft Windows RPC
49672/tcp open msrpc syn-ack Microsoft Windows RPC
49676/tcp open msrpc syn-ack Microsoft Windows RPC
49703/tcp open msrpc syn-ack Microsoft Windows RPC
49713/tcp open msrpc syn-ack Microsoft Windows RPC
49833/tcp open msrpc syn-ack Microsoft Windows RPC
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port53-TCP:V=7.80%I=7%D=10/10%Time=6344DB43%P=x86_64-pc-linux-gnu%r(DNS
SF:VersionBindReqTCP,20,"\0\x1e\0\x06\x81\x04\0\x01\0\0\0\0\0\0\x07version
SF:\x04bind\0\0\x10\0\x03");
Service Info: Host: LAB-DC; OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
|_clock-skew: mean: 0s, deviation: 0s, median: 0s
| p2p-conficker:
| Checking for Conficker.C or higher...
| Check 1 (port 34470/tcp): CLEAN (Couldn't connect)
| Check 2 (port 50382/tcp): CLEAN (Couldn't connect)
| Check 3 (port 21984/udp): CLEAN (Failed to receive data)
| Check 4 (port 60775/udp): CLEAN (Timeout)
|_ 0/4 checks are positive: Host is CLEAN or ports are blocked
| smb2-security-mode:
| 2.02:
|_ Message signing enabled and required
| smb2-time:
| date: 2022-10-11T02:58:29
|_ start_date: N/A
HTTP - Port 80
Port 80 didn't get us anywhere other than a "keep out" notice. I threw ffuf
at it for some basic directory brute-forcing but didn't get anywhere - oh well.
SMB - Ports 139 & 445
With SMB running, we can use smbclient
to enumerate any shares. When connecting via anonymous, two shares stick out -
The Docs
share contains a few office documents that are encrypted and with no viable way to get access, we can skip them for the time being.
As for the Users
share, while we can enumerate potential users - we don't get anywhere as we either get permission-denied errors for users like atlbitbucket
and bitbucket
or if we can list contents, they're empty.
RDP - Port 3389
Yeah - no. We don't even have credentials yet - trying to get into RDP should be a last resort. There has to be something...
HTTP - Port 7990
What's this? An HTTP service running on port 7990? Strange - let's check it out.
Oh nice - it's an Atlassian login page...with an interesting comment.
This is a pretty large hint on where we need to focus for the next steps - Github! GitHub repositories can sometimes store all kinds of useful information such as credentials, API keys, and other juicy information. Let's check it out!
Doing some basic OSINT, we find the Enterprise.THM GitHub profile.
Looking over the profile, we find a member of the organization - Nik-enterprise-dev
Nik has one repository and it's a Powershell script. Looking over the current commit, there isn't anything special. It's just a basic script that runs Get-ADComputer against a list of computers on the domain.
But if we look closer, this script has two interesting variables - userName
and userPassword
. What are the chances Nik inadvertently pushed a commit with these variables set?
That's exactly what happened. If we look at the commit history for this repo, there were two; the current one and the initial one.
We already know the current one isn't anything special - but what's in the original commit and why did he feel the need to update things?
The reason he needed to update things is that his first commit contained his credentials. He saw that and quickly pushed a new commit with these removed.
If we check these credentials using CrackMapExec
, we find they are valid credentials! Neat - we'll store these away for the time being.
Let's Get Roasting
Before we do anything - we need to modify our hosts file to include the lab.enterprise.thm
domain so DNS resolutions work as expected.
We already have Nik's credentials so let's use them for some user enumeration. We can use GetADUsers
from the Impacket library to do just this - there are a few who have logged in.
We have a few accounts to narrow our enumeration on.
I also ran ldapdomaindump
using Nik's credentials and found bitbucket
is a member of the Remote Desktop Users
group which permits the user to RDP to LAB-DC
.
Other than listing user accounts, what else could we do with Nik's credentials? Well, we could check to see if there are any service accounts in the domain. If there are accounts with a service principle name set, we could Kerberoast them and attempt to crack their hash offline.
We can again utilize Impacket for this by using GetUserSPN
to list any service accounts. There is one - bitbucket
Why this works.
Any authenticated user can request a TGS for any service in a Kerberos environment. While TGT's are signed by a special account called KRBTGT, TGS's are signed with the hash of the requested service account. Why is this done?
The KDC and service account has one thing in common - the service account password. After the KDC gives us a TGT, it will then send us a TGS, which has been signed with the password hash of the service account. If we can get that TGS, we could take it offline and attempt to crack it to recover the password. This can be pretty lucrative because service accounts always have strong passwords and are never over-permissive - right?? Never.
With the help of hashcat
, that's exactly what we did! Hashcat was able to churn through rockyou.txt
with ease and we got the password for bitbucket
.
Remoting Our Way In & Getting User Flag
Since we know bitbucket
can RDP to LAB-DC
, and we have the password, we use Remmina to RDP -
bitbucket to SYSTEM
To assist with privilege escalation, I first load PowerUp
via Invoke-WebRequest
since I am hosting it with Updog.
Just a quick side note - I love Updog. Not only does it do the usual file hosting like python3 -m http.server
, but it also has an upload function that allows file uploads from a victim back to the server hosting Updog. It's great - I suggest checking it out.
Look, I know using IEX
is terrible opsec and will get me popped on an engagement but this is a CTF and doing it this way is a good way to load PowerUp
in memory.
With PowerUp
in memory and after running Invoke-AllChecks
, we find several possible privilege escalation vectors via zerotieroneservice
We can modify the service binary for zerotieroneservice
which PowerUp
so graciously offers an abuse function for us. Thanks, PowerUp! This could also have been done manually, but work smarter, not harder.
Privilege Escalation Breakdown
So what's going on here and why can we do what we're about to do? So services have a binary path - it points to the executable that's going to be run when the service is started. In our case, that's ZeroTier One.exe
.
Our current user (bitbucket) has permission to modify the path and the executable itself because we have "write" privileges over the location of the executable. This can be validated using icacls
. The permissions are inherited (I) and write access (W).
Once we run the below PowerUp
abuse function, the original ZeroTier One.exe
was overwritten with the original being backed up.
Okay - back to abusing the service with PowerUp.
Using the abuse function provided by PowerUp
, I load a Nishang
shell into memory and then call the Invoke-PowerShellTcp
function to get a reverse shell on our listener.
Before we start the service, we need to use Updog to host Invoke-PowerShellTcp.ps1
and netcat
to listen on port 443.
Once done - we start the service to get a reverse shell running as SYSTEM
And that's that - we have fully compromised the Enterprise DC. I really enjoyed this room as it offered something a little different when it came to OSINT in order to find Nik's Github.