By using the so called universal gadget from
__libc_csu_init we can read shellcode into the rwx memory segment and return into it.
By executing read function we can overwrite only last two bytes of read to find something useful and defeat ASLR. Fortunately there is one-gadget RCE located at
0xf0567 in this version of libc, right near the
read function (0xf6670). We overflow only last two bytes to defeat ASLR, so that only around 16 attemps needed, because of 4 bit entropy of ASLR.
EDIT: checkout another great solution proposed by agadeint in the comment section below, which is cleaner and does not require bruteforcing and one gadget.
Stack looks like this:
... char buf; char *buf_;
gets function is used to fill the
buf, so it's easy to overflow
buf_ pointer, which is later passed into
count_crc function, so we can count crc almost of any memory region, thus we can get arbitrary read. We can get base address of libc from .got, and also we can get canary, because it's located in the memory segment right after the ld.so, which we can get by using kind of offset2ldso attack (though it is not stable and platform specific).
We can underflow the
fu pointer which in located in .bss section and make it point into the .got section, where we can read and write. I address of libc from got, then changed
strlen@got to address of
puts@got into the address of main function, so after restart of the binary
system function will be called instead of
strlen of string controlled by me.
First of all canary can be leaked by entering numbers 1 .. 7 into the menu and the last byte is always zero. Also in this binary couple of very useful gadgets like
syscall; ret can be found. So by using these gadgets and technic called SROP we can leak .got section, read our new ropchain and then return on it by using sigreturn.
In this task we can read any file, so we can read
/proc/self/maps to defeat ASLR and by abusing double free into fast bin attack we can overflow
__malloc_hook by address of system and call
system("/bin/sh") will be called.
In this task we can not read any file on the system, but we can get memory leak of heap by reading contents of fastbin chunk, and we can get memory leak of libc arena by reading contents of small chunk. Then I overflow
__malloc_hook once again into the one-gadget RCE and trigger double free error, which will trigger our hook. This is done exactly that way, because there is not such one-gadget that meets contrains if you simply call malloc, and you can not do the trick with
addr_of_binsh_on_heap like the last time, because of the PIE address of the heap is now more that
2 ** 32 and we could only call
malloc(unsigned int size).
defaulter says he accepts a shellcode as input. But obviously was some trick in this task. First I tried to call
execve("/bin/sh", NULL, NULL) shellcode, just to be sure that it blocked by seccomp sandbox or some sort of it (and it didn't work). So I tried testing over syscalls and I jumped into the inf. loop if syscall fails.
open syscall was blocked as well, but
openat was not, but
openat needs absolute path to file as argument so I read the
/etc/passwd to get username (which was pwn) and the read
/home/pwn/flag. So full path looks like this: openat flag, read the flag into writable location, write it to the screen.