从后门到修复:Webmin CVE-2019-15107漏洞的完整时间线分析
从后门到修复: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、Webmin的现代化分支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会先执行id命令,然后把输出作为错误信息的一部分。
但事情蹊跷的地方在于,这个漏洞的触发条件相当特殊。研究人员很快发现,要成功利用需要满足几个前提:
- Webmin必须开启“密码重置”功能(默认关闭)
- 使用的用户不能是系统用户(如root)
- 新旧密码需要符