TryHackMe 的 Source 房间的解题报告及一个用于利用此漏洞的 Python 脚本
我不对发现此漏洞的行为表示认可。感谢以下人员提供了资源,让我这样的人可以学习!
漏洞发现者:
Özkan Mustafa Akkuş
MSF 模块:
https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/linux/http/webmin_backdoor.rb
https://www.rapid7.com/db/modules/exploit/linux/http/webmin_backdoor/
MSF 模块作者:
wvu
TryHackMe 房间:
https://tryhackme.com/room/source
THM 作者:
https://tryhackme.com/p/DarkStar7471
资源:
https://www.webmin.com/exploit.html
https://github.com/webmin/webmin/issues/947
https://www.perlmonks.org/?node_id=301355
我绝不是一位经验丰富的安全专家。这意味着我可能会提供一些错误的信息。如果你是一位经验丰富的专业人士/研究员,并且发现了一些错误,请告知我,这样我就能回来学习我错在哪里并提供正确的信息。这对我以及可能偶然发现这份报告的初学者研究者都有好处。如果你发现我写的内容有误,请通过 [email protected] 联系我,以便我进行修正。谢谢!
1. 历史
Webmin 是一个基于 Web 的类 Unix 系统管理工具。在 2018 年第一季度左右,Webmin 遭遇了一次供应链攻击,一位未知攻击者成功将恶意代码插入到 password_change.cgi 文件中,从而创建了一个漏洞,允许在运行默认配置的特定版本 Webmin(1.890)的系统上开后门。我称之为供应链攻击,因为该软件的开发者/分发者的源代码被破坏了。当供应商发布被破坏的软件时,所有更新其软件的用户都将运行存在漏洞的代码,从而使攻击者能够破坏任何运行该漏洞代码的系统。同年,Webmin 开发者发现了这一问题,并将文件恢复到原始状态,然而攻击者再次将代码插入。这一次,只有在启用“更改过期密码”选项时,代码才会存在漏洞。这个漏洞直到 2019 年 8 月才被发现。该漏洞在 Webmin 1.930 版本中被修复。
2. 代码
经过一番搜索,我找到了使 Webmin 1.890 版本容易受到命令注入攻击的那行代码。我很难找到正确的信息,因为实际上有两个不同的 CVE 涉及此问题(CVE-2019-15231 / CVE-2019-15107)。CVE-2019-15231 与 1.890 版本的默认配置漏洞有关,而 CVE-2019-15107 与需要启用“更改过期密码”选项的漏洞有关,影响版本至 1.920。让我们看一下版本 1.890 的代码。在 password_change.cgi 的第 12 行,有以下一行代码:
$in{'expired'} eq '' || die $text{'password_expired'},qx/$in{'expired'}/;
截至撰写本文时,我从未写过任何 Perl 代码。我们将使用搜索引擎分解这行代码,以更好地理解它的功能以及为何容易受到利用。|| 操作符左侧的第一部分代码似乎是一个变量($in),它接收一个参数(expired)并检查它是否等于(eq)一个空字符串 ''。中间是 || 操作符。|| 是 Perl 中逻辑操作符 or 的另一种写法。使用 || 时,如果左侧为真,则不会评估右侧;如果左侧为假,则评估右侧。在 || 操作符右侧的第一部分代码中,我们看到 die $text{'password_expired'}。在 Perl 中,die 是一个函数,会终止脚本进程并显示一条错误消息。消息很可能来自变量 $text,内容为密码过期。代码的最后部分变得有趣。我们看到一个逗号 后跟 以及一个结束这行代码的分号 。逗号作为代码的分隔符,先评估左侧,然后评估右侧。在 Perl 中, 是一个允许在主机上执行系统命令的函数。 是分隔符,用于标识参数。在这种情况下, 会将 参数作为系统命令执行。我认为 变量可能类似于 PHP 中的 ,原因如下:在我编写的利用脚本中,有一个名为 的参数,用于在通过 POST 请求发送到服务器之前存储有效载荷。代码是这样的:。 变量肯定是在做某种事情来检索我们设置的 值,以便 函数可以执行有效载荷。总结一下这部分,存在漏洞的这行代码发现我们 POST 请求中的 参数不等于空字符串,因此 操作符将评估右侧的代码并执行我们存储在 参数中的有效载荷。让我们开始对 TryHackMe.com 的 Source 房间进行解题报告。
首先进行一次端口扫描。我们将使用 rustscan 进行广泛扫描,因为 nmap 可能非常慢。

看起来有两个端口开放:22 和 10000。现在我们使用 nmap 来确定每个端口上运行的服务。

所以 SSH 运行在标准端口上,而在端口 10000 上运行着 HTTP 服务。让我们导航到端口 10000 上的页面,看看那里有什么。

你需要使用 HTTPS 并绕过 SSL 证书警告才能访问此页面。看起来这是 Webmin 服务的登录页面。我最初做这个盒子时,尝试了几次目录暴力破解,但没有发现有趣的东西。让我们通过 searchsploit 检查我们通过 nmap 扫描获得的 Webmin 版本是否存在漏洞。

看起来有几个不同的选项,但都不匹配我们的版本。让我们打开 MSF 看看我们有什么可用的。

这里有几个不同的选项可供选择。让我们搜索我们通过 nmap 获得的 Webmin 版本,看看是否有相关的 CVE 可以帮助我们缩小范围。

在漏洞摘要中,我们看到它提到了关于 password_change.cgi 文件的内容。让我们使用 MSF 搜索结果中的第 5 个选项,因为它也提到了 password_change.cgi 文件以及相同的披露日期。

哈哈,我们实际上不会使用 MSF。MSF 很好,但用自己编写的代码来弄清楚如何利用漏洞更有趣!我使用 Ruby 源代码作为参考,用 Python 编写了自己的利用代码。让我们使用它吧!

Bada-bing Bada-boom,我们在房间中获得了 root shell!我不会透露 flag。我相信你能找到它们!感谢阅读,祝你愉快!
,qx/$in{'expired'}/;qx//qx/$in{'expired'}/$in{'expired'}$in$_GETexpireddata = {'expired':payload,}$inexpiredqxexpired||expired