Pivot class builds ROP chains that perform stack pivoting - moving the stack pointer to a different memory location to enable exploitation when stack space is limited.
Overview
Accessed through the ROP instance asrop.pivot(), Pivot automatically:
- Finds gadgets that modify the stack pointer
- Supports pivoting to addresses or register values
- Handles different pivot mechanisms (mov, xchg, add, etc.)
- Manages pre-pivot stack setup
- Verifies pivot operations
Class Definition
angrop/chain_builder/pivot.py
Public Methods
pivot
RopValue
required
Target for the pivot. Can be:
- Address (RopValue with concrete address)
- Register (RopValue with register name)
RopChain that pivots the stack.
Raises: RopException if pivot cannot be performed.
pivot_addr
RopValue
required
Target address for the new stack location.
RopChain that pivots to the address.
pivot_reg
RopValue
required
RopValue representing a register containing the target address.
RopChain that pivots to the register value.
ROP Instance Method
Implementation Details
Pivot Gadget Types
Pivot recognizes several gadget patterns:- Direct move:
mov rsp, rbp; ret - Exchange:
xchg rsp, rax; ret - Add to SP:
add rsp, 0x100; ret - Pop to SP:
pop rsp; ret - Leave:
leave; ret(equivalent tomov rsp, rbp; pop rbp; ret)
SP Controllers
Gadgets are analyzed to identify which registers control the final SP value: From source code (pivot.py:111-113):Pivot to Address
From source code (pivot.py:43-75):Pivot to Register
From source code (pivot.py:77-109):Usage Examples
Basic Stack Pivot to Address
Pivot to Register
Complete Pivot Example
Pivot for Buffer Extension
Chained Pivots
Pivot with Leave Gadget
Gadget Requirements
For pivoting to work:- SP modification: Gadget must change stack pointer
- Controllable: SP target must be controllable via registers or offsets
- No conditional branches: Ensures predictable execution
- Not jmp_reg: Direct jumps don’t help with pivoting
- No symbolic access: Memory accesses must be concrete
Common Pivot Patterns
x86_64 Patterns
x86 (32-bit) Patterns
ARM Patterns
Stack Change Tracking
Pivot gadgets track two stack changes:- stack_change_before_pivot: Stack movement before SP is modified
- stack_change_after_pivot: Stack movement after pivot
Verification
Pivot chains are verified using symbolic execution:stop_at_pivot=True flag stops execution when SP changes significantly.
Error Handling
”Fail to pivot the stack to !”
Raised when no pivot chain can be built. Solutions:- Check if pivot gadgets exist:
rop.pivot_gadgets - Try pivoting to a register instead
- Use
find_gadgets(fast_mode=False)for more gadgets - Verify target address is valid
”Fail to pivot the stack to !”
Raised when register-based pivot fails. Solutions:- Check if gadgets control SP via that register
- Try a different register
- Use address-based pivot instead
Performance Considerations
- Pivot gadgets are pre-filtered and sorted during bootstrap
- Symbolic execution adds overhead for verification
- Simpler pivots (direct moves) are faster
- Complex pivots may require multiple gadgets
Architecture Support
- x86/x86_64: Full support, many pivot patterns
- ARM/ARM64: Full support
- MIPS: Basic support
- PowerPC: Basic support
Advanced Techniques
Partial Overwrites
Info Leak + Pivot
Best Practices
- Verify target alignment: Stack should be aligned to word boundary
- Plan stack layout: Know what will be at target address
- Test pivot gadgets: Use
chain.pp()to inspect - Consider stack growth: Stack grows down on most architectures
- Account for saved values: Leave gadget pops rbp first
See Also
- Shifter - Stack shifting operations
- ChainBuilder - Main chain building interface
- Building Chains Guide - ROP construction patterns