This challenge is funny and I’ve never seen it before it was really easy once I turned on my brain and realised that the solution isn’t supposed to work on my local system without the provided container and that I should try on the remote.

So we get a file and the usual nc command, as always lets fire up ghidra and see what we’re dealing with.

int main(void)
{
  int iVar1;
  char input [64];
  
  signal(0xb,on_segfault);
  printf("What is the password?\n?: ");
  fflush(stdout);
  fgets(input,0x80,stdin);
  iVar1 = strcmp(input,"password\n");
  if (iVar1 != 0) {
    puts("incorrect password");
    fflush(stdout);
  }
  return 0;
}

This looks like a simple password checking function, however we quickly notice two things.

  1. First we have a nice little buffer overflow on the input, we are able to input 0x80 chars (which is 128 in decimal) inside of a 60 bytes buffer. For a beginner oriented CTF this isn’t surprising.
  2. More surprising is the use of signal which I guessed allows to do something when receiving a syscall. After a quick look at the manual I was right. This allow us to map a signal to a function resulting in a call to the function being performed when the signal is received by the program (I don’t think this is all and I am not sure that it is exactly what happens but it’s more than enough to do the challenge). By the name of the function and after a quick look on the internet we can confirm that 0xb (11 in decimal) is the syscall number for SIGSEGV better know as the segmentation fault (invalid memory reference, tried to dereference an invalid pointer).

So putting it all together we have a buffer overflow that allows us to trigger a segfault by overriding the return pointer and a function that executes when a segfault occurs. But what’s that function ?

void on_segfault(int sig_num)
{
  int iVar1;
  FILE *__stream;
  char acStack_b0 [64];
  code *pcStack_70;
  int sig_num_local;
  char data [64];
  FILE *fd;
  
  sig_num_local = sig_num;
  __stream = fopen("./flag","r");
  fgets(data,0x40,__stream);
  printf("%s",data);
  fclose(__stream);
  FUN_00401140(1);
  signal(0xb,on_segfault);
  printf("What is the password?\n?: ");
  fflush(stdout);
  fgets(acStack_b0,0x80,stdin);
  iVar1 = strcmp(acStack_b0,"password\n");
  if (iVar1 != 0) {
    puts("incorrect password");
    fflush(stdout);
  }
  return;
}

I removed some bloat but what this function basically does is read the flag and print it. So we know what to do, trigger a segfault and you’re done. To do that send about 100 characters and you get the flag.