一.
SpEL表达式:(Spring Expression Language),即Spring表达式语言,是比JSP的EL更强大的一种表达式语言。
SpEL有三种用法,一种是在注解@Value中;一种是XML配置;最后一种是在代码块中使用Expression。
1.
@Value("#{表达式}")
public String arg;
2.
<bean id="xxx" class="com.java.XXXXX.xx">
<!-- 同@Value,#{}内是表达式的值,可放在property或constructor-arg内 -->
<property name="arg" value="#{表达式}">
</bean>
3.
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("表达式");
Object value = exp.getValue();
二.
Spring JNDI:
JNDI全称为 Java Naming and Directory Interface(Java命名和目录接口),是一组应用程序接口,为开发人员查找和访问各种资源提供了统一的通用接口,可以用来定义用户、网络、机器、对象和服务等各种资源。
JNDI支持的服务主要有:DNS、LDAP、CORBA、RMI等。
简单点说,JNDI就是一组API接口。每一个对象都有一组唯一的键值绑定,将名字和对象绑定,可以通过名字检索指定的对象,而该对象可能存储在RMI、LDAP、CORBA等等。
JNDI注入
前提条件&JDK防御
要想成功利用JNDI注入漏洞,重要的前提就是当前Java环境的JDK版本,而JNDI注入中不同的攻击向量和利用方式所被限制的版本号都有点不一样。
所有不同版本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协议的攻击途径也给禁了。
因此,在进行JNDI注入之前,必须知道当前环境JDK版本这一前提条件,只有JDK版本在可利用的范围内才满足我们进行JNDI注入的前提条件。
RMI攻击向量
RMI+Reference利用技巧
JNDI提供了一个Reference类来表示某个对象的引用,这个类中包含被引用对象的类信息和地址。
因为在JNDI中,对象传递要么是序列化方式存储(对象的拷贝,按值传递),要么是按照引用(对象的引用,按引用传递)来存储,当序列化不好用的时候,我们可以使用Reference将对象存储在JNDI系统中。
那么这个JNDI利用技巧——就是将恶意的Reference类绑定在RMI注册表中,其中恶意引用指向远程恶意的class文件,当攻击者可以控制JNDI客户端的lookup()参数,或Reference类构造方法的classFactoryLocation参数时,会使用户的JNDI客户端访问RMI注册表中绑定的恶意Reference类,从而,加载远程服务器上的恶意class文件,在客户端本地执行,最终实现JNDI注入攻击,导致远程代码执行。
|