01-system — Kimi 沙箱系统与容器层:OS、容器边界、s6 初始化树、用户权限、资源与网络

← 返回主报告:Kimi Agent(云端沙箱)技术报告GitHub 原文

合规与风险声明:本报告为安全研究与互操作学习目的的逆向分析,全程只读采集,未对目标系统做任何修改;文中所有密钥、token、账号级标识(chat_id / project_id / tenant_id 等)均已脱敏;沙箱内发现的默认弱口令(VNC/SSH)属平台侧配置,仅作安全发现披露,请勿用于访问任何不属于自己的系统。docx/pdf/xlsx/kimi-slides 等引擎二进制为 Moonshot 专有许可(禁再分发/逆向),本文仅作行为级描述。报告基于单次分析窗口(约 50 分钟生命周期),软件版本与技能库存随镜像更新可能变化。

采集时间:2026-08-18 08:14–09:26 UTC。来源:SSH 只读访问(kimi 用户,ssh -p 12222)+ root HTTP 兜底(http://127.0.0.1:18080/<绝对路径>)。所有路径均为沙箱内路径。 注意:沙箱在 09:26 UTC 左右被平台回收(frp 隧道 ssh-terminal 离线,三次重连均 Connection refused),少量收尾项未采集,见文末”未完成的取证缺口”。

1. OS 与内核:不是普通容器,是 cubevm 微虚拟机

  • 用户态:Debian GNU/Linux 12 (bookworm)(/etc/os-release)。
  • 内核:Linux 2d9b504a 6.6.69-cube.pvm.guest.005.x-g039db8913c80 #1 SMP PREEMPT_DYNAMIC Thu May 21 23:33:35 CST 2026 x86_64——定制 “cube.pvm.guest” 内核,明确是 guest 内核。
  • 虚拟化证据:
    • /sys/class/dmi/id/sys_vendor = Cube Hypervisorproduct_name = cube-hypervisorsystemd-detect-virt = kvm
    • /proc/cmdlineroot=/dev/pmem0 rootflags=dax,errors=remount-ro ro rootfstype=ext4 panic=1 console=hvc0 net.ifnames=0 cubevm ... clocksource=kvm-clockpmem0+DAX、hvc0 virtio-console、cubevm 标记、mitigations=off 都是 Firecracker/Kata 类 microVM 典型特征。
    • 设备文件:/dev/pmem0/dev/pmem1/dev/vda~/dev/vdd/dev/vsock/dev/cubemsg0(宿主通信字符设备)、/dev/ndctl0/1/dev/hvc0-7。没有 /dev/kvm(guest 内不可嵌套)、没有 /dev/dri(无 GPU,kasmvnc 配置里 gpu.hw3d: false)。
  • 结论:所谓”沙箱容器”= Moonshot 自研 cubevm microVM(腾讯云基础设施,见网络节)里再跑一层容器。容器边界在 VM 之内。

2. 容器边界:cgroup v1 + overlay2,非 Docker 标准运行时

  • /.dockerenv/run/.containerenv 均不存在。
  • /proc/1/cgroupcgroup v1(12 个控制器单独挂载到 /sys/fs/cgroup/<ctl>),各控制器路径为 /default/<container-id>

2d9b504a104a439f9374a6374a236fa7(memory/cpu/cpuacct/devices/freezer/net_cls/net_prio 有容器级子组;pids/cpuset/blkio/hugetlb/perf_event 在根 /)。

  • 根文件系统是 overlay2:61 个 lower 层 /run/blk-cube/vdc/0..60,upperdir=/run/blk-cube/vda/disk/<container-id>/upper——镜像层放在独立块设备 vdc、可写层在 vda,由宿主的 blk-cube 机制热挂进 VM。
  • tmpfs 覆盖 /etc/hosts/etc/resolv.conf/etc/hostname(运行时可写但不入镜像)。
  • 业务 FUSE 挂载(proc/mounts 摘录):
    • portal /mnt/portal-overlay fuse.portal ... allow_other(只读技能/插件 overlay,claim 时绑定)
    • drive9 /mnt/agents fuse.drive9 ... allow_other(可写工作区,详见 03-storage)
  • 主机名 = 容器 ID 前 8 位:2d9b504a;/etc/hosts 只有一行 127.0.0.1 localhost 2d9b504a
  • 环境标识文件:/run/e2b/.E2B_SANDBOX(5 字节标记文件,E2B 兼容信号,配合 envd 提供 E2B 协议命令执行)。

3. s6 初始化树与容器完整生命周期

3.1 引导链(/init → PID1)

/inits6-overlay v3.1.6.2 标准入口(1012 字节 shell):自举 PATH(/command、/bin、/usr/bin)后 exec s6-overlay-suexec preinit → /package/admin/s6-overlay-3.1.6.2/libexec/stage0。 stage0 调 s6-linux-init-maker 生成 basedir /run/s6/basedir,最终 exec 出 PID1:

PID 1: /package/admin/s6/command/s6-svscan -d4 -- /run/service

s6 套件全部静态安装在 /package/admin/:execline-2.9.4.0、s6-2.12.0.2、s6-linux-init-1.1.2.0、s6-overlay-3.1.6.2、s6-rc-0.5.4.2 等。 关机由常驻的 s6-linux-init-shutdownd -d3 -c /run/s6/basedir -g 3000 -C -B 接管(3 秒 kill 宽限)。

3.2 服务目录结构

  • 服务源定义/etc/s6-overlay/s6-rc.d/(编译进镜像);运行时编译结果在 /run/s6-rc/servicedirs//run/service/ 下以符号链接挂入扫描目录。
  • bundle user(s6-overlay 默认启动目标)的 contents:browser-guard、envd、kasmvnc、kernel-server、portal、socat、sshduser2 bundle 为空。各服务均无 dependencies.d(除 browser-guard 在脚本内用 s6-svwait -u /run/service/kasmvnc 做显示就绪等待)。
  • S6_LOGGING=0(容器环境),即 -B:无 catch-all 日志器,各服务日志直接到容器 stdout/stderr。
  • 镜像环境变量被 dump 到 /run/s6/container_environment/(每变量一个文件),各 run 脚本用 #!/command/with-contenv bash 继承——这是沙箱内所有服务环境变量的统一来源

3.3 各服务 run 脚本要点(原文已取证)

服务关键内容
envdexec envd -isnotfc。脚本内中文注释:AGS 不是 firecracker,无 MMDS(169.254.169.254 黑洞),-isnotfc 跳过 MMDS 探测,否则每次 /init 挂起 ~7s——这是针对非 firecracker 后端的定制补丁。提供 E2B 兼容命令执行通道。
portalGo 二进制 /usr/local/bin/portal -http-bind -allow-other -env prod -gateway-addr https://kimi-api-sandbox.msh.team/apiv2 /mnt/portal-overlay。注释说明:启动时是空 manifest,等 kimiwarden 在 claim 时 POST /api/v1/bind_token(HS256 JWT 换 STS)+ POST /api/v1/bind(overlay manifest:skills/plugins/auth/vault)。启用开关 KIMI_PROJECT_PORTAL_CAPABILITY_ENABLED=true 由 kimiwarden 注入。
kernel-servers6-setuidgid kimi python3 /app/kernel_server.py --host 0.0.0.0 --port 8888WORKDIR=${KERNEL_SERVER_WORKDIR:-/mnt/agents},注入 DISPLAY=:99HOME=/home/kimi(详见 02-runtime)。
kasmvncroot/bin/bash /root/setup_kasmvnc.sh:生成 kasmvnc.yaml、vncpasswd(明文 ‘password’),启动 Xvnc :99 -SecurityTypes None -rfbport 5901 -websocketPort 6080 -interface 0.0.0.0,用 snakeoil 自签证书。脚本主进程是 sleep infinity,Xvnc(PID 155)实为孤儿挂在 PID1 下。
browser-guards6-svwait 等 kasmvnc → s6-setuidgid kimi python3 /app/browser_guard.py --wait-display --display :99 --timeout 60 --monitor。它拉起 Chromium 151(--remote-debugging-port=9222 --remote-debugging-address=0.0.0.0 --no-sandbox --disable-blink-features=AutomationControlled --user-data-dir=/tmp/chromium_user_data,加载 /app/pdf-viewer 扩展,JS heap 限 512MB)。
socatexecline 单行:python3 /opt/moonbox-project-template/bin/project-cdp-proxy.py——CDP 代理,名字留自旧架构。
sshdexec /usr/sbin/sshd -D -e,无自定义配置目录(sshd_config.d 为空)。

3.4 claim 时注入的第二批服务(生命周期关键观察)

进程树时间戳显示:boot 于 08:36(s6 全家桶拉起),而 drive9-fusedrive9-fuse-watchdog 两个服务的 supervise 目录创建于 08:43——它们不是镜像 s6-rc 源,而是在沙箱被 claim(绑定具体项目)时由外部控制面直接写进 /run/service/

  • /run/service/drive9-fuse/run:重启前先 fusermount3 -uz 清残留死挂载(带防误删校验),source 环境文件后

exec drive9 mount --foreground --mode=fuse -allow-other --server http://10.213.5.144 --profile kimi-project --durability close-sync :/projects/<项目UUID> /mnt/agents,日志到 /tmp/kimi-project-drive9.log,自带 2 秒防抖动重启限速。

  • /run/service/drive9-fuse-watchdog/run:每 15s 探活(stat /mnt/agents/. + ls .drive9-health 小目录,避免大目录 readdir 触发预取),连续 3 次失败 pkill -9 -x drive9 交给 s6 重启,日志写同一文件。
  • 同时创建的还有 /run/kimi-project/preview.json(root:kimi 0440,claim 元数据)和两个 root 调试 http.server(18080 暴露 /tmp/project-probe、18082 绑 127.0.0.1——疑为控制面探针)。

完整生命周期:cubevm 微 VM 启动(pmem0 DAX rootfs)→ 容器层 overlay2 组装 → /init(s6-overlay) → s6-svscan → s6-rc 编译并拉起 7 个基础服务(envd/portal/sshd/kasmvnc/kernel-server/browser-guard/socat)→ 沙箱进入空闲池 → 用户会话 claim:kimiwarden 通过 portal 8080 下发 bind_token+manifest(skills overlay 挂上),同时把项目级 drive9-fuse + watchdog 服务注入 /run/service(工作区挂上)→ 会话结束沙箱回收(本次实测存活约 50 分钟,09:26 UTC 被回收)。

4. 用户与权限模型

  • 用户:kimi:x:999:995::/home/kimi:/bin/bash,仅属自己的组;root 正常存在;另有 Debian 常规系统用户(systemd-*、avahi、polkitd 等,来自镜像预装包)。kimi 不在 sudo 组
  • sudo:/etc/sudoers 是 Debian 原版(root + %sudo ALL),sudoers.d 只有 README;sudo -n true 实测 a password is required——kimi 无免密 sudo,事实上也无法 sudo(密码未设置)
  • /etc/shadow(经 18080 root 通道读取,已脱敏):root 有 yescrypt 哈希($y$j9T$KQhGRcPm...,仅记前 8 位);kimi:!(锁定,无密码)。其余系统账户全锁。
  • SSH:AllowUsers kimi(白名单只放行 kimi,PermitRootLogin yes 被其架空),PubkeyAuthentication + PasswordAuthentication 双开,sshd_config 里 SetEnv 给 SSH 会话注入 npm 镜像 NPM_CONFIG_REGISTRY=https://npm.mirrors.msh.team/ 和一条把各 skills 模板 node_modules/.bin 塞进前面的定制 PATH。
  • 提权辅助:不存在 /etc/s6/sudod 规则目录;s6-sudod 仅以 s6rc-oneshot-runner 的 IPC socket 形式存在(/run/s6-rc/servicedirs/s6rc-oneshot-runner,用于 root 跑 oneshot),与业务无关。
  • 权限分工总览:root 持有基础设施(s6、portal、drive9、Xvnc、sshd、envd);kimi 持有用户负载(kernel-server、browser-guard、Chromium、ipykernel)。工作区 /mnt/agents 由 kernel-server run 脚本 chown -R kimi:kimi

5. 资源限制(cgroup v1 实测值)

维度限制证据
内存4 GiB 硬限(4294967296 B),无 swap/sys/fs/cgroup/memory/memory.limit_in_bytes;free -h:total 3.9Gi、采集时已用 1.5Gi、buff/cache 2.2Gi
CPU配额 2 核(cfs_quota 200000/100000),可见 3 个逻辑核nproc=3;/sys/fs/cgroup/cpu/cpu.cfs_*
磁盘overlay 根 41G(可用 39G);/dev/shm 仅 64M;/mnt/agents 显示 1.0T(远端配额)df -h
进程数nproc ulimit 16152;pids 控制器未按容器挂载(无 pids.max 可读)ulimit -u
文件句柄nofile 1024(偏小,高并发 FD 型负载是潜在瓶颈)ulimit -n
其他core=0、stack 8M、locked memory 8Mulimit -a;/etc/security/limits.conf 为空

6. 网络

  • 接口(/proc/net/dev):loeth0dummy0sit0(dummy0/sit0 无流量,为内核默认残留)。
  • 编址(/proc/net/route 解码):eth0 为 169.254.68.4/30 链路本地段,默认网关 169.254.68.5——宿主侧 NAT,沙箱无真实内网地址。
  • DNS:/etc/resolv.conf(tmpfs,”Generated by NetworkManager”)指向 183.60.83.19183.60.82.98(腾讯 DNSPod 公共 DNS)。
  • 出站:可直连公网,未做 egress 过滤。实测 https://www.baidu.com 200、https://github.com 200;出口公网 IP 43.153.86.66(腾讯云)。SCF_POD_ID 环境变量进一步指向腾讯云 SCF/云函数宿主。
  • 内网依赖:drive9 存储服务端 http://10.213.5.144;portal 网关 https://kimi-api-sandbox.msh.team/apiv2;pip/npm 走 *.mirrors.msh.team 内网镜像。
  • 镜像精简到没有 ip、iptables、ss 命令(网络工具不预装,诊断只能靠 /proc)。
  • 对外暴露链路:sshd(22)/CDP(9222)/VNC(5901/6080)/portal(8080)/kernel(8888) 监听在容器 eth0,由沙箱内 frpc 反向连到我们的 frps(127.0.0.1:12222 等端口)——沙箱本身无入站 NAT 规则。

7. 时区与环境变量来源

  • 系统时钟/时区:/etc/localtime → Etc/UTC/etc/timezone=Etc/UTC,date 输出 UTC。TZ=Asia/Shanghai 只存在于容器环境变量(cubevm 平台注入),不改系统时区——业务进程见上海时区,系统日志见 UTC
  • 环境变量三级来源:
  1. 平台注入(cubevm/控制面 → /run/s6/container_environment → with-contenv → 所有 s6 服务):CUBE_CONTAINER_ID_SANDBOX/MONITOR_SIDECARSCF_POD_IDKIMI_PROJECT_PORTAL_CAPABILITY_*MOONBOX_BASE_IMAGE=msh-sandbox.tencentcloudcr.com/kimiclaw/moonbox-okc:project-20260811-2SSH_PASSWORDVNC_PASSWORD 等。
  2. sshd SetEnv:SSH 会话专属(npm 镜像、含 skills 模板 bin 的 PATH)。注意 SSH 会话的 PATH 与 s6 服务的 PATH(/command 开头)不同。
  3. 服务 run 脚本内 export:如 kernel-server/browser-guard 的 DISPLAY、HOME、XAUTHORITY。
  • 容器环境里 HOME=/root(镜像遗留),但各服务脚本显式覆盖成 /home/kimi;直接 SSH 进 kimi 时 HOME 正常。
  • /proc/1/environ 对 kimi 不可读,经 root HTTP 通道读到为空——PID1 (s6-svscan -d4) 启动时环境已被 stage0 清理,敏感值只留存在 container_environment 文件(kimi 可读)。

8. 密钥/凭据盘点(全部脱敏)

凭据位置格式/状态用途
SSH_PASSWORD/run/s6/container_environment/SSH_PASSWORD11 字符明文,kimi 可读平台注入的 kimi SSH 密码(与 shadow 中 kimi:! 不一致,疑供控制面它用)
VNC_PASSWORD同上11 字符明文VNC/web 桌面访问密码(Xvnc 实际 -SecurityTypes None,疑给 web 层用)
root 密码哈希/etc/shadowyescrypt $y$j9T$KQhGRcPm...root 本地登录
kasmvnc 密码/root/setup_kasmvnc.sh 内嵌字面量 ‘password’vncpasswd 初始化(实例密码文件 /root/.vnc/passwd、/root/.kasmpasswd)
Xauthority/root/.Xauthority、/home/kimi/.XauthorityMIT cookieX 显示访问
TLS 私钥/etc/ssl/private/ssl-cert-snakeoil.key自签 snakeoilkasmvnc websocket TLS
portal bind_token运行时由 kimiwarden POST 到 portal :8080HS256 JWT(未落盘可见)claim 时换 STS,授权 overlay 挂载

9. 未完成的取证缺口(沙箱 09:26 UTC 被回收导致)

  • stage0 尾部与 /run/s6/basedir/scripts/rc.init(s6-rc 拉起 user bundle 的确切调用)未抓到原文;§3 的引导链结论基于 s6-overlay 3.1.6.2 标准行为 + 已取证片段。
  • 监听端口全量清单(/proc/net/tcp 解码)未取回;已知端口来自进程参数与既有架构知识。
  • shell 级环境来源(/etc/profile.d/*、/home/kimi/.bashrc)未读取。
  • /opt/moonbox-project-template/ 模板内容(socat 实际执行的 CDP 代理)未深入——留给对应章节。

10. 对 Hermes 的可移植性速评

  • s6-overlay 标准容器初始化(/init→stage0→s6-rc bundle user + with-contenv 环境分发)可直接照搬,Hermes 若要多服务编排这是最省事且久经考验的方案;服务 run 脚本的 s6-setuidgid 降权 + s6-svwait 依赖等待模式值得复刻。
  • “启动时空 manifest、claim 时绑定”的两阶段生命周期(portal bind_token → drive9-fuse 注入 /run/service)是池化沙箱的关键设计:镜像与环境无关,项目身份延迟绑定——Hermes 要做沙箱池,这套模式价值最高。
  • envd -isnotfc 补丁说明 Kimi 沙箱抽象层兼容 E2B API 但后端换成了自研 cubevm;Hermes 若复用 E2B 协议,注意元数据服务探测必须可开关。
  • nofile=1024、/dev/shm=64M、2 核/4G 的限额是低成本高密度取舍,浏览器场景已踩到边缘(Chromium 限 JS heap 512M),Hermes 容量规划可参考。