0×00 漏洞描述
近日Webmin被发现一处远程命令执行漏洞,经过分析后,初步猜测其为一次后门植入事件。
Webmin是目前功能最强大的基于Web的Unix系统管理工具。管理员通过浏览器访问Webmin的各种管理功能并完成相应的管理动作。据统计,互联网上大约有13w台机器使用Webmin。当用户开启Webmin密码重置功能后,攻击者可以通过发送POST请求在目标系统中执行任意命令,且无需身份验证。
0×01 漏洞分析
首先分析msf给出的插件
根据插件,还原出poc如下:
当poc执行后,回像password_change.cgi发送POST请求
接下来看下password_change.cgi
位于37行到188行处,存在if-else语句
他们分别是
1、if ($wuser)
2、elsif ($gconfig{\’passwd_cmd\’})
3、elsif ($in{\’pam\’})
4、else
我们需要确认,程序到底进入那个if分支了
我们先print $wuser
从上图打印结果看,wuser不为空,所以这里直接进入if ($wuser)分支
在if ($wuser)分支中,首先执行encrypt_password方法,如下图红框处
encrypt_password方法位于\acl\acl-lib.pl
该方法的底层,调用了crypt方法,如下图,位于acl/md5-lib.pl中
传入该crypt方法的第一个参数为$passwd
打印此时passwd
可见值为 AkkuS|dir,也就是POST请求中的old参数值
encrypt_password底层调用crypt进行编码后,将计算值return,赋值给$enc,如下图
由于我们传入的pass(AkkuS|dir)并不是root用户的密码,下图红框处的eq结果为false
因此触发pass_error,系统需要把Failed to change password : The current password is incorrect这个信息反馈给用户
但是注意上图红框处,在pass_error方法的传参中,$in{’old’}被 qx/ /包裹
了解下qx/ /在perl中的用法:
qx执行外部程序,相当于“
也就是说,$in{’old’}的值会被执行。$in{’old’}就是POST中传入的old参数,可控,所以这里造成了任意代码执行漏洞。
值得注意的是,POST中的old参数,是用户修改密码时所提交的旧密码。众所周知,密码是一个字符串,而非可执行代码,这里将传入的旧密码字符串拿来执行,并非正常业务逻辑所为。
不仅如此,$in{‘old’}的值在被执行后,会拼接在$text{‘password_eold’}参数后面,一同传入pass_error中,如下图
打印$text{‘password_eold’},查看它的值
当我们的$in{’old’}传入”AkkuS|dir”时,dir执行后的返回值会拼接到The current password is incorrect后,传入pass_error
接着,在pass_error中被打印出来
这里不仅仅将用户旧密码拿来执行,更是通过pass_error,把返回值直接打印到返回值中,更加落实了被植入后门的猜测
对比官网\ SourceForge\github三个不同地方下载的Webmin代码发现,官网\ SourceForge存在代码执行点,而github不存在
1、官网与SourceForge:
这里存在qx包裹的$in{‘old’}
再来看github上下载的同版本Webmin代码
Pass_error中竟然没有被qx包裹的$in{‘old’}
对比如下:
也就是说,github上下载的Webmin不存在代码执行漏洞,而官网和SourceForge上却存在
0×02 被植入后门依据
1、 将用户提交的旧密码通过qx直接执行
正常业务逻辑中旧密码为字符串,而非可执行代码,这里将密码字符串拿来直接执行,不符合逻辑
2、 将执行结果通过报错打印到返回值中
如果仅仅是执行代码,攻击者无法判断后台执行是否成功,以及无法得到执行成功后的返回值,例如”dir”、”ifconfig”这类指令,是需要看回显值得。因此,在这里通过pass_error将执行成功的返回值隐蔽的返回
3、 官网\ SourceForge代码中存在漏洞,github代码中无漏洞
通过以上三点,初步猜测,Webmin代码被移植入后门
0×03 POC无需管道符
目前业界流传的poc,都是需要使用管道符 “|”的形式:
例如msf给出的poc:”AkkuS|dir ”
但是经过漏洞深入的分析发现,old中的值最终会被直接执行,因此并不需要管道符
可以构造如下poc