TryHackMe - Enterprise Walkthrough

TryHackMe - Enterprise Walkthrough
Photo by Tyler Lagalo / Unsplash

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 Usersgroup 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.

Kyle Gray

Kyle Gray

Hey there 👋 Certs - ITILv3, eJPT, PNPT, CRTP, CRTE, PJPT, CRTO