JavaSec系列 - 5. SpEL注入
本章源码: https://github.com/hey3e/JavaSec-Code/tree/main/javasec5
先前,我们在系列2中jdk>8u191的环境下实现JNDI注入时,使用到了EL表达式。SpEL,是EL的一种,”Sp”代表”Spring”,即用于Spring的表达式。而最近,Spring Cloud爆出两个RCE,其原理均为SpEL注入,因此我们下面通过接触这两个实例来了解SpEL注入的实现。
本章源码: https://github.com/hey3e/JavaSec-Code/tree/main/javasec5
先前,我们在系列2中jdk>8u191的环境下实现JNDI注入时,使用到了EL表达式。SpEL,是EL的一种,”Sp”代表”Spring”,即用于Spring的表达式。而最近,Spring Cloud爆出两个RCE,其原理均为SpEL注入,因此我们下面通过接触这两个实例来了解SpEL注入的实现。
本章源码: https://github.com/hey3e/JavaSec-Code/tree/main/javasec4
深入分析CVE-2021-21344。
本章源码: https://github.com/hey3e/JavaSec-Code/tree/main/javasec3
上章我们了解到,通过控制lookup
方法的参数,可以实现JNDI注入。从控制到注入,就是一条完整的攻击链。我们来看一个实例。
本章源码: https://github.com/hey3e/JavaSec-Code/tree/main/javasec2
命名与目录系统 (Naming and Directory services),如RMI (Remote Method Invocation)、LDAP (Lightweight Directory Access Protocol) 等,能够以类似字典key-value
的name-object
形式对对象进行存储,使得我们可以通过名称来查询并访问对象。JNDI (Java Naming and Directory Interface) 便是该过程的接口。
结合上一章的知识,我们考虑在系统中存储对象序列化后的字节流,当用户进行查询时,系统返回对应的字节流,用户再进行反序列化获取对象。但在实际场景中,如果对象过大,采用该方式往往会给系统带来一定的负担。
于是,JNDI使用Naming References
的方式进行存储,此时,name-object
中的object
并非对象本身,而是对象的引用Reference
,其中包含对象名及其真正被存放的地址codebase。当用户进行查询时,系统返回Reference
,用户解析后再从codebase获取对象。不过这里说的不太严谨,后面会进行补充。
不过,上述从远程codebase加载对象的方式存在许多安全问题,随着jdk版本的迭代,系统对codebase已逐渐不再信任,JNDI受到越来越多的限制。我们下面看一下各版本下JNDI如何实现。
本章源码: https://github.com/hey3e/JavaSec-Code/tree/main/javasec1
在Java中,我们创建的对象会随着其JVM的销毁而销毁。但有时,我们希望能在其他JVM、或是其他机器上复用这个对象。序列化允许我们将Java对象转换为字节流,便于存储到本地,以及通过网络发送给其他机器。而反序列化允许我们重新将序列化的字节流还原为Java对象。