Deserialization "gadget chain" in clojure

451 views
Skip to first unread message

Ian Haken

unread,
Jul 12, 2017, 12:37:30 AM7/12/17
to Clojure
Dear Clojure community,

First off, apologies for directing this at the general clojure mailing list. I was looking for a better destination, but I couldn't find any obvious person or private mailing list to direct this to; hopefully from here this can get in front of anyone who may be interested.

I recently identified a means to exploit an application performing unsafe deserialization by utilizing a "gadget chain" contained entirely in Clojure classes. What this means is that any application which is deserializing untrusted data and has Clojure on the classpath (whether or not it is actually using Clojure) is subject to a remote code execution exploit. Some more information on this form of vulnerability is available on the OWASP wiki, which also has a number of useful links for deeper discussion.

Details of the specific gadget chain I found can be seen here.

This does not represent a "security vulnerability" in Clojure, and I do not necessarily believe that any action needs to be taken. If an application is subject to exploit via this gadget chain, the vulnerability is with application deserializing untrusted data. However, when deserialization vulnerabilities became a hot topic a couple of years ago with the discovery of a gadget chain in apache-commons, that project received a lot of attention and some made the argument that the projects which support exploitable gadget chains should apply some form of mitigation. For this reason, I wanted to give maintainers of this project a heads-up in case there was any particular action you want to take.

If you have any questions or if there's anything I can clarify, please don't hesitate to reach out to me.
Ian Haken
Twitter: @ianhaken
Message has been deleted

Alex Miller

unread,
Jul 12, 2017, 8:15:20 AM7/12/17
to Clojure
Thanks dropping a line Ian. I dug into this a little to understand it better, would be happy for any corrections.

It seems the prerequisite for an attack like this is to have a server that deserializes objects from an untrusted source. It should be obvious that this is a bad idea. The attack boils down to crafting a serialized object that, when deserialized, can run arbitrary code.

The serialized class being constructed in the attack is clojure.inspector.proxy$javax.swing.table.AbstractTableModel$ff19274a. The Clojure inspector is a Swing app that ships inside the Clojure jar that can be used from the repl to inspect Clojure data structures. AbstractTableModel implements Serializable. The class in question is a proxied subclass of AbstractTableModel (which is thus also Serializable). Clojure proxies contain a field (__clojureFnMap) that is a map of method names to proxy methods. Clojure AOT compiles the clojure.inspector code and includes this proxied, serializable class inside the clojure jar.

The attack constructs an instance of this proxy class and adds a "hashCode" proxy method to the proxy's table. The method is a Clojure function that can run arbitrary code. This instance is then put inside a HashMap and the whole thing is serialized. On deserialization, the HashMap will invoke hashCode() on the proxy object and cause the execution of the arbitrary code.

I have looked at all uses of proxy in the Clojure code base, and as far as I can tell, this is the only case of a proxy of a Serializable class. A quick and effective way to address this particular case is to stop AOT compiling the clojure.inspector namespace. This removes the serializable class from the Clojure jar. Users have no impact other than making the Clojure inspector (which almost no one uses) slightly longer to start. So this is an easy fix with little impact on users. I have filed an issue at https://dev.clojure.org/jira/browse/CLJ-2204 with a patch modifying the build for this purpose for the next Clojure release. We may also consider releasing Clojure 1.8.1 with this change.

Stepping back, it may also be worth considering ways to protect proxies in general, either by detecting and forbidding the proxying of a Serializable/Externalizable class without further steps or by reworking how proxies are implemented in the first place. That's likely to be a bigger change requiring a lot more analysis. I've logged a placeholder issue for this at https://dev.clojure.org/jira/browse/CLJ-2205.

Thanks,
Alex

Ian Haken

unread,
Jul 19, 2017, 1:33:03 PM7/19/17
to Clojure
Hey Alex,

Thanks for digging and the quick reply. I missed your reply originally (apparently I have much to learn about properly subscribing to google groups), so sorry about the delay.

Your understanding is completely correct and your assessment around the best way to mitigate this issue also seems spot on. I took a look at the comments in CLJ-2204 and it seems like you've got a good handle on a holistic approach to mitigating the issue as well.

If you end up having any questions, let me know, but it seems like you're totally on top of it! Thanks again for digging into it and offering up a fix!

Ian

Daniel Compton

unread,
Sep 7, 2017, 6:30:22 PM9/7/17
to Clojure
I saw that this issue was fixed in Clojure 1.9-alpha20. It's tracked in https://dev.clojure.org/jira/browse/CLJ-2204. If you immediately wrote it off as not affecting you because you never use clojure.inspector, it looks like it also affects APersistentMap which is used by everyone. You still need to be accepting serialized objects from an untrusted source (!) for this to affect you AFAICT, but I thought it worth bringing up again.

--
Daniel.

--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages