JVM参数注入漏洞
JVM参数注入漏洞
A、简述:
JVM参数注入是一种特定于Java应用程序的安全漏洞,它允许攻击者通过某种方式向JVM传递恶意构造的启动参数,从而改变JVM的行为。这些参数可能会影响内存分配、垃圾回收策略、安全管理器配置等方面,进而导致严重的安全后果。
B、流程:
1、命令行参数:如果应用程序直接使用用户输入构建JVM启动命令,而没有进行适当的验证或清理,就可能存在风险。
2、环境变量:一些JVM参数可以通过环境变量设置,如JAVA_TOOL_OPTIONS。如果应用程序运行在一个不受信任的环境中,或者环境变量是由用户提供的,那么就容易受到攻击。
3、配置文件:部分应用程序可能会从配置文件读取JVM启动参数。如果配置文件的内容可控或容易被篡改,也可能导致参数注入的问题。
API调用:通过Java代码中的API,如ManagementFactory.getPlatformMBeanServer(),可以在运行时动态设置JVM参数,如果这部分逻辑存在缺陷,也可能会引入漏洞。
C、某ERP系统(核心代码):
#!/bin/bash
# 系统变量
readonly APP_HOME=${FILE_PATH:-$(dirname $(cd `dirname $0`; pwd))}
readonly CONFIG_HOME="$APP_HOME/config/"
readonly LIB_HOME="$APP_HOME/lib"
readonly LOGS_HOME="$APP_HOME/logs"
# JVM参数
JAVA_OPTS="-server -Xms128m -Xmx320m -XX:PermSize=128M -XX:MaxPermSize=256M"
# 启动命令
java $JAVA_OPTS -jar $APP_MAIN_CLASS
D、漏洞分析:
A、JAVA_OPTS 未使用 readonly
JAVA_OPTS 并没有被声明为只读(readonly)。这意味着 JAVA_OPTS 可以在脚本执行之前或执行过程中被修改。如果攻击者能够控制环境变量或在脚本执行之前修改 JAVA_OPTS,攻击者会注入恶意的JVM 参数。
B、环境变量覆盖:
由于 JAVA_OPTS 没有被声明为只读,攻击者可以通过设置环境变量来覆盖 JAVA_OPTS 的值。例如,攻击者可以在命令行中设置 JAVA_OPTS,然后运行脚本。
export JAVA\_OPTS="-Djava.rmi.server.hostname=malicious.host -agentlib:jdwp=transport=dt\_socket,server=y,suspend=n,address=5005" ./run-manage.sh
这会导致应用程序以攻击者指定的 JVM 参数启动,可能带来严重的安全风险,例如:
1、远程调试端口:启用远程调试端口,允许攻击者连接并执行任意代码。
2、加载恶意 JAR 文件:通过 -Djava.class.path 或其他参数加载恶意 JAR 文件。
3、日志配置篡改:通过 -Dlogging.config 等参数篡改日志配置,导致日志信息泄露或其他安全问题。
E、验证:
命令:export JAVA\_OPTS="-Djava.rmi.server.useCodebaseOnly=false -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=12345 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false"
参数解释:
-Dcom.sun.management.jmxremote:启用 JMX 远程管理接口。
-Dcom.sun.management.jmxremote.port=12345:指定 JMX 监听的端口为 12345。
-Dcom.sun.management.jmxremote.authenticate=false:禁用 JMX 认证。
-Dcom.sun.management.jmxremote.ssl=false:禁用 JMX SSL 加密。
增加权限:chmod +x run-manage.sh
端口查看:netstat -tuln | grep 12345
F、修复:
1、启用 JMX 身份验证:
设置 com.sun.management.jmxremote.authenticate=true,并配置用户名和密码文件。
例如:
-Dcom.sun.management.jmxremote.authenticate=true \
-Dcom.sun.management.jmxremote.password.file=/path/to/jmxremote.password \
-Dcom.sun.management.jmxremote.access.file=/path/to/jmxremote.access
2、启用 JMX SSL/TLS 加密:
设置 com.sun.management.jmxremote.ssl=true,并配置 SSL 证书。
-Dcom.sun.management.jmxremote.ssl=true \
-Djavax.net.ssl.keyStore=/path/to/keystore.jks \
-Djavax.net.ssl.keyStorePassword=your_keystore_password
3、3、限制 JMX 接口的访问范围:
使用防火墙规则或网络安全组,限制只有特定 IP 地址或子网可以访问 JMX 端口 12345。
例如,使用 iptables 限制只有本地网络可以访问该端口:
iptables -A INPUT -p tcp --dport 12345 -s 192.168.0.0/16 -j ACCEPT
iptables -A INPUT -p tcp --dport 12345 -j DROP
4、审查和清理 MBean 注册::
确保应用程序只注册必要的 MBean,并且这些 MBean 不包含任何不安全的操作。
避免使用第三方库中可能存在安全问题的 MBean。
5、使用最小化权限原则:
确保运行应用程序的用户权限最小化,避免使用 root 或其他高权限用户。
G、问题(小思考):
如果用在内网横向会怎么样?