
Un analyseur de bytecode pour trouver des chaînes de gadgets de désérialisation dans les applications Java.
Ce projet inspecte les bibliothèques Java et les classpaths à la recherche de chaînes de gadgets. Les chaînes de gadgets sont utilisées pour construire des exploits pour les vulnérabilités de désérialisation. En découvrant automatiquement les chaînes de gadgets possibles dans le classpath d'une application, les testeurs d'intrusion peuvent rapidement construire des exploits et les ingénieurs en sécurité des applications peuvent évaluer l'impact d'une vulnérabilité de désérialisation et prioriser sa correction.
Ce projet a été présenté au Black Hat USA 2018. Apprenez-en plus là-bas ! (Liens à venir)
AVERTISSEMENT : Ce projet est au stade alpha au mieux. Il nécessite l'ajout de tests et de documentation. N'hésitez pas à contribuer en ajoutant l'un ou l'autre !
En supposant que vous ayez un JDK installé sur votre système, vous devriez pouvoir simplement exécuter ./gradlew shadowJar. Vous pouvez ensuite lancer l'application avec java -jar build/libs/gadget-inspector-all.jar <arguments>.
Cette application attend comme argument(s) soit le chemin vers un fichier war (auquel cas le war sera décompressé et toutes ses classes et bibliothèques utilisées comme classpath), soit un nombre quelconque de jars.
Notez que l'analyse peut être gourmande en mémoire (et jusqu'à présent, gadget inspector n'a pas du tout été optimisé pour être moins gourmand en mémoire). Pour les petites bibliothèques, vous voudrez probablement allouer au moins 2 Go de mémoire de tas (c'est-à-dire avec l'option -Xmx2G). Pour les applications plus grandes, vous voudrez utiliser autant de mémoire que possible.
La boîte à outils passera par plusieurs étapes d'inspection du classpath pour construire des ensembles de données destinés aux étapes ultérieures. Ces ensembles de données sont écrits dans des fichiers avec une extension .dat et peuvent être supprimés après votre exécution (ils sont écrits principalement pour que les premières étapes puissent être ignorées pendant le développement).
Une fois l'analyse terminée, le fichier gadget-chains.txt sera écrit.
Voici un exemple d'exécution contre commons-collections-3.2.1.jar, par exemple avec
wget http://central.maven.org/maven2/commons-collections/commons-collections/3.2.1/commons-collections-3.2.1.jar
java -Xmx2G -jar build/libs/gadget-inspector-all.jar commons-collections-3.2.1.jar
Dans gadget-chains.txt se trouve la chaîne suivante :
com/sun/corba/se/spi/orbutil/proxy/CompositeInvocationHandlerImpl.invoke(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object; (-1)
com/sun/corba/se/spi/orbutil/proxy/CompositeInvocationHandlerImpl.invoke(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object; (0)
org/apache/commons/collections/map/DefaultedMap.get(Ljava/lang/Object;)Ljava/lang/Object; (0)
org/apache/commons/collections/functors/InvokerTransformer.transform(Ljava/lang/Object;)Ljava/lang/Object; (0)
java/lang/reflect/Method.invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object; (0)
Le point d'entrée de cette chaîne est une implémentation de la classe InvocationHandler du JDK. En utilisant la même astuce que dans la chaîne de gadgets originale de commons-collections, toute implémentation sérialisable de cette classe est atteignable dans une chaîne de gadgets, donc la chaîne découverte commence ici. Cette méthode invoque classToInvocationHandler.get(). La chaîne de gadgets découverte indique que classToInvocationHandler peut être sérialisé en tant que DefaultedMap de sorte que cette invocation saute vers DefaultedMap.get(). L'étape suivante de la chaîne invoque value.transform() à partir de cette méthode. Le paramètre value de cette classe peut être sérialisé en tant que InvokerTransformer. À l'intérieur de la méthode transform de cette classe, on voit que l'on appelle cls.getMethodName(iMethodName, ...).invoke(...). Gadget inspector a déterminé que iMethodName est contrôlable par l'attaquant en tant que membre sérialisé, et donc un attaquant peut exécuter une méthode arbitraire sur la classe.
Cette chaîne de gadgets est la brique de base de la chaîne de gadgets complète de commons-collections découverte par Frohoff. Dans le cas ci-dessus, gadget inspector a découvert l'entrée via CompositeInvocationHandlerImpl et DefaultedMap au lieu de AnnotationInvocationHandler et LazyMap, mais c'est en grande partie la même chose.
Si vous cherchez d'autres exemples du type de chaînes que cet outil peut trouver, les bibliothèques suivantes donnent également des résultats intéressants :
N'oubliez pas que vous pouvez également pointer gadget inspector vers une application complète (empaquetée en JAR ou WAR). Par exemple, en analysant le war de l'application Zksample2, nous obtenons la chaîne de gadgets suivante :
net/sf/jasperreports/charts/design/JRDesignPieDataset.readObject(Ljava/io/ObjectInputStream;)V (1)
org/apache/commons/collections/FastArrayList.add(Ljava/lang/Object;)Z (0)
java/util/ArrayList.clone()Ljava/lang/Object; (0)
org/jfree/data/KeyToGroupMap.clone()Ljava/lang/Object; (0)
org/jfree/data/KeyToGroupMap.clone(Ljava/lang/Object;)Ljava/lang/Object; (0)
java/lang/reflect/Method.invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object; (0)
Comme vous pouvez le voir, cela utilise plusieurs bibliothèques différentes contenues dans l'application pour construire la chaîne.
Q : Si gadget inspector trouve une chaîne de gadgets, peut-on construire un exploit à partir de celle-ci ?
R : Pas toujours. L'analyse utilise certaines hypothèses simplificatrices et peut signaler des faux positifs (chaînes de gadgets qui n'existent pas réellement). Pour un exemple simple, elle n'essaie pas de résoudre la satisfiabilité des conditions de branche. Ainsi, elle signalera le code suivant comme une chaîne de gadgets :
public class MySerializableClass implements Serializable {
public void readObject(ObjectInputStream ois) {
if (false) System.exit(0);
ois.defaultReadObject();
}
}
De plus, gadget inspector a des conditions assez larges sur les fonctions qu'il considère comme intéressantes. Par exemple, il traite la réflexion comme intéressante (c'est-à-dire les appels à Method.invoke() où un attaquant peut contrôler la méthode), mais souvent des assertions négligées signifient qu'un attaquant peut influencer la méthode invoquée mais n'a pas un contrôle total. Par exemple, un attaquant peut être capable d'invoquer la méthode "getError()" dans n'importe quelle classe, mais pas n'importe quel autre nom de méthode.
Q : Si aucune chaîne de gadgets n'est trouvée, cela signifie-t-il que mon application est à l'abri d'une exploitation ?
R : Non ! Tout d'abord, gadget inspector dispose d'un ensemble très restreint de fonctions "de terminaison" qu'il considère comme ayant des effets secondaires "intéressants". Cela ne signifie certainement pas qu'il n'y a pas d'autres comportements intéressants ou dangereux qui ne figurent pas dans la liste.
De plus, il existe un certain nombre de limitations de l'analyse statique qui feront que gadget inspector aura toujours des angles morts. Par exemple, gadget inspector manquerait actuellement ceci car il ne suit pas les appels de réflexion.
public class MySerializableClass implements Serializable {
public void readObject(ObjectInputStream ois) {
System.class.getMethod("exit", int.class).invoke(null, 0);
}
}