From babdb36578a83993fdb393aa32f3a122fa44a47e Mon Sep 17 00:00:00 2001 From: Jeremy Rossi Date: Mon, 8 Sep 2014 21:34:15 -0400 Subject: [PATCH] Fix for CVE-2014-5284 which allows for root escalation via temp files This includes a fix for the Security Issue identified by Jeff Petersen of Roka Security LLC. Full details of the issue are attached to this commit message. This correct will create the temp file for the hosts deny file in /var/ossec and will use mktemp where available to create NON-predictable temp file name. In cases where mktemp is not available we have written a *BAD* version of mktemp, but should be a little better then just process id. ============================= Researcher Info ============================= Jeff Petersen Roka Security LLC jpetersen@rokasecurity.com OSSEC 0.5 (released 11/2005) - 2.8 Affected code: All know version SHA1 checksum: 1d72a8cd347379ef7a533ba9633231c5bfedfa1a ossec-hids-2.8.tar.gz OSSEC v2.8 provides a utility named "host-deny.sh" which may be used to add and remove IP addresses from the /etc/hosts.deny file. For example, too many unsuccessful attempts to log into the shell as root via sshd can trigger an automatic block of the offending IP address if the "active response" system is enabled (the default configuration option has it enabled). The IP address is then automatically removed after the block has expired (default is 600 seconds). The logic for the removal can be found in ossec-hids-2.8/active-response/host-deny.sh and is as follows: 111 # Deleting from hosts.deny 112 elif [ "x${ACTION}" = "xdelete" ]; then 113 lock; 114 if [ "X$UNAME" = "XFreeBSD" ]; then 115 cat /etc/hosts.allow | grep -v "ALL : ${IP} : deny$"> /tmp/hosts.deny.$$ 116 mv /tmp/hosts.deny.$$ /etc/hosts.allow 117 else 118 cat /etc/hosts.deny | grep -v "ALL:${IP}$"> /tmp/hosts.deny.$$ 119 cat /tmp/hosts.deny.$$ > /etc/hosts.deny 120 rm /tmp/hosts.deny.$$ 121 fi [???] As shown above on lines 115 and 118, a predictable filename is written to the /tmp directory in the format of "/tmp/hosts.deny." followed by the process ID. Then the contents of the file are copied back to the /etc/hosts.deny file. This presents a race condition that any local user can perform: 1) create the /tmp/hosts.deny.$$ file first 2) wait for root to overwrite the file 3) write your own data to the file before it is copied to /etc/hosts.deny Though the window of attack is very small, this attack has been 100% reliable on a test system by monitoring the file via inotify(7). In addition to the previous information that was sent, it should be noted that this vulnerability can result in command execution as the root user via the "twist" option (see hosts_options(5) for more info). An example from my proof of concept is below. Now whenever anyone connects to sshd on the host, the command "id | wall" will be executed as root. --- active-response/host-deny.sh | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/active-response/host-deny.sh b/active-response/host-deny.sh index 9a68700ab..d29aa69fe 100755 --- a/active-response/host-deny.sh +++ b/active-response/host-deny.sh @@ -111,13 +111,18 @@ if [ "x${ACTION}" = "xadd" ]; then # Deleting from hosts.deny elif [ "x${ACTION}" = "xdelete" ]; then lock; + TMP_FILE = `mktemp /var/ossec/ossec-hosts.XXXXXXXXXX` + if [ "X${TMP_FILE}" = "X" ]; then + # Cheap fake tmpfile, but should be harder then no random data + TMP_FILE = "/var/ossec/ossec-hosts.`cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -1 `" + fi if [ "X$UNAME" = "XFreeBSD" ]; then - cat /etc/hosts.allow | grep -v "ALL : ${IP} : deny$"> /tmp/hosts.deny.$$ - mv /tmp/hosts.deny.$$ /etc/hosts.allow + cat /etc/hosts.allow | grep -v "ALL : ${IP} : deny$"> ${TMP_FILE} + mv ${TMP_FILE} /etc/hosts.allow else - cat /etc/hosts.deny | grep -v "ALL:${IP}$"> /tmp/hosts.deny.$$ - cat /tmp/hosts.deny.$$ > /etc/hosts.deny - rm /tmp/hosts.deny.$$ + cat /etc/hosts.deny | grep -v "ALL:${IP}$"> ${TMP_FILE} + cat ${TMP_FILE} > /etc/hosts.deny + rm ${TMP_FILE} fi unlock; exit 0;