题目
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.';
}
}
解题思路
题目代码还是挺好理解的:
- 输入内容以
#
分隔 - 左侧内容放入
<form>
的action
属性 - 右侧内容是 json 格式,每一对 key-val 构造成
<form>
内的一个<input>
子标签,其中 key 作为<input>
的name
属性值、val 作为<input>
的value
属性值 - 只要
<form>
的action
属性值通过正则校验,则会调用<form>
的submit()
函数触发action
行为
要在 <form>
的 action
属性执行 javascript 代码,可以构造这样的 payload:
javascript:alert(1)#{"EXP":"M02"}
但是由于 document.forms[0].action
的内容被正则过滤了,导致 javascript:alert(1)
无法执行:
但是这个过滤是不完善的,可以绕过。关键在于 document.forms[0].action
的指向。
当 <forms>
的子标签中没有任何名为 <action>
的子标签时, document.forms[0].action
指向的就是 <forms>
自身的 action
属性。
但若 <forms>
的子标签中,有任一子标签名为 <action>
时, document.forms[0].action
会优先指向该子标签。这样,正则过滤所校验的值就是子标签 <action>
的值,而非 <forms>
标签自身的 action
属性。
回到此题,虽然题目会把我们输入的 json 构造成 <form>
内的 <input>
子标签,但是我们无法直接构造标签名为 <action>
。不过 json 的 key 会作为 <action>
标签的 name
属性值,而我们恰恰可以通过 name
属性为标签更名。
例如 <input name="action">
的名字实际是 action ,而非 input 。
于是我们可以构造这样的 payload 绕过针对 action 的正则过滤:javascript:alert(1)#{"action":"EXP"}
显然成功触发了 alert 事件:
至此,只需要把 alert 改成 prompt 即可完成挑战,最终 payload 为:javascript:prompt(1)#{"action":"EXP"}
答案下载
- payload.md : 下载