1586 字
8 分钟
PolarisCTF
2026-03-31

1.ezpollute#

进入比赛先挑了道简单题上手,一看题目 expolute,附件又是个 js 文件,猜测就是 node.js 原型链污染,md 这比赛怎么感觉好几道原型链污染沙箱逃逸的题目

打开附件看到 merge 方法就知道原型链污染没跑了

复习一下 node.js 原型链中 merge 方法是怎样污染的,merge 方法通过递归比较源对象与目标对象的属性,如果相同就替换目标对象的属性,又因为 node.js 中存在原型链,通过这条原型链我们可以沿着链子一直找上 Obiect 对象,通过构造相同属性名称来污染我们想要控制的属性

找到/api/status 路由

显示创建了一个空对象,没有原型链也就污染不了 全局属性

然后对父进程的环境变量进行遍历操作,将其拷贝进子进程的环境变量中,而 NODE_OPTINS 这个环境变量在 Node.js 程序启动时会自动读取这个变量并执行内容的指令

代码对 node_options 的输入内容进行过滤,但是可用短标签-r 绕过

const proc = spawn('node', ['-e', 'console.log("System Check: Node.js is running.")'], {//spawn新开一个进程执行命令,node -e 执行一段js代码
env: customEnv,//设置子进程的环境变量为customEnv,污染后的环境变量
shell: false
});

spawn 启动一个新的子进程,并设置环境变量为 custmEnv,所以只需要控制环境变量 node_options 的值为我们想要执行的命令就能在启动子进程时自动执行,回到 merge 方法中,我们只需要控制 payload 中存在参数名为 NODE_OPTIONSJ 就能污染全局参数 NODE_OPTIONS

payload:{“constructor”:{“prototype:{“NODE_OPTIONS”:“-r /flag”}}

jb 的有点酣畅淋漓了

2.only real#

开局一个登录框,先查看源码暴漏了用户信息,直接登录一手

一个疑似文件上传的界面,前端禁止了上传文件,直接改,但是点击上传后没有回显路径

扫一下目录,直接出现了 flag.php,出题人失误这居然是真 flag,复现时直接忽略了,我说怎么开始做的时候明明好像不难的

抛开 flag.php 不谈,来看看其他路径,值得注意的有 upload.php,/uploads,/static

首先访问 upload.php,没有东西,只回显上传成功,以为消遣我呢

又看了下/uploads,/static,显示 403,说明存在但没有权限,想到上传的文件有没有可能就存在这两个目录下,直接访问传命令发现行不通

想了很久还是不知道怎么入手,中间还是试图爆破了一下 jwt,以为会有 xm,xmctf 这样的弱密钥,然并卵

求助 agent,发现可以直接在 upload.php 构造出一个上传文件的请求,md 我怎么没想到,虽然空白但是我们可以自己造啊,所以说这题的意思是前端封禁了文件上传接口,但是后端却暴漏了?

尝试上传文件,发现不能上传.php 文件,绕过也不行,直接上传.jpg 文件的话没有文件包含等可利用点,执行不了代码

尝试上传.htaccess 文件,使服务器将.jpg 后缀的当作 php 代码解析

上传成功!访问 /uploads/shell.jpg 也成功!!,但是当我传命令时会回显 500,检查了一下语法应该没有错误,考虑是不会 eval 被封禁了?

尝试直接回显 phpinfo()的内容,回显成功,说明我们的代码的确被执行,eval 很可能的确被封禁,查看 disable-funcrion 却显示 no value ,何意味?

不管了,换个执行命令的函数 shell_exec 试一下

拿下 shell!!!复现找了半天 flag,结果就在 flag.php,我真会谢

3.ezopython#

又出一道原型链污染吗?比 node.js 那道还要简单很多,应该先做这道题的

payload:{“config”:{“filename”:“/flag”}}

秒了,注意把 content-type 换成application/json 就行

4.DXT#

一个简单的 mcp-server

询问 ai 了解一下.dxt 文件格式

.dxt 是 antropic 推出的插件包格式,本质上是一个压缩包,包含 mcp 服务器及所有依赖

文件结构:

extension.dxt (本质是ZIP)

├── manifest.json ← 核心配置文件(重点攻击面)

├── server/

│ ├── index.js ← MCP服务器主程序

│ └── node_modules/ ← 依赖包

└── icon.png

manifest.json:

{

“name”: “my-extension”,

“version”: “1.0.0”,

“server”: {

“type”: “node”,

“entry_point”: “server/index.js”, ← 指定入口文件

“mcp_config”: {

“command”: “node”,

“args”: [”${__dirname}/server/index.js”], ← 命令参数

“env”: {

“API_KEY”: ”${user_config.api_key}” ← 环境变量注入

}

}

}

}

5.AutoPypy#

一个沙箱逃逸的题目

查看附件中的 launcher.oy

启动了一个沙箱隔离的脚本,规定了沙箱的根目录和挂载的宿主机的目录

看了一下 server.py 的内容,发现存在一个漏洞点,/upload 路径有一个文件上传内容,但是并没有对上传的文件名进行过滤,直接拼接了用户输入的 filename,立马想到 launcher.py 中限制了沙箱可以执行的目录范围,那么是否可以通过目录穿越来上传文件到本不可访问的宿主机的目录执行危险代码呢?感觉逻辑闭环了

尝试上传了一个探测文件,发现并没有对函数模块什么的做什么限制,也是,代码里面也没过滤

尝试目录穿越,好消息是的确没有过滤,的确可以目录穿越,但是尝试上传到其他目录时显示权限不足,尝试多加几个../也绕不开,权限不足说明的确可以穿越只是我们对当前路径没有写的权限,所以可以尝试哪些路径具有可写的权限?并且要完成我们的目标,执行一段代码

还是有点没招,询问了 agent 后说可以尝试写入 site-packages/sitecustomize.py 中,site-packages 是 python 的包安装路径,在 python 启动时会自动 import sitecustomize.py 和 usercustomize.py 两个模块,一个由 root 权限执行,一个由普通用户执行

由前面知道上传的路径为/app/uploads/,使用../../到宿主机根目录

最终 payload: ../../usr/local/lib/python3.10/site-packages/sitecustomize.py(usercustomize.py 也可以)

又尝试了一下发现.pth 也能利用成功,但要注意.pth 对文件内每行内容执行命令,sitecustomize.py 是作为整个模块一起导入

使用.pth 时:import os;os.system(‘cat /flag’)

PolarisCTF
https://lab404.cn/posts/polaris-ctf/
作者
见山
发布于
2026-03-31
许可协议
CC BY-NC-SA 4.0