0xsha/KindaRails2Shell

GitHub: 0xsha/KindaRails2Shell

针对 Rails Active Storage/libvips 任意文件读取漏洞(CVE-2026-66066)的零依赖单文件 PoC,集成文件读取、密钥恢复、条件性 RCE、扫描与本地实验环境。

Stars: 0 | Forks: 0

# KindaRails2Shell: CVE-2026-66066 一个零依赖、单文件的 PoC(概念验证)和仅限 loopback 的 Docker 实验环境, 用于验证 Rails Active Storage/libvips 的任意文件读取漏洞。它还 演示了安全公告中描述的、从恢复的 `secret_key_base` 到伪造图片变体及命令执行的条件性升级路径。 - 受影响版本:Rails 7.2.0–7.2.3.1, 8.0.0–8.0.5, 及 8.1.0–8.1.3 - 已修复版本:Rails 7.2.3.2, 8.0.5.1, 及 8.1.3.1 - 运行环境:Python 3.11+,仅使用标准库 - 适用范围:授权测试与本地研究 主要参考来源: [Rails 安全公告](https://github.com/rails/rails/security/advisories/GHSA-xr9x-r78c-5hrm)、 [Rails 取证分析](https://github.com/rails/rails-forensics-CVE-2026-66066)、 [Ethiack 技术分析文章](https://ethiack.com/info-hub/research/kindarails2shell-how-a-matlab-file-reads-your-secrets-and-pops-a-shell-on-ruby-on-rails)、 以及 [8.1.3.1 版本发布说明](https://github.com/rails/rails/releases/tag/v8.1.3.1)。 ## 演示 https://github.com/user-attachments/assets/fdcb5651-c1d1-4bc4-b322-8f1205b09635 ## 为什么这个 PoC 很有用 `kr2s.py` 在单个文件中包含了完整的客户端程序: - 内置可修改的 HDF5/MAT payload,无需依赖 `h5py` 或 `numpy`; - 支持直接上传交付及自动处理 CSRF; - 可从现有的 Active Storage 缩略图中提取变体密钥 (variation key); - 具备严格的标准库 PNG 解码器,确保字节级精确恢复; - 支持任意偏移量,且单次请求最多可读取 16 MiB; - 包含 secret 发现机制及纯 Python 实现的 Rails 变体签名工具; - 支持通过随机标记进行命令输出读取,并尽最大努力进行痕迹清理; - 支持多线程的被动或显式主动扫描,并输出 JSON 报告; - 支持 proxy、自定义路径、TLS、timeout 及 user-agent 控制。 该工具不会安装软件包、启动回调监听器、要求目标机器上存在 `curl`,也不依赖 `make`。RCE 阶段使用内置的 Active Storage 表现层路由 (representation route),不需要 Marshal gadget。 ## 快速开始 启动包含漏洞的实验环境: ``` cd lab RAILS_VERSION=8.1.3 docker compose up --build ``` Compose 端口绑定到 `127.0.0.1`,且容器以非特权用户身份运行,所有 Linux capabilities 均已被禁用。 在另一个终端中: ``` # Intrusive: 上传一个 blob,然后确认 /etc/hostname 是否可读。 python3 kr2s.py check http://127.0.0.1:3000 # 恢复固定大小的前缀。除非使用 -o,否则二进制输出将发送至 stdout。 python3 kr2s.py read http://127.0.0.1:3000 /etc/passwd --size 4096 python3 kr2s.py read http://127.0.0.1:3000 /etc/passwd -o passwd.bin # 恢复选定的 environment secrets。默认情况下,值会被遮盖。 python3 kr2s.py secrets http://127.0.0.1:3000 # 显示匹配的完整 environment 值以供授权分析。 python3 kr2s.py secrets http://127.0.0.1:3000 --show-full # 对一个目标或每行包含一个目标的文件进行 Passive 预检。 python3 kr2s.py scan http://127.0.0.1:3000 python3 kr2s.py scan targets.txt --threads 10 --json scan.json # Intrusively 确认列表中的每个目标均可读取文件。 python3 kr2s.py scan targets.txt --active # 探测选定的 libvips loaders。 python3 kr2s.py probe http://127.0.0.1:3000 # Conditional escalation。这将执行所提供的命令。 python3 kr2s.py rce http://127.0.0.1:3000 "id; uname -a" ``` 运行 `python3 kr2s.py COMMAND --help` 查看所有可覆盖的参数。针对真实应用程序的常用控制参数包括 `--harvest-url`、`--show-path`、`--proxy`、`--insecure` 和 `--skb`。 `secrets --show-full` 会打印完整匹配到的环境变量值。如果不提供该参数,工具将仅打印前 12 个字符及省略号。 使用 `--also-read` 请求的文件(包括默认的 Rails 凭据路径)在可读的情况下,最多会打印 600 个字符。 被动 `scan` 仅报告页面是否暴露了可提取的 Active Storage 表现层;它无法识别目标已安装的 Rails 补丁级别。 `scan --active` 会上传一个恶意 blob 并尝试执行 canary 读取。失败的主动扫描结果会被标记为 `BLOCKED_OR_INCONCLUSIVE`,而不是 `SAFE`,因为从应用程序外部来看,WAF、身份验证、不支持的变体以及 Rails 的修复机制表现出的行为可能完全相同。 使用以下命令停止实验环境: ``` cd lab docker compose down ``` ## 漏洞利用原理 1. 客户端申请一个被声明为 `image/png` 的 Active Storage 直接上传。 2. 它会上传一个混合型的 MATLAB/HDF5 文件。其中的 HDF5 dataset 使用了外部存储,其文件名和偏移量指向 Rails 进程中的某个文件。 3. 从现有的缩略图中提取一个由服务器签名的变体密钥,并将其与恶意 blob 的签名 ID 结合使用。 4. 存在漏洞的 Rails 会将数据传递给 libvips 的 `matload`;目标文件的字节会转化为图像像素,并在生成的 PNG 中返回。 5. 客户端验证并解码该 PNG,随后反转 matio 的列主序布局,从而恢复原始字节。 该混合文件同时满足了两种解析器的要求:其文本以 `MATLAB 5.0` 开头,而位于偏移量 124 处的版本字则选择了由 HDF5 支撑的 MATLAB 7.3 处理路径。Rails 的修复方案会在攻击者控制的文件触及 `matload` 之前,拦截所有标记为不受信任的 libvips 操作。 ## 条件性 RCE 除非提供 `--skb`,否则 `rce` 会首先从 `/proc/self/environ` 读取 `SECRET_KEY_BASE`。接着它会派生出 Active Storage 验证器密钥,并对包含 `instance_eval` 操作的 JSON 变体进行签名。在受影响的 vips 处理路径上,该操作会触达 `Vips::Image.public_send`。PoC 通过内置的表现层路由发送请求,利用 `/bin/sh` 执行提供的命令,并捕获两个输出流。 第二阶段的利用取决于能否成功恢复签名密钥,以及能否触达 Ethiack 在其对 [CVE-2025-24293](https://github.com/rails/rails/security/advisories/GHSA-r4mg-4433-c7g3) 的分析中所描述的、存在漏洞的 vips 转换行为。 CVE-2026-66066 的补丁关闭了文件读取的入口点;这并不是针对先前已泄露签名密钥的通用修复方案。如怀疑密钥已泄露,请按照 Rails 安全公告的建议轮换密钥。 命令输出会被写入一个随机的 `/tmp/.kr2s_*` 文件中,随后通过相同的文件读取漏洞原语进行恢复,最后通过第二个签名 payload 将其删除。 ## 读取行为与限制 读取操作将返回所请求的固定大小区域。如果源文件较短,则其前缀后会跟随零字节。请使用 `--offset` 获取后续区域的内容。 默认的实验环境变体仅执行 PNG 转换,因此可以做到字节级精确恢复。真实应用程序可能会调整变体的大小。已提取密钥的模式使用单像素列以避免水平重采样,但如果变体的高度较低,仍然可能改变图像几何结构。在这种情况下,客户端会显式报错;请减小 `--size` 或提取一个不执行调整大小操作的表现层。 执行的每条命令都具有侵入性:它会创建持久化的 Active Storage blob,并可能生成处理后的变体。`rce` 还会额外执行所提供的命令。 ## 版本矩阵 该矩阵脚本会构建每个发行版,对存在漏洞的版本执行真实的读取和 RCE 检查,断言已修复版本的读取行为被成功拦截,并在出现任何不匹配的情况时返回非零值: ``` ./lab/matrix.sh ./lab/matrix.sh 8.1.3 ./lab/matrix.sh 8.1.3.1:PATCHED ``` 于 2026-07-31 使用 Ruby 3.4.10、image_processing 1.14.0、ruby-vips 2.3.0 和 libvips 8.16.1 进行了验证: | Rails | 文件读取 | RCE 检查 | 结果 | |---|---|---|---| | 7.2.3.1 | `READ-OK` | `RCE-OK` | 通过 | | 7.2.3.2 | 拦截 | 未运行 | 通过 | | 8.0.5 | `READ-OK` | `RCE-OK` | 通过 | | 8.0.5.1 | 拦截 | 未运行 | 通过 | | 8.1.3 | `READ-OK` | `RCE-OK` | 通过 | | 8.1.3.1 | 拦截 | 未运行 | 通过 | 对于已打补丁的版本行,我们特意没有使用预先提供的签名密钥来触发 RCE payload;该矩阵测试的是 CVE 文件读取的边界。 ## 研究实用工具 `research/craft.py` 用于为加载器研究重新生成候选 payload,需要依赖 `h5py` 和 `numpy`。发布的 PoC 并不会导入该工具。 `lab/probe/probe.sh` 会在实验镜像内部使用 ruby-vips 检查这些候选项: ``` uv run --script research/craft.py all -o /tmp/kr2s-payloads docker run --rm \ -v "$PWD/lab/probe:/probe:ro" \ -v /tmp/kr2s-payloads:/payloads:ro \ --entrypoint /probe/probe.sh kr2s-rails:8.1.3 ``` 使用以下命令运行无依赖项的单元测试: ``` python3 -m unittest discover -s tests -v ``` ## 公开工作的出处 MAT/HDF5 payload 及无依赖的客户端是通过本地测试独立开发的。在公开的 PoC 出现后,此发布版本吸收了 [Zer0SumGam3 的 PoC](https://github.com/Zer0SumGam3/CVE-2026-66066-POC) 中记录的变体密钥提取技术及内置 Active Storage 路由。 此处的 Python 实现是原创的,且仅使用标准库。 早期版本演示了使用 `Puma::MiniSSL::Context` 和 ActiveSupport 代理通过签名的 Marshal payload 同样可以实现 RCE,这部分基于 [Behrad Taher 的公开 gadget 研究](https://behradtaher.dev/Hunting-for-Deserialization-Gadgets/)。 该路径避免了目标端的辅助二进制文件,但需要支持 Marshal 的签名 ID sink,以及已加载的 Puma 和 ActiveSupport gadget 类。在 Ethiack Research Team 发布了他们的 [KindaRails2Shell 技术分析文章](https://ethiack.com/info-hub/research/kindarails2shell-how-a-matlab-file-reads-your-secrets-and-pops-a-shell-on-ruby-on-rails) 后,该方法被替换。该文章记录了更简单的签名 JSON 变体技术,该技术使用原生路由并移除了上述先决条件。 漏洞发现归功于 André Baptista (0xacb)、Bruno Mendes (s3np41k1r1t0)、Rafael Castilho 和 Ethiack Research Team,以及 RyotaK (GMO Flatt Security)。Abdelmounaim Moulahcene (bl0rph) 在协调披露之前独立发布了底层的漏洞原语。有关维护者记录的完整时间线和致谢,请参阅 Rails 取证代码库。 ## 负责任使用与许可证 请仅在您拥有或已获得明确授权测试的系统上使用。作者不对任何滥用行为承担责任。有关报告此研究产物问题的信息,请参阅 [SECURITY.md](SECURITY.md)。 基于 [MIT License](LICENSE) 发布。
标签:IP 地址批量处理, PoC, Python, Ruby on Rails, 内存转储, 子域名变形, 无后门, 暴力破解, 网络安全审计, 请求拦截, 逆向工具