title: How can I use the set-guid (i.e., set group identification) vulnerability to execute a file with limited permissions?
body: <p>How can I use the set-guid bit vulnerability to execute a file <code>/bin/grade</code> which is owned by <code>root</code> 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 &amp; execute only. For the file <code>/bin/grade</code>, I only have read access, but I want to execute it as group bsp*.</p>
  
  <pre><code>-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
  </code></pre>
  
  <p>The 3 programs are binaries which contain the following C code:</p>
  
  <p>//prog2:</p>
  
  <pre><code>int main(int argc, char **argv)
  {
    /* set up command buffer */
    char cmdbuf[128] = "export IFS=' \t\n'; /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 != '\0'; ++input) {
      switch (*input) {
      case '|': case '&amp;':
      case '&lt;': case '&gt;':
      case '!': case '$':
      case ';':
        *input = ' ';
        break;
      }
    }
  
    /* execute command */
    system(cmdbuf);
  
    return 0;
  }
  </code></pre>
  
  <p>//prog3:</p>
  
  <pre><code>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) &gt; len)
      progname[len] = '\0';
    strcat(cmdbuf, progname);
  
    system(cmdbuf);
    exit(1);
  }
  
  void usage()
  {
    printf("%s &lt;n&gt; where 0 &lt; n &lt;= 5.000\n", 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(&amp;sa, sizeof(struct sigaction), 0);
    sa.sa_handler = handle_signal;
    sigaction(SIGINT, &amp;sa, NULL);
  
  
    /* process argument */
    progname = argv[0];
    if (argc != 2)
      usage();
    N = strtol(argv[1], NULL, 10);
    if ((N &lt;= 0) || (N &gt; 5000))
      usage();
  
  
    /* calculate prime numbers -- simple sieve */
    candidate = 1;
    for (cnt = 0; cnt &lt; N; ++cnt) {
  
      for (;;) {
        found = 1;
        divisor = 2;
        candidate += 1;
  
        while (divisor &lt;= candidate/2) {
          if ((candidate % divisor) == 0) {
            found = 0;
            break;
          }
          else
            ++divisor;
        }
        if (found)
          break;
      }
      printf("%ld\n", candidate);
    }
  
    return 0;
  }
  </code></pre>
  
  <p>//prog4:</p>
  
  <pre><code>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!\n\n");
    printf("Never think you've seen the last of anything. Eudora Welty\n\n");
  
    return 0;
  }
  </code></pre>