Mike-Boya

Information Security and Programming Blog

GoogleCTF - Spotted Quoll Write-Up

Intro

I participated in the Google CTF this weekend and really enjoyed the challenges. Here is a write-up of one of my solutions.

Challenge

Spotted Quoll was a web challenge worth 50 points. The details of the challenge are in the image below.

I loaded up the blog and looked for any clues:

GSE Results

It’s official, I received the email from SANS letting me know that I earned the GSE certification! I am GSE #141 in a group of impressive information security professionals.

There are a ton of people that I would like to thank, including co-workers and friends. I would also like to thank Chris Sanders (GSE #64) for just being awesome and fielding some of my questions. Lastly, I would like to thank my lovely fiancée, Sophie, for putting up with my constant study and the late nights where, in her own words, I am “in the Matrix.”

SANS Holiday Challenge 2015 - Writeup

Intro

The SANS Holiday Hack challenge this year was fantastic and I wanted to make sure to document my solutions on my blog. I have participated in the Holiday Hack Challenges since 2012, but haven’t documented them with the exception of some informal notes – maybe I should change that! Anyway, enjoy my write-up and I encourage anyone who did not participate to give it a try before reading this post!

Exploit Exercises - Nebula Level19

Level19 provides us with the following code:

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

    int main(int argc, char **argv, char **envp)
    {
      pid_t pid;
      char buf[256];
      struct stat statbuf;

      /* Get the parent's /proc entry, so we can verify its user id */

      snprintf(buf, sizeof(buf)-1, "/proc/%d", getppid());

      /* stat() it */

      if(stat(buf, &statbuf) == -1) {
          printf("Unable to check parent process\n");
          exit(EXIT_FAILURE);
      }

      /* check the owner id */

      if(statbuf.st_uid == 0) {
          /* If root started us, it is ok to start the shell */

          execve("/bin/sh", argv, envp);
          err(1, "Unable to execve");
      }

      printf("You are unauthorized to run this program\n");
    }

And this very detailed hint:

“There is a flaw in the below program in how it operates.”

…No way!!

Exploit Exercises - Nebula Level18

Level18 provides us with this large snippet of code:

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

    struct {
      FILE *debugfile;
      int verbose;
      int loggedin;
    } globals;

    #define dprintf(...) if(globals.debugfile) \
      fprintf(globals.debugfile, __VA_ARGS__)
    #define dvprintf(num, ...) if(globals.debugfile && globals.verbose >= num) \
      fprintf(globals.debugfile, __VA_ARGS__)

    #define PWFILE "/home/flag18/password"

    void login(char *pw)
    {
      FILE *fp;

      fp = fopen(PWFILE, "r");
      if(fp) {
          char file[64];

          if(fgets(file, sizeof(file) - 1, fp) == NULL) {
              dprintf("Unable to read password file %s\n", PWFILE);
              return;
          }
                    fclose(fp);
          if(strcmp(pw, file) != 0) return;
      }
      dprintf("logged in successfully (with%s password file)\n",
          fp == NULL ? "out" : "");

      globals.loggedin = 1;

    }

    void notsupported(char *what)
    {
      char *buffer = NULL;
      asprintf(&buffer, "--> [%s] is unsupported at this current time.\n", what);
      dprintf(what);
      free(buffer);
    }

    void setuser(char *user)
    {
      char msg[128];

      sprintf(msg, "unable to set user to '%s' -- not supported.\n", user);
      printf("%s\n", msg);

    }

    int main(int argc, char **argv, char **envp)
    {
      char c;

      while((c = getopt(argc, argv, "d:v")) != -1) {
          switch(c) {
              case 'd':
                  globals.debugfile = fopen(optarg, "w+");
                  if(globals.debugfile == NULL) err(1, "Unable to open %s", optarg);
                  setvbuf(globals.debugfile, NULL, _IONBF, 0);
                  break;
              case 'v':
                  globals.verbose++;
                  break;
          }
      }

      dprintf("Starting up. Verbose level = %d\n", globals.verbose);

      setresgid(getegid(), getegid(), getegid());
      setresuid(geteuid(), geteuid(), geteuid());

      while(1) {
          char line[256];
          char *p, *q;

          q = fgets(line, sizeof(line)-1, stdin);
          if(q == NULL) break;
          p = strchr(line, '\n'); if(p) *p = 0;
          p = strchr(line, '\r'); if(p) *p = 0;

          dvprintf(2, "got [%s] as input\n", line);

          if(strncmp(line, "login", 5) == 0) {
              dvprintf(3, "attempting to login\n");
              login(line + 6);
          } else if(strncmp(line, "logout", 6) == 0) {
              globals.loggedin = 0;
          } else if(strncmp(line, "shell", 5) == 0) {
              dvprintf(3, "attempting to start shell\n");
              if(globals.loggedin) {
                  execve("/bin/sh", argv, envp);
                  err(1, "unable to execve");
              }
              dprintf("Permission denied\n");
          } else if(strncmp(line, "logout", 4) == 0) {
              globals.loggedin = 0;
          } else if(strncmp(line, "closelog", 8) == 0) {
              if(globals.debugfile) fclose(globals.debugfile);
              globals.debugfile = NULL;
          } else if(strncmp(line, "site exec", 9) == 0) {
              notsupported(line + 10);
          } else if(strncmp(line, "setuser", 7) == 0) {
              setuser(line + 8);
          }
      }

      return 0;
    }

It also provides us with these directions:

“Analyze the C program, and look for vulnerabilities in the program. There is an easy way to solve this level, an intermediate way to solve it, and a more difficult/unreliable way to solve it.”

Exploit Exercises - Nebula Level17

Level17 dictates, “There is a python script listening on port 10007 that contains a vulnerability.”

Python! Nice. The nebula war game is using a variety of languages, which is fantastic. We are provided with the following source code:

    #!/usr/bin/python

    import os
    import pickle
    import time
    import socket
    import signal

    signal.signal(signal.SIGCHLD, signal.SIG_IGN)

    def server(skt):
      line = skt.recv(1024)

      obj = pickle.loads(line)

      for i in obj:
          clnt.send("why did you send me " + i + "?\n")

    skt = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
    skt.bind(('0.0.0.0', 10007))
    skt.listen(10)

    while True:
      clnt, addr = skt.accept()

      if(os.fork() == 0):
          clnt.send("Accepted connection from %s:%d" % (addr[0], addr[1]))
          server(clnt)
          exit(1)

Exploit Exercises - Nebula Level16

For Level16, we are told that a perl script is running on port 1616.

The source code for that script is provided:

    #!/usr/bin/env perl

    use CGI qw{param};

    print "Content-type: text/html\n\n";

    sub login {
      $username = $_[0];
      $password = $_[1];

      $username =~ tr/a-z/A-Z/; # conver to uppercase
      $username =~ s/\s.*//;        # strip everything after a space

      @output = `egrep "^$username" /home/flag16/userdb.txt 2>&1`;
      foreach $line (@output) {
          ($usr, $pw) = split(/:/, $line);


          if($pw =~ $password) {
              return 1;
          }
      }

      return 0;
    }

    sub htmlz {
      print("<html><head><title>Login resuls</title></head><body>");
      if($_[0] == 1) {
          print("Your login was accepted<br/>");
      } else {
          print("Your login failed<br/>");
      }
      print("Would you like a cookie?<br/><br/></body></html>\n");
    }

    htmlz(login(param("username"), param("password")));

Exploit Exercises - Nebula Level15

The About section for Level15 contains the following instructions:

“strace the binary at /home/flag15/flag15 and see if you spot anything out of the ordinary.

You may wish to review how to “compile a shared library in linux” and how the libraries are loaded and processed by reviewing the dlopen manpage in depth.

Clean up after yourself :)"

Exploit Exercises - Nebula Level14

Level14 provides us with these instructions:

“This program resides in /home/flag14/flag14. It encrypts input and writes it to standard output. An encrypted token file is also in that home directory, decrypt it :)”

Exploit Exercises - Nebula Level13

In Level13 we are given the following code:

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

    #define FAKEUID 1000

    int main(int argc, char **argv, char **envp)
    {
      int c;
      char token[256];

      if(getuid() != FAKEUID) {
          printf("Security failure detected. UID %d started us, we expect %d\n", getuid(), FAKEUID);
          printf("The system administrators will be notified of this violation\n");
          exit(EXIT_FAILURE);
      }

      // snip, sorry :)

      printf("your token is %s\n", token);

    }

In order to receive the token we need to FAKE our UID to bypass the if statement.

Now, we could solve this a few different ways. The two that pop into mind are: 1.) Write a fake getuid() program to trick the call. 2.) Use a debugger.