Skip to content

Instantly share code, notes, and snippets.

Created Apr 19, 2014
What would you like to do?
(defproject parser-vuln-test "1.0" :dependencies [[org.clojure/clojure "1.6.0"]])
(ns vuln-test
(:require [clojure.xml :as xml]
[clojure.string :as s]
[clojure.test :refer :all]))
;; See
(spit "target/xxe-attack.xml" "<?xml version=\"1.0\"?>
<!DOCTYPE foo [ <!ELEMENT foo ANY > <!ENTITY xxe SYSTEM \"../project.clj\" >]>
;; See
;; Processed XML will expand to 100 fold. Increase these values to blow up your JVM.
(def ent-times 100)
(def ent-len 64000)
(def bomb-yield (* ent-len ent-times))
(spit "target/bomb.xml" (str "<?xml version=\"1.0\"?>
<!DOCTYPE foo [ <!ENTITY a \"" (s/join (repeat ent-len "a")) "\">]>
<foo>" (s/join (repeat ent-times "&a;")) "</foo>"))
(deftest default-impl
(testing "clojure.xml/parse default implementation is vulnerable to XXE attacks"
(is (.startsWith
(-> (xml/parse "target/xxe-attack.xml") xml/content first)
(testing "clojure.xml/parse default implementation is vulnerable to XML bombs"
(is (=
(-> (xml/parse "target/bomb.xml") xml/content first)
(s/join (repeat bomb-yield"a"))))))
;; Luckily, mitigation is easy
;; Safer version of clojure.xml/startparse-sax
(defn startparse-sax-no-doctype [s ch]
(doto (javax.xml.parsers.SAXParserFactory/newInstance)
(.setFeature javax.xml.XMLConstants/FEATURE_SECURE_PROCESSING true)
(.setFeature "" true))
(parse s ch)))
(deftest disallow-doctype-decl
(testing "Disallowing DOCTYPE declaration disables external entity processing"
(is (thrown-with-msg? org.xml.sax.SAXParseException #"DOCTYPE is disallowed"
(xml/parse "target/xxe-attack.xml" startparse-sax-no-doctype))))
(testing "Disallowing DOCTYPE declaration defuses XML bombs"
(is (thrown-with-msg? org.xml.sax.SAXParseException #"DOCTYPE is disallowed"
(xml/parse "target/bomb.xml" startparse-sax-no-doctype)))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment