ECW 2018 is a French Jeopardy challenge organized by the PEC (French Pôle d’Excellence Cyber) in partnership with the Bretagne county, Airbus and Thales. “Troll.JSP” is challenge based on the CVE-2017-5638 exploitation, executing code to change a session variable and then display the flag.
From 06/10 to 21/10 2018, it will be used as a pre-selection for the final Capture The Flag event, which will start on 21 November 2018 at the European Cyber Week conference in Rennes.
Discovery
No statement for this challenge, since the following image was displayed as a statement guide. But no worries, look at the name of the challenge…
We land on a page, very clear, containing almost no information.
Information gatherig and vulnerability identification
First thing, we just go chek sources and we can see a “debug.jsp” file.
https://web125-trolljsp.challenge-ecw.fr/debug.jsp
Accessing this page offer more features. There is a “flag” tab, with a gift…
Needless to say, knowing the goal of this challenge, that this “flag” is a troll. Nevertheless, it allows us go ahead in the challenge because the MD5 gives us the following information : “swp”. Some research on “.swp” extensions lead us to believe that an important swap file for the challenge is available. Some tests are therefore performed and quite quickly we find the file ".flag.jsp.swp".
https://web125-trolljsp.challenge-ecw.fr/.flag.jsp.swp
Three interesting points here:
- the comment “TODO change the flag” ;
- A new MD5 hash ;
- A session variable, “flag” is displayed.
First, the MD5 hash. If it is the same as the first one, it could also give us information…. And indeed, once broken, we obtain the string “equifax”. Some research about this term lead us to discover a story about Equifax, a company that was hacked in 2017. The cause? A vulnerability in the Apache Struts (CVE-2017-5638) framework. So it seems that we know how we will solve this challenge…. Before going to exploitation, a quick word on the two other elements.
It seems that the page displays the value of the variable “flag” if the value of session.flag is not null. Otherwise, we receive the display of trollFlag, which we already know. Moreover, since this file is a swap file and there is a comment “TODO change the flag”, we can assume that in the real file, the flag has been changed by the real flag. So we have a guideline ! A way must be found to modify the value of session.flag.
Exploication - CVE-2017-5638
Some research around this vulnerability leads us to the following two articles, detailing very well the vulnerability :
- https://www.immun.io/blog/will-it-pwn-cve-2017-5638-remote-code-execution-in-apache-struts-2
- https://blog.xmco.fr/12-questions-pour-mieux-comprendre-la-derniere-faille-struts/
Very quickly, the exploitation involves the use of the header “Content-Type” of HTTP requests.
- A “multipart” type HTTP request will be detected by Struts ;
- This one will be sent to the Jakarta parser ;
- If an error occurs during processing (for example, an invalid Content-Type) the error message generated will contain the invalid element ;
- In order to display the error to the user, an unsafe function, findText() is used. This one will evaluate the string generated. Thus, if a malicious payload is ut there, it will be executed.
This vulnerability allows in theory to execute commands directly on the server. The malicious payload used in many examples on the Internet is :
Content-Type: %{(#_='multipart/form-data').(#_memberAccess=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(@java.lang.Runtime@getRuntime().exec('curl localhost:8000'))}
Some tests have shown that this type of payload does not work on the server. Indeed, it seems that we are facing a WAF (Web Application Firewall) that will prevent the request from being processed if it detects special elements (parentheses or dots, for example).
Moreover, in our case, we are trying to modify the value of a session variable. No need to execute code with @java.lang.Runtime@getRuntime()
.
Note that in the payload, the first expression (#_='multipart/form-data')
is only used to pass the condition necessary to trigger the vulnerability. This is the assignment of a string to a variable. Isn’t that exactly what we need?
Some additional research and tests allow us to build this payload :
Content-Type: %{#session["flag"]="multipart/form-data"}
In this way, we satisfy the server side condition, indicating that the “multipart/form-data” string must be present and we satisfy the application side condition saying that the session.flag value must not be null. In addition, no prohibited characters are used, so the firewall is not triggered.
Getting the flag
In order to pass our exploit, we intercept a classic request to the page /flag.jsp using Burp, to which we add our malicious header.
We see that the request has been processed and that the returned flag is different… Solved challenge ;)
References
- Will it pwn CVE-2017-5638 RCE in Apache Struts 2
- 12 questions pour mieux comprendre la dernière faille Struts