从后门到修复:Webmin CVE-2019-15107 漏洞的完整时间线分析
Webmin 是一个基于 Web 的 Unix/Linux 系统管理工具。它允许管理员通过浏览器图形界面完成配置 Apache 虚拟主机、管理用户账户、设置 Cron 任务等操作,降低了非专业运维人员的门槛。
Webmin 默认监听 10000 端口,通过 HTTPS 提供服务,以 root 权限运行。一旦 Webmin 被攻破,攻击者即获得服务器最高权限。根据网络空间测绘引擎数据,2019 年漏洞曝光时全球有超过 13 万台 Webmin 服务器暴露在互联网上。
Webmin 架构特点值得注意。它完全用 Perl 编写,由大量 CGI 脚本组成。这种架构模块化程度高,但每个 CGI 脚本都可能成为攻击面,且 Perl 代码的安全审计资源相对较少。
提示:如果仍在 Webmin,建议检查版本号。虽然 CVE-2019-15107 已过多年,但老版本可能还存在其他未公开漏洞。最好的做法是升级到最新版本,或者考虑替代方案如 Cockpit、Usermin 等。
事件起点:异常漏洞报告的浮现
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 会先执行 id 命令,然后把输出作为错误信息的一部分。
但事情蹊跷的地方在于,这个漏洞的触发条件相当特殊。研究人员很快发现,要成功利用需要满足几个前提:
- Webmin 必须开启'密码重置'功能(默认关闭)
- 使用的用户不能是系统用户(如 root)
- 新旧密码需要符

