ropemporium - challenge 7 'pivot'
This challenge teaches us how to escape limited stack space and pivot to a new stack to jump onto a fresh rop-chain.
As we can see the challenge offers 2 read entries and gives us a clear direction how to approach it.
We are also told that 1. our foothold function is not yet resolved, as is our ret2win function, and 2. that we have to find the offset by examining the libpivot.so file.
We therefore have to understand how plt-stubs, got and lazy binding works. All of this is explained at https://ropemporium.com/guide.html.
- got entry for the not yet resolved foothold_function, this can be confirmed by firing up gdb and disas usefulFunction.
- plt stub for foothold_function, when the function gets called for the first time this stub dereferences the pointer to check if there is a real adress behind the got entry, if not it calls the linker to resolve it, after that the got entry points to the resolved adress.
- offsets of ret2win and foothold_function in the custommade libpivot.so, ret2win
ropper(an example of a few of the gadgets we will use)
Our plan will be like this:
- give the big rop chain into the first read, catching the adress from the output
- handing the stack pivot to the 2nd read and jumping to our first chain, printing the flag
This exploit does the following:
- using all the static elements we found with readelf, nm, ropper/gdb to prepare all our gadgets.
- build a chain(leak_call_chain) that does the following
- place footplt(plt stub of foothold_function) at the return adress after the pivot
- pop rax; ret; + footgot sends the got entry into rax
- the mov rax gadget will dereference the got entry of foothold after it has been resolved by our first attempt to call it and write the actual adress into rax
- pop rbp; ret; + ret2win offset will send our offset to rbp to thenn add this onto rax which contains our foothold_function adress
we use call rax to call the adress in rax which is exactly the adress of our ret2win
- we start the process with process(bin.path), receive the prompt and read the adress in integer form for further usage
- we send our leak_call_chain
- we execute our stack smash with the stack pivot which does the following
- pop rax; ret; + addr (this is where our big chain is waiting) will send this adress to rax, after that we exchange rax and rsp and hit a ret so our stack gets transfered to the adress where the rest of our chain is waiting, the ret of this gadget will load the got entry into rip and make it work
Conclusion
This time my code is way more readable although there is room for improvement.