Using a pop rsp gadget to stack pivot
FIrst off, let's grab all the gadgets. I'll use ROPgadget
again to do so:
Now we have all the gadgets, let's chuck them into the script:
Let's just make sure the pop
works by sending a basic chain and then breaking on ret
and stepping through.
If you're careful, you may notice the mistake here, but I'll point it out in a sec. Send it off, attach r2.
You may see that only the gadget + 2 more values were written; this is because our buffer length is limited, and this is the reason we need to stack pivot. Let's step through the first pop
.
You may notice it's the same as our "leaked" value, so it's working. Now let's try and pop the 0x0
into r13
.
What? We passed in 0x0
to the gadget!
Remember, however, that pop r13
is equivalent to mov r13, [rsp]
- the value from the top of the stack is moved into r13
. Because we moved RSP, the top of the stack moved to our buffer and AAAAAAAA
was popped into it - because that's what the top of the stack points to now.
Now we understand the intricasies of the pop, let's just finish the exploit off. To account for the additional pop
calls, we have to put some junk at the beginning of the buffer, before we put in the ropchain.
Using leave; ret to stack pivot
By calling leave; ret
twice, as described, this happens:
By controlling the value popped into RBP, we can control RSP.
As before, but with a difference:
I won't bother stepping through it again - if you want that, check out the pop rsp walkthrough.
Essentially, that pops buffer
into RSP (as described previously).
You might be tempted to just chuck the payload into the buffer and boom, RSP points there, but you can't quite - as with the previous approach, there is a pop
instruction that needs to be accounted for - again, remember leave
is
So once you overwrite RSP, you still need to give a value for the pop rbp
.
Stack Pivoting
It's fairly clear what the aim is - call winner()
with the two correct parameters. The fgets()
means there's a limited number of bytes we can overflow, and it's not enough for a regular ROP chain. There's also a leak to the start of the buffer, so we know where to set RSP to.
We'll try two ways - using pop rsp
, and using leave; ret
. There's no xchg
gadget, but it's virtually identical to just popping RSP anyway.
Since I assume you know how to calculate padding, I'll tell you there's 96 until we overwrite stored RBP and 104 (as expected) until stored RIP.
Just to get the basics out of the way, as this is common to both approaches: