CVE-2019-17571 Log4j組件存在反序列化


https://www.openwall.com/lists/oss-security/2019/12/19/2

Date: Wed, 18 Dec 2019 21:21:19 -0600
From: Matt Sicker <mattsicker@...che.org>
To: oss-security@...ts.openwall.com
Subject: [CVE-2019-17571] Apache Log4j 1.2 deserialization of untrusted data
 in SocketServer

CVE-2019-17571: Deserialization of untrusted data in SocketServer

Severity: Critical
CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H/RL:W

Product:
Apache Log4j

Versions Affected:
Apache Log4j up to and including 1.2.27. Separately fixed by
CVE-2017-5645 in Log4j 2.8.2.

Problem type:
CWE-502: Deserialization of Untrusted Data

Description:

Included in Log4j 1.2 is a SocketServer class that is vulnerable to
deserialization of untrusted data which can be exploited to remotely
execute arbitrary code when combined with a deserialization gadget
when listening to untrusted network traffic for log data.

Mitigation:

Apache Log4j 1.2 reached end of life in August 2015. Users should
upgrade to Log4j 2.x which both addresses that vulnerability as well
as numerous other issues in the previous versions.

Credit:

This issue was initially discovered in CVE-2017-5645 by Marcio Almeida
de Macedo of Red Team at Telstra.

Links:

https://logging.apache.org/log4j/1.2/
https://issues.apache.org/jira/browse/LOG4J2-1863

-- 
Matt Sicker
Secretary, Apache Software Foundation
VP Logging Services, ASF

漏洞在SocketServer類里

下載Log4j的jar包。我選擇了1.2.14版本。

全局搜到SocketServer.class

 

 

看class代碼的main函數代碼,代碼不長,還是比較好理解的。

  void main(String argv[]) {
    if(argv.length == 3)
      init(argv[0], argv[1], argv[2]);
    else
      usage("Wrong number of arguments.");

    try {
      cat.info("Listening on port " + port);
      ServerSocket serverSocket = new ServerSocket(port);
      while(true) {
    cat.info("Waiting to accept a new client.");
    Socket socket = serverSocket.accept();
    InetAddress inetAddress =  socket.getInetAddress();
    cat.info("Connected to client at " + inetAddress);

    LoggerRepository h = (LoggerRepository) server.hierarchyMap.get(inetAddress);
    if(h == null) {
      h = server.configureHierarchy(inetAddress);
    }

    cat.info("Starting new socket node.");
    new Thread(new SocketNode(socket, h)).start();
      }
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }

init初始化了參數,傳入的參數是三個。

new一個serverSocket對象,最后new Thread(new SocketNode(socket, h)).start();

把收到的socket流內容,用SocketNode實例化這個流內容。我們看下SocketNode這個類是怎么實現的吧。全局搜索SocketNode。

public class SocketNode implements Runnable {

  Socket socket;
  LoggerRepository hierarchy;
  ObjectInputStream ois;

  static Logger logger = Logger.getLogger(SocketNode.class);

  public SocketNode(Socket socket, LoggerRepository hierarchy) {
    this.socket = socket;
    this.hierarchy = hierarchy;
    try {
      ois = new ObjectInputStream(
                         new BufferedInputStream(socket.getInputStream()));
    }
    catch(Exception e) {
      logger.error("Could not open ObjectInputStream to "+socket, e);
    }
  }

  //public
  //void finalize() {
  //System.err.println("-------------------------Finalize called");
  // System.err.flush();
  //}

  public void run() {
    LoggingEvent event;
    Logger remoteLogger;

    try {
      while(true) {
    // read an event from the wire
    event = (LoggingEvent) ois.readObject();
    // get a logger from the hierarchy. The name of the logger is taken to be the name contained in the event.
    remoteLogger = hierarchy.getLogger(event.getLoggerName());
    //event.logger = remoteLogger;
    // apply the logger-level filter
    if(event.getLevel().isGreaterOrEqual(remoteLogger.getEffectiveLevel())) {
      // finally log the event as if was generated locally
      remoteLogger.callAppenders(event);
    }
      }
    } catch(java.io.EOFException e) {
      logger.info("Caught java.io.EOFException closing conneciton.");
    } catch(java.net.SocketException e) {
      logger.info("Caught java.net.SocketException closing conneciton.");
    } catch(IOException e) {
      logger.info("Caught java.io.IOException: "+e);
      logger.info("Closing connection.");
    } catch(Exception e) {
      logger.error("Unexpected exception. Closing conneciton.", e);
    }

    try {
      ois.close();
    } catch(Exception e) {
      logger.info("Could not close connection.", e);
    }
  }
}

代碼不是很長,執行的是run的代碼。可以看到

event = (LoggingEvent) ois.readObject();

直接執行了readObject操作。ois是ObjectInputStream ois;定義了ois是輸入流。

因此只要傳入的字節流是反序列化的內容即可。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM