spring-jndi反序列化
众所周知Spring框架是一款用途广泛影响深远的java框架,因此Spring框架一旦出现漏洞也是影响深远。这次分析的Spring jdni反序列化漏洞主要存在于spring-tx包中,该包中的org.springframeworkl.transation.jta.JtaTransationManager
类存在JDNI反序列化的问题,可以加载我们注册的RMI链接,然后将对象发送到有漏洞的服务器从而执行远程命令。首先应当注意本文中成功执行的Poc本人仅在jdk1.7中测试成功,而jdk1.8中未测试成功。
什么是JNDI?
JNDI
(Java Naming and Directory Interface)是J2EE中的重要规范之一,是一组在Java应用中访问命名和目录服务的API,使得我们能够通过名称去查询数据源从而访问需要的对象。
这里我们给出在java下的一段提供JNDI服务的代码:
1 | System.out.println("Starting HTTP server"); |
这里我们创建了一个HTTP服务后又创建了一个RMI服务,并且RMI服务提供了对ExportObject
类的查询,这里ExportObject类的源码为:
1 |
|
其功能便是执行我们验证rce时常用的调用计算器的功能。
要加载ExportObject类我们可以使用以下的代码:
1 | Context ctx=new InitialContext(); |
执行以下代码后可以发现ExportObject类的构造函数被调用,弹出了计算器。
Spring框架中的JNDI反序列化漏洞
导致JNDI反序列化问题的类主要是org.springframework.transaction.jta.JtaTransactionManager
类。跟进该类的源码中的readObject()
函数:
1 | private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { |
继续跟进initUserTransactionAndTransactionManager()
函数
1 | protected void initUserTransactionAndTransactionManager() throws TransactionSystemException { |
继续进一步跟进lookupUserTransaction()
函数
1 | protected UserTransaction lookupUserTransaction(String userTransactionName) throws TransactionSystemException { |
可以看到最终return (UserTransaction)this.getJndiTemplate().lookup(userTransactionName, UserTransaction.class)
,跟进JndiTemplate
类的lookup
方法,
1 | public Object lookup(final String name) throws NamingException { |
而execute()
方法的定义如下
1 | public <T> T execute(JndiCallback<T> contextCallback) throws NamingException { |
可以看到在整个流程的最后将会查询最开始我们由反序列化传入的org.springframework.transaction.jta.JtaTransactionManager
类的对象的userTransactionName
属性,最终导致加载了我们恶意的rmi源中的恶意类,从而导致RCE。
Poc
这个漏洞的Poc构造比起之前分析的apache common collections反序列化的Poc构造显然要简单许多:
1 | System.out.println("Connecting to server "+serverAddress+":"+port); |
执行后可以发现成功弹出计算器。