From 057e2f1cd19189b2bcf88d240171315f4a55adab Mon Sep 17 00:00:00 2001 From: Peter Taoussanis Date: Thu, 10 Sep 2020 13:47:23 +0200 Subject: [PATCH] Serializable: add `read-quarantined-serializable-object-unsafe!` util --- src/taoensso/nippy.clj | 25 ++++++++++++++++++++++++- test/taoensso/nippy/tests/main.clj | 26 +++++++++++++++++--------- 2 files changed, 41 insertions(+), 10 deletions(-) diff --git a/src/taoensso/nippy.clj b/src/taoensso/nippy.clj index b5b9509..1cf62ee 100644 --- a/src/taoensso/nippy.clj +++ b/src/taoensso/nippy.clj @@ -321,7 +321,9 @@ If `thaw` encounters an unwhitelisted Serialized class: - `thaw` will throw if it's not possible to safely quarantine. - Otherwise the object will be thawed as: - `{:nippy/unthawable {:class-name _ :content ...}}`. + `{:nippy/unthawable {:class-name <> :content ...}}`. + - Objects thus quarantined may be manually unquarantined with + `read-quarantined-serializable-object-unsafe!`. This is a security measure to prevent Remote Code Execution (RCE). @@ -1381,6 +1383,27 @@ :content nil :exception e}}))) +(defn read-quarantined-serializable-object-unsafe! + "Given a quarantined Serializable object like + {:nippy/unthawable {:class-name <> :content }}, reads and + returns the object WITHOUT regard for `*serializable-whitelist*`. + + **MAY BE UNSAFE!** Don't call this unless you absolutely trust the payload + to not contain any malicious code. + + See `*serializable-whitelist*` for more info." + [m] + (when-let [m (get m :nippy/unthawable)] + (let [{:keys [class-name content]} m] + (when (and class-name content) + (read-object + (DataInputStream. (ByteArrayInputStream. content)) + class-name))))) + +(comment + (read-quarantined-serializable-object-unsafe! + (thaw (freeze (java.util.concurrent.Semaphore. 1))))) + (defn- read-serializable-q "Quarantined => object serialized to ba, then ba written to output stream. Has length prefix => can skip `readObject` in event of whitelist failure." diff --git a/test/taoensso/nippy/tests/main.clj b/test/taoensso/nippy/tests/main.clj index bab06e9..367b294 100644 --- a/test/taoensso/nippy/tests/main.clj +++ b/test/taoensso/nippy/tests/main.clj @@ -276,16 +276,24 @@ "Can freeze and thaw Serializable object if approved by whitelist") - (is - (= :quarantined - (get-in - (nippy/thaw - (nippy/freeze (java.util.concurrent.Semaphore. 1) - #_{:serializable-whitelist "*"}) - {:serializable-whitelist #{}}) - [:nippy/unthawable :cause])) + (let [sem (java.util.concurrent.Semaphore. 1) + ba (nippy/freeze sem #_{:serializable-whitelist "*"}) + thawed (nippy/thaw ba {:serializable-whitelist #{}})] - "Thaw will quarantine Serializable objects approved when freezing.") + (is + (= :quarantined (get-in thawed [:nippy/unthawable :cause])) + "Serializable objects will be quarantined when approved for freezing but not thawing.") + + (is + (instance? java.util.concurrent.Semaphore + (nippy/read-quarantined-serializable-object-unsafe! thawed)) + "Quarantined Serializable objects may still be manually force-read.") + + (is + (instance? java.util.concurrent.Semaphore + (nippy/read-quarantined-serializable-object-unsafe! + (nippy/thaw (nippy/freeze thawed)))) + "Quarantined Serializable objects are themselves safely transportable.")) (is (instance? java.util.concurrent.Semaphore