Stack Pivoting is a technique we use when we lack space on the stack - for example, we have 16 bytes past RIP. In this scenario, we're not able to complete a full ROP chain.
During Stack Pivoting, we take control of the RSP register and "fake" the location of the stack. There are a few ways to do this.
pop rsp gadget
Possibly the simplest, but also the least likely to exist. If there is one of these, you're quite lucky.
xchg <reg>, rsp
If you can find a pop <reg> gadget, you can then use this xchg gadget to swap the values with the ones in RSP. Requires about 16 bytes of stack space after the saved return pointer:
pop <reg> <=== return pointer
xchg <rag>, rsp
This is a very interesting way of stack pivoting, and it only requires 8 bytes.
Every function (except main) is ended with a leave; ret gadget. leave is equivalent to
mov rsp, rbp
Note that the function ending therefore looks like
mov rsp, rbp
That means that when we overwrite RIP the 8 bytes before that overwrite RBP (you may have noticed this before). So, cool - we can overwrite rbp using leave. How does that help us?
Well if we look at leave again, we noticed the value in RBP gets moved to RSP! So if we call overwrite RBP then overwrite RIP with the address of leave; ret again, the value in RBP gets moved to RSP. And, even better, we don't need any more stack space than just overwriting RIP, making it very compressed.