-
Notifications
You must be signed in to change notification settings - Fork 221
Cure53 Easter Challenge '13
So, it's the 15th of April and the Easter Challenge 2013 is over.
We received an astounding amount of 299784 requests. Yes, many people were fuzzing, enumerating and doing other crazy stuff, but almost 300K requests.. that's an insane record. I reckon people had fun.
Now, let's have a look at the winning solution and the dissect, how it works - and what I actually wanted the contestants to do. The winner is... @shafigullin! Second place goes to @thewildcat, congratulations, gentlemen! @shafigullin was first to submit a solution that is 37 characters in length. And here it is, the winning vector of fame and glory:
http://cure53.de/easter?a=<x&d='onload=&e=;alert%281e25%29<!--
Here's how I counted:
strlen("?a=<x&d='onload=~&e=;alert(~1e25)<!--") == 37
Now what the heck is going on here? Why does this work? Well, some of you know it already - but some maybe not. Let's explain. First of all, the challenge was meant to be nasty and mess with your brain. Here's how I decided to make the contestant’s lives harder:
- The GET parameter names were not known, had to be guessed
- Some parameters were useful, some not
- Each parameter was filtered by a different regex
- Each parameter had a specific maximum length
- Some parameters were traps, leading to spend time on nothing of particular relevance (we call them armpit-parameters)
- The whole thing happened inside an SVG! That's important!
- I built in some Unicode RTL/LTR characters to make debugging bad for your brain :)
So. People were supposed to inject into a script-block, in the midst of juicy strings and comment blocks. First thing that comes to mind: Oh, I'll break those strings and comments and done. Stupid .mario, so easy. Duh.
Well - nope! Not at all! I am not sure how many requests I counted trying to break strings and comments and believe me - I had diabolic fun watching those poor souls suffer. Because they were all wrong.
Some people nevertheless quickly realized, that the script-block, once wrapped by an SVG, follows different rules, allows different injections - has its own mind. Once you inject a HTML-like construct into a JavaScript string inside a script-block inside an SVG, things change fundamentally! I had a set if dirty little helpers hiding that fact. our fellow browsers. Most people debugged while watching the page-source in parallel. Problem with that: the source-view let's you think, you're still inside a JavaScript string - but you already are in a completely different reality! That's messed up, right? Welcome to the reality of HTML5 :)
Let's have a look at an example; this is what you got without any parameters:
<svg height="100">
<script>
a='';
id='';
c='';
/* remove before going live
d='';//e='';
f='';
*/
</script></svg>
This is how the winning solution looks in source-view: http://cure53.de/easter?a=%3cx&d=%27onload=~&e=;alert%28~1e25%29%3c!--
<svg height="100">
<script>
a='<X';
id='';
c='';
/* remove before going live
d=''onload=~';//e=';alert(~1e25)<!--';
f='';
*/
</script></svg>
But don't forget - your browser is messing with you and not telling you the actual truth. Because this is what actually happens. Like, really. Not kidding:
<svg height="100">
<script>
a='<x'; id="" ;="" c="" *="" remove="" before="" going="" live="" d="" onload="~';//e=';alert(~1e25)<!--';" f="" <="" script=""></x';></script></svg>
The only way of getting here is to inspect the DOM or watch the resulting innerHTML
(yep, that property again. You're gonna be hearing more from it soon I hope). Note, it's still messed up thanks to my nasty RTL/LTR characters! Man, I like doing these things to honest hard-working people :) But let's be nice for once and remove them:
<svg height="100">
<script>
a='<x'; id="" ;="" c="" *="" remove="" before="" going="" live="" d="" onload="~';//e=';alert(~1e25)<!--';" f="" <="" script=""></x';></script></svg>
So now you can see what actually happens:
- The parameter a fills variable a, destroys the script-block inside the SVG, opens a new HTML element
- The parameter fills the variable id - unnecessary, a trap for people who work with the DOM a lot
- The parameter c is totally not necessary
- The parameter d nevertheless ends an attribute - created by itself, formerly the variable d and then creates an event handler
- The parameter e fills the handler with JavaScript
Now, since I wanted to get the number 2147483647
to be alerted, people not only had to make it until here, but then also find a way to represent this number in the shortest possible way. Many submitted a variation using a bit-shift. But JavaScript is full of surprises - and also allows to represent numbers exponentially :) The snippet ~1e25
is the so far shortest way to do the 2147483647
.
Now we have everything together: Short number 2147483647
, destroyed script-block in SVG, injected event handler... wait! We have an onload
on an <x>
-element? And that works? Yes. That's the last part of the challenge - choosing the right browser. In this case we need Chrome (or anything like it). Chrome allows onload
on everything that is inside SVG. Even on an <x>
element, that doesn't even exist. Well - and that’s it :) That's the whole story. Easy, right?
I hope you enjoyed this challenge, thanks to @mmrupp for a juicy donation on top of the original price money and, as for your glorious winners, enjoy the book packages! And thanks for living so freaking far away and busting my petty cash box :D