Webmin CVE-2019-15107 漏洞深度解析:从后门到修复
2019 年,Webmin 因一个编号为 CVE-2019-15107 的漏洞在安全圈引发了广泛关注。这个看似普通的系统管理工具背后,隐藏着一段从后门植入到最终修复的完整故事。今天我们就来深入聊聊这个漏洞背后的技术细节,看看从代码审计到修复方案,中间到底发生了什么。
1. 序幕:Webmin 是什么,为什么它如此重要
在深入时间线之前,得先搞清楚 Webmin 到底是个什么东西。简单来说,Webmin 是一个基于 Web 的 Unix/Linux 系统管理工具。想象一下,你管理着几十台服务器,每台都要通过 SSH 命令行去配置用户、设置防火墙、管理服务——这活儿既繁琐又容易出错。Webmin 的出现,就是要把这些管理任务都搬到浏览器里,通过直观的图形界面来完成。
我最早接触 Webmin 是在 2015 年,当时接手了一个小公司的服务器运维工作。那家公司没有专职的运维人员,几个开发人员轮流管理服务器,水平参差不齐。有人建议上 Webmin,理由是'点几下鼠标就能搞定,不用记那么多命令'。确实,对于非专业运维人员来说,Webmin 降低了门槛:配置 Apache 虚拟主机、管理用户账户、设置 Cron 任务,这些原本需要一定 Linux 基础的操作,在 Webmin 里变成了表单和按钮。
但便利性往往伴随着风险。Webmin 默认监听 10000 端口,通过 HTTPS 提供服务,需要管理员账号密码登录。听起来挺安全,对吧?问题在于,很多中小企业的管理员为了方便,要么使用弱密码,要么干脆把 Webmin 暴露在公网上,还不做访问限制。更关键的是,Webmin 本身是以 root 权限运行的——这意味着一旦 Webmin 被攻破,攻击者就拿到了服务器的最高权限。
根据 Shodan 等网络空间测绘引擎的数据,在漏洞曝光的 2019 年,全球有超过 13 万台 Webmin 服务器暴露在互联网上。这个数字可能还只是冰山一角,因为很多服务器部署在内网,外部扫描不到。这些服务器中,有企业用于管理内部基础设施的,有云服务商提供给客户的托管面板,甚至还有一些教育机构用来管理实验室机器。
Webmin 的架构特点也值得注意。它完全用 Perl 编写,这在上世纪 90 年代末期项目启动时是个合理的选择,但到了 2019 年,Perl 的流行度已经大不如前。整个系统由大量 CGI 脚本组成,每个管理模块对应一个或多个脚本。这种架构的优点是模块化程度高,容易扩展;缺点也很明显:每个 CGI 脚本都可能成为攻击面,而且 Perl 代码的安全审计相对 PHP、Java 等语言来说,专业的安全研究人员更少。
提示:如果你现在还在使用 Webmin,强烈建议检查版本号。虽然 CVE-2019-15107 已经过去多年,但老版本可能还存在其他未公开的漏洞。最好的做法是升级到最新版本,或者考虑替代方案如 Cockpit、Usermin 等。
2. 事件起点:异常漏洞报告的浮现
时间来到 2019 年 8 月 10 日,这一天在 Pentest 博客上出现了一篇关于 Webmin 漏洞的详细分析。作者声称在 Webmin 的密码重置功能中发现了一个无需身份验证的远程命令执行漏洞,影响版本为 1.920 及之前。漏洞位于 password_change.cgi 文件中,攻击者可以通过向该页面发送特制的 POST 请求,在 old 参数中注入系统命令。
初看之下,这像是一个典型的输入验证漏洞。安全研究人员在审计代码时发现,password_change.cgi 在处理用户修改密码请求时,会检查旧密码是否正确。如果旧密码错误,程序会调用 pass_error 函数显示错误信息。问题就出在这个函数调用上:
$enc eq $wuser->{'pass'} || &pass_error($text{'password_eold'}, qx/$in{'old'}/);
第二行代码中,qx/$in{'old'}/ 是 Perl 中执行系统命令的语法,相当于反引号。正常情况下,这里应该只是把用户输入的旧密码作为错误信息的一部分显示出来。但代码编写者(或者说,修改者)犯了一个致命错误:他们直接把用户输入的 $in{'old'} 放进了 qx// 操作符中。这意味着如果攻击者在 old 参数中传入 | id 这样的值,Perl 会先执行 命令,然后把输出作为错误信息的一部分。

