Mike-Boya

Information Security and Programming Blog

Exploit Exercises - Nebula Level11

Level11 provides us with the source code for level11.c:

      #include <stdlib.h>
      #include <unistd.h>
      #include <string.h>
      #include <sys/types.h>
      #include <fcntl.h>
      #include <stdio.h>
      #include <sys/mman.h>

      /*
       * Return a random, non-predictable file, and return the file descriptor for it.
       */

      int getrand(char **path)
      {
        char *tmp;
        int pid;
        int fd;

        srandom(time(NULL));

        tmp = getenv("TEMP");
        pid = getpid();

        asprintf(path, "%s/%d.%c%c%c%c%c%c", tmp, pid,
            'A' + (random() % 26), '0' + (random() % 10),
            'a' + (random() % 26), 'A' + (random() % 26),
            '0' + (random() % 10), 'a' + (random() % 26));

        fd = open(*path, O_CREAT|O_RDWR, 0600);
        unlink(*path);
        return fd;
      }

      void process(char *buffer, int length)
      {
        unsigned int key;
        int i;

        key = length & 0xff;

        for(i = 0; i < length; i++) {
            buffer[i] ^= key;
            key -= buffer[i];
        }

        system(buffer);
      }

      #define CL "Content-Length: "

      int main(int argc, char **argv)
      {
        char line[256];
        char buf[1024];
        char *mem;
        int length;
        int fd;
        char *path;

        if(fgets(line, sizeof(line), stdin) == NULL) {
            errx(1, "reading from stdin");
        }

        if(strncmp(line, CL, strlen(CL)) != 0) {
            errx(1, "invalid header");
        }

        length = atoi(line + strlen(CL));

        if(length < sizeof(buf)) {
            if(fread(buf, length, 1, stdin) != length) {
                err(1, "fread length");
            }
            process(buf, length);
        } else {
            int blue = length;
            int pink;

            fd = getrand(&path);

            while(blue > 0) {
                printf("blue = %d, length = %d, ", blue, length);

                pink = fread(buf, 1, sizeof(buf), stdin);
                printf("pink = %d\n", pink);

                if(pink <= 0) {
                    err(1, "fread fail(blue = %d, length = %d)", blue, length);
                }
                write(fd, buf, pink);

                blue -= pink;
            }

            mem = mmap(NULL, length, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
            if(mem == MAP_FAILED) {
                err(1, "mmap");
            }
            process(mem, length);
        }

      }

“There are two ways of completing this level, you may wish to do both :-)” - That sounds cool. Let’s take a look.

Sorry folks, but this one completely stumped me. I thought I had a working exploit but could not successfully run getflag.

    level11@nebula:~$ export TEMP=/tmp
    level11@nebula:~$ python foobar.py | /home/flag11/flag11
    python foobar.py | /home/flag11/flag11
    blue = 1024, length = 1024, pink = 1024
    getflag is executing on a non-flag account, this doesn't count

I believe the issue has to do with system(), this excerpt from the man page appears to confirm my suspicion:

“system() will not, in fact, work properly from programs with set-user-ID or set-group-ID privileges on systems on which /bin/sh is bash version 2, since bash 2 drops privileges on startup.”

    level11@nebula:~$ bash --version
    bash --version
    GNU bash, version 4.2.10(1)-release (i686-pc-linux-gnu)
    Copyright (C) 2011 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
    This is free software; you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.

I did take a look around at other solutions and could not find a recent write-up that had success with this level.

If anyone has better luck or a solution, let me know on Twitter!

Thanks!

Mike