Summary: Attacker sends a malformed Content-Type header on file upload, which throws an exception due to the Content-Type being unknown. But, in the exception text is the direct, unsanitized user input from the header.
There is not a specific text localization handler for struts.messages.upload.error.InvalidContentTypeException, so a generic exception handler ends up being used to process the exception. This generic handler turns out to parse the unsanitized user input as OGNL markup, running the attacker code when processing the exception text.
Some effort is made to blacklist loading other Java libraries in the text rendering context, however it was easily defeated by emptying the blacklist in the attacking code before calling the blacklisted modules.
So basically they called eval() on an error message, to put it bluntly? Nice reminder that no matter how safe the language, people will do nutty stuff with it.
This generic handler turns out to parse the unsanitized user input as OGNL markup
The article is pretty dense and I don't understand this point. I can maybe understand why you'd want to parse the output of an exception message, but why would you ever want to be executing what you parse?
I don't know either, so I googled [OGNL] and the instant answer snippet was
> OGNL stands for Object-Graph Navigation Language; it is an expression language for getting and setting properties of Java objects, plus other extras such as list projection and selection and lambda expressions. You use the same expression for both getting and setting the value of a property.
No. But template expression language used in Struts is quite expressive. :) There's some defensive system to prevent access to arbitrary classes, but the attacker managed to overcome it in a clever way.
Ah, I probably should have used a TL;DR tag - my original comment is just a really condensed summary of the awesome but super detailed article, which even shows and explains the Struts code in question, example requests and responses, stack traces from the exception, and the exception logs. Even in the comments are some logs that look like evidence of an actual in-the-wild RCE attempt!
So maybe check there for more explanation... all credit for the research and investigation goes to the article's author. It was really a good 'deep dive' into the internals of Struts to see how such a subtle bug could be turned into RCE.
I have yet to see any credible source pinpointing the CVE used to compromise the Equifax data (we all know it's in Struts, but which one was it?). Has something changed, or is this title clickbait?
Note that the linked article isn't clickbait. It's an InfoSec description of how they dealt with the same vuln that hit Equifax. The article was written ~6 weeks before Equifax's stated timeline of attack.
To clarify your comment, Equifax did recently reveal[1] the specific vuln (CVE-2017-5638) in Apache Struts that was used during the ~May-July attack that caused the most headlines.
Oh, yes, I understand that the linked article isn't clickbait - I was calling out the title specifically for that reason, because if Equifax hadn't confirmed the CVE, I think it would qualify as a clickbait title ;)
Thanks for the link, though, I somehow managed to miss that announcement.
>The attack vector used in this incident occurred through a vulnerability in Apache Struts (CVE-2017-5638), an open-source application framework that supports the Equifax online dispute portal web application.
Summary: Attacker sends a malformed Content-Type header on file upload, which throws an exception due to the Content-Type being unknown. But, in the exception text is the direct, unsanitized user input from the header.
There is not a specific text localization handler for struts.messages.upload.error.InvalidContentTypeException, so a generic exception handler ends up being used to process the exception. This generic handler turns out to parse the unsanitized user input as OGNL markup, running the attacker code when processing the exception text.
Some effort is made to blacklist loading other Java libraries in the text rendering context, however it was easily defeated by emptying the blacklist in the attacking code before calling the blacklisted modules.