最近在学习反序列化之类漏洞之类的东西,之前也是看别人分析,一直没有实践,这次找到16年的一个漏洞,准备分析调试一下。漏洞环境 https://github.com/zerothoughts/spring-jndi
没搜到编号,反正重点是在于学习这个漏洞。首先先把服务端跑起来,服务端代码很简单,是一个serversocket的,监听9999端口,并且抑制等待客户端socket链接过来。
客户端代码客户端流程如下:
1.客户端代码先监听8088端口,开启一个文件下载服务。其中该地址映射的就是ExportObject.class。 2.将文件地址http://127.0.0.1:8080/ExportObject.class映射到rmi服务上面
3.将ExportObject用JtaTransactionManager封装一下
4.客户端连接服务端9999,然后发送包装后的object
5.服务端接收到object,然后调用readObject 最终会弹出计算器 在分析之前有必要介绍下RMI,Remote Method Invoke 远程方法调用,用于在远端服务器上提供远程对象给客户端?什么意思,就是服务端开启这个服务,然后客户端访问服务端着个接口就可以直接拿到服务器上的对象,它的底层应该就是socket通信,然后传递一个object的。关于它的用法,可以参考这篇博客 http://haolloyin.blog.51cto.com/1177454/332426/
使用起来也很简单,这个被传递的对象必须继承IService,然后服务端用rebind函数将这个对象和路径映射起来就可以了,服务端关键代码如下:
IService service02 = new ServiceImpl("service02"); //初始化命名空间 Context namingContext = new InitialContext(); //将名称绑定到对象,即向命名空间注册已经实例化的远程服务对象 namingContext.rebind("rmi://localhost/service02", service02);
客户端怎么调用,也很简单
String url = "rmi://localhost/"; Context namingContext = new InitialContext(); // 检索指定的对象。 即找到服务器端相对应的服务对象存根 IService service02 = (IService) namingContext.lookup(url + "service02");
只需要调用lookup将该路径传递进去就可以获得IService类的对象了,又做了这个基础后面理解起来就很简单了。
Spring框架中的JtaTransactionManager出了问题,JtaTransactionManager实现了Serializable,并重写了readObject函数,所以当服务端运行到readObject的时候,就会调用JtaTransactionManager类的readObject函数,跟进这个函数
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { ois.defaultReadObject(); this.jndiTemplate = new JndiTemplate(); this.initUserTransactionAndTransactionManager(); this.initTransactionSynchronizationRegistry(); }
其中initUserTransactionAndTransactionManager()函数的作用看意思应该是初始化一些参数,进入这个函数
继续跟进lookupUserTransaction这个函数 最终执行了lookup,如果看了前面的话应该还记得需要跟一个rmi路径,这个路径其实在ExploitClient中就设置了 所以最终被带入到lookup里面了,那么会怎样?由于路径是rmi://127.0.0.1:1099/Object ,那怎么样?new 一个Object呗,由于前面用bind将ExportObject和Object绑定了,那么就是执行ExportObject的构造函数咯,构造函数里面就是弹出一个计算器,至此,整个逻辑调通。用一张图来总结整个流程比较好,这里借鉴了Seebug上某片文章的图
自己还真的很菜,道阻且长,加油,趁着自己闲下来的时间好好学习。