从业者-存储型DOM XSS
# 实验室:存储型DOM XSS
# 题目
此实验室在 博客评论功能 中包含一个存储型的 DOM 漏洞。若要解决实验室问题,请利用此漏洞调用alert()
函数。
- name: 实验室-从业者
desc: 存储型DOM XSS >>
avatar: https://fastly.statically.io/gh/clincat/blog-imgs@main/vuepress/static/imgs/docs/burpsuite-learn/public/lab-logo.png
link: https://portswigger.net/web-security/cross-site-scripting/dom-based/lab-dom-xss-stored
bgColor: '#001350'
textColor: '#4cc1ff'
2
3
4
5
6
# 实操
点击 “ACCESS THE LAB” 进入实验室。
点击任意文章下方的 “View post” 进入详情页。
在文章详情中存在一处 JavaScript,此处定义了一个escapeHTML
函数,该函数对尖括号<>
进行了 HTML 实体编码。
function escapeHTML(html) {
return html.replace('<', '<').replace('>', '>');
}
2
3
此外还存在三处innerHTML
。
第一处,接收评论作者名称,用户输入可控。
let newInnerHtml = firstPElement.innerHTML + escapeHTML(comment.author)
第二处,获取当前时间,用户不可控。
let newInnerHtml = firstPElement.innerHTML + " | " + dateStr
第三处,获取评论内容,用户输入可控。
commentBodyPElement.innerHTML = escapeHTML(comment.body)
尝试发布一个评论,用户名称 和 评论内容都位于标签之外,无法在现有的标签内注入载荷。
尝试注入经典的攻击载荷。
提交之后,点击 “Back to blog” 返回刚刚的博客文章。
正如前面看到的escapeHTML
函数,尖括号都被过滤了。
捕获评论的请求数据包,一共有四个数据包。
第一个请求,提交表单。
第二个请求,跳转至 “提交成功” 页面,可以点击返回按钮回到刚刚的博客。
第三个请求,调用函数loadComments
加载评论。
第四个请求,获取评论内容并返回。
修改载荷,尝试闭合响应中的 JSON 数据。
失败,双引号被转义。
尝试提交自己的反斜杠,同样被转义,这次应用程序没有再犯错。
在提交经典的script
载荷时,发现结束标签会离奇消失,为什么?
尝试提交多个script
标签。
查看提交结果,发现只有第一个<script>
的尖括号被编码了,而且由于第一个</script>
是结束标签,起始标签被编码后 无法与其配对,所以会消失。
而后面两个script
标签的尖括号未被编码,说明应用程序只进行了一次编码。
还记得刚刚的escapeHTML
函数吗?
function escapeHTML(html) {
return html.replace('<', '<').replace('>', '>');
}
2
3
在某篇文章 (opens new window)中提到,replace
只能替换匹配到的第一个字符:
那就好办了,在原有的载荷前面添加一个额外的标签,先让其把replace
的第一次替换给消耗掉,后面的标签就能够正常解析。
提交载荷之后查看结果,前面的标签消耗掉第一次替换,后面的标签虽然没有被编码,但 alert 函数依然没有被调用,为什么?
在前面的理论知识中提到:innerHTML
接收器不接受任何现代浏览器上的script
元素,也不会触发svg onload
事件。这意味着你需要使用其他替代元素,如img
或iframe
。
懂了吧?
前面的消耗性标签不变,将后面的script
载荷更换为img
载荷。
<script><img src=1 onerror=alert(5)>
提交之后,回到博客页面,可以看到 alert 函数被成功调用了。
实验完成。