Lion Cipher Lab
Defeat NX with a ROP chain (in your own lab)
- Penetration Testing / Red Team
- Advanced
- ~90 min
- Free · no account required
Why it matters
Part 1 ended on a cliffhanger: you recompiled at modern defaults and watched NX mark the stack non-executable, killing the 'write shellcode to the stack and jump to it' plan for good. Every real target you will ever meet has NX on. So how do exploits still work? This lab is the answer, and it is the single most important technique in modern binary exploitation: Return-Oriented Programming. Instead of bringing your own code, you reuse the program's own instructions — you find tiny fragments that already end in `ret`, called gadgets, and you chain them by stuffing their addresses onto the stack…
What you'll learn
- understanding WHY a non-executable stack (NX/DEP) makes classic shellcode-on-the-stack exploitation dead on arrival, and confirming it with readelf
- the core idea of Return-Oriented Programming: chaining tiny snippets of the program's OWN executable code ('gadgets') that each end in `ret`, since running existing code is exactly what NX permits
- finding a real `pop rdi ; ret` gadget in a binary with ROPgadget AND with ropper, and knowing why that specific gadget matters for the 64-bit calling convention
- measuring the overflow offset the reliable way with pwntools' cyclic pattern, then building a ROP chain by hand with struct.pack/flat
- building the same chain cleanly with pwntools' ROP() class and popping a shell without ever leaking a libc address (because a -no-pie binary's win()/PLT are at fixed addresses)
- diagnosing the classic 64-bit ROP reliability bug: a crash inside system() from a misaligned stack, fixed by adding one extra bare `ret` gadget to 16-byte-align rsp
- the judgment: when ROP-to-own-code fits vs when you need ret2libc, a one-gadget, or SROP -- and why ASLR + full RELRO + CFI/CET/shadow stacks are what make this hard on real targets
Steps in this lab
- Read this first: this is Part 2, still on your own machine
- The wall Part 1 left you at: NX means you can't just inject shellcode
- What ROP is, in one breath: gadgets ending in `ret`
- Get Linux and the exploit tooling
- Write the vulnerable program — with a win() that takes an argument
- Compile with NX ON — and confirm the stack is non-executable
- Find the offset the reliable way (pwntools cyclic)
- Find the `pop rdi ; ret` gadget (ROPgadget AND ropper)
- Build the ROP chain by hand and pop a shell
- The pro way: let pwntools' ROP() build the chain for you
- When ROP-to-your-own-code isn't enough: ret2libc, one-gadget, SROP
- The defenses that make this hard on real targets — and clean up