Visit our newest sister site!
Hundreds of free aircraft flight manuals
Civilian • Historical • Military • Declassified • FREE!


TUCoPS :: Linux :: Apps A-M :: lnx5926.htm

middleman off-by-one bug



12th Jan 2003 [SBWID-5926]
COMMAND

	middleman off-by-one bug

SYSTEMS AFFECTED

	middleman-1.2 and prior

PROBLEM

	qitest1 [http://bespin.org/~qitest1] found, credits to h2so4 :
	
	Middleman is a powerful proxy server  with  many  features  designed  to
	make browsing the Internet a more pleasant experience. It  can  do  much
	more than just proxying though; it can be used as a  layer  between  any
	web server and client to filter  HTTP  requests,  or  act  as  a  portal
	between an internal network and the Internet. It has  an  intuitive  Web
	interface that provides an  easy  way  of  accessing  and  changing  the
	proxy's configuration, there's no need to dig  through  any  complicated
	configuration files. (quoted from its README.html)
	
	 Vulnerability
	 =============
	
	The program is affected by an ebp corruption condition  in  the  routine
	performing the dns lookup of  the  hostname  provided  in  the  request,
	because its own implementation of strncpy  goes  off  by  one.  The  bug
	could be easily exploited by a remote attacker, leading to a root  shell
	if the daemon runs as root (it's really nice that  the  sample  rc  init
	file provided calls the daemon without  dropping  privileges,  which  is
	one of its features). If exploitation is not successful, it will  result
	in a denial of service, because the program will die at all.
	
	 Details
	 =======
	
	In src/misc.c:
	
	/*
	strncpy which always NULL terminates
	*/
	char *s_strncpy(char *d, char *s, size_t len)
	{
	        char *dest = d;
	
	        for (; len && (*dest = *s); s++, dest++, len--);
	        *dest = '\0';
	
	        return d;
	}
	
	No doubt. It always NULL terminates. But even off by one.
	
	In src/networks.c near line 614 we find:
	
	/*
	perform a dns lookup, using cached response from a previous lookup if possible
	*/
	HOSTENT *net_dns(char *host)
	{
	        time_t t;
	        char *string, hst[128], buf[24];
	        HOSTENT *hostent;
	
	Looking to this code we could think the memory layout on the  stack  for
	this function is the following:
	
	hst[128]		|
	string[4]		|
	t[4]			|
	ebp			|
	eip			V
	
	In src/networks.c near line 627 we find:
	
	        s_strncpy(hst, host, 128);
	
	We know that s_strncpy puts its  final  0x00  off  by  one.  This  fact,
	apparently, should not be a real problem, because the 0x00  byte  should
	be put on the lsb of string.
	
	Where is the bug?
	
	Due to compilation (maybe optimization), those variables  get  allocated
	in a different way:
	
	(I dumped this from the program)
	** net_dns(): &hst 0xbf7ff9f4 &string 0xbf7ff9d4 &t 0xbf7ff9d8
	
	So the real memory layout is:
	
	string[4]		|
	t[4]			|
	hst[128]		|
	ebp                     |
	eip                     V
	
	So we have ebp corruption. Let's have a memory dump:
	
	** net_dns(): 0xbf7ff9f4 -> 0xbfffc0d3 (0)
	** net_dns(): 0xbf7ff9f8 -> 0xbfffc0d3 (1)
	** net_dns(): 0xbf7ff9fc -> 0xbfffc0d3 (2)
	[...]
	** net_dns(): 0xbf7ffa70 -> 0xbfffc0d3 (31)
	** net_dns(): 0xbf7ffa74 -> 0xbf7ffa00 (32)
	** net_dns(): 0xbf7ffa78 -> 0x804db07 (33)
	
	At 0xbf7ffa78 we have 0x804db07: that's the eip. Indeed:
	
	(gdb) x 0x804db07
	0x804db07 <net_connect+75>:     0xc483c289
	net_connect() effectively calls net_dns()
	
	At 0xbf7ffa74 there is the corrupted ebp.
	At 0xbf7ffa00 + 4 the execution flow will search an eip:
	** net_dns(): 0xbf7ffa04 -> 0xbfffc0d3 (4)
	
	We can control the data contained at that address, which  can  obviously
	be a pointer to our code. But there's no need to explain here  how  this
	kind of vulnerability can be exploited: it's quite trivial.
	
	I think this kind of problems should be seriously valued,  because  they
	are difficult to be detected and prevented. But they can be  avoided  by
	simply checking that the program never goes off  by  one,  even  if  the
	buffer is not immediately before  the  ebp:  indeed  there  could  be  a
	condition like that I described.

SOLUTION

	Check freshmeat, apply the following patch :
	
	- --- middleman/src/misc.c	2002-10-19 19:07:24.000000000 +0200
	+++ middleman-patched/src/misc.c	2003-01-10 11:29:08.000000000 +0100
	@@ -27,17 +27,34 @@
	 #include <sys/types.h>
	 #include "proto.h"
	
	- -/*
	- -strncpy which always NULL terminates
	- -*/
	- -char *s_strncpy(char *d, char *s, size_t len)
	- -{
	- -	char *dest = d;
	- -
	- -	for (; len && (*dest = *s); s++, dest++, len--);
	- -	*dest = '\0';
	+	/* Adapted version of OpenBSD strlcpy */
	+char *
	+s_strncpy(dst, src, siz)
	+	char *dst;
	+	char *src;
	+	size_t siz;
	+{
	+	register char *d = dst;
	+	register const char *s = src;
	+	register size_t n = siz;
	+
	+	/* Copy as many bytes as will fit */
	+	if (n != 0 && --n != 0) {
	+		do {
	+			if ((*d++ = *s++) == 0)
	+				break;
	+		} while (--n != 0);
	+	}
	+
	+	/* Not enough room in dst, add NUL and traverse rest of src */
	+	if (n == 0) {
	+		if (siz != 0)
	+			*d = '\0';		/* NUL-terminate dst */
	+		while (*s++)
	+			;
	+	}
	
	- -	return d;
	+	return dst;
	 }
	
	 /*
	


TUCoPS is optimized to look best in Firefox® on a widescreen monitor (1440x900 or better).
Site design & layout copyright © 1986-2014 AOH