• 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是输入流。

    因此只要传入的字节流是反序列化的内容即可。

  • 相关阅读:
    如何运行 PPAS上的pgpoolII
    Postmaster主循环的大致流程
    对ListenSocket 的研究(三)
    对ListenSocket 的研究(二)
    对ListenSocket 的研究(五)
    PostgreSQL的postmaser的fork的学习体会
    赛门铁克公告:解密Kneber恶意软件 狼人:
    微软免费杀毒软件MSE最新版本释出 狼人:
    Facebook出现邮件错发故障 隐私安全再受关注 狼人:
    McAfee和Brocade将联合开发网络安全解决方案 狼人:
  • 原文地址:https://www.cnblogs.com/ph4nt0mer/p/12125241.html
Copyright © 2020-2023  润新知