Don't like this style? Click here to change it! blue.css
I'll try to start each lecture (at least for the next couple weeks) with a demo PWN designed for several reasons:
Let's do bof
from PWNABLE.kr
So last time we learned that passing an argument to a win function requires a 4-byte gap in the 32-bit case. This gap was from the fact that we jumped to the win function instead of "call"-ing the win function. So it was up to us to provide the 4-byte "return address" to the win function BEFORE the arguments.
That is:
payload=b"A"*offset + b"xOBP"+p32(winAddress) + p32(NEXTaddress) + p32(arg1)
NOW suppose that we need to call a series of "win"-functions before we get the flag.
If it's 3 functions that need calling, each requiring an argument things start to get weird.
Let's see why:
payload=b"A"*offset + b"xOBP"
+p32(func1Address) + p32(func2address)
+p32(func1arg1)+p32(func2arg1)
This payload works for calling 2 functions each requiring exactly 1 argument. But if I need a third function call (or a second argument for func1) I have some serious problems. the place where func3address goes is ALSO where func1arg1 has to be!
To resolve this dilemma we're going to introduce another concept, that of the GADGET.
A Gadget is an address in an executable segment which does a few useful instructions and ends with a ret
(or a jmp
or call REGISTER
).
The idea is that you can piece together little chunks of utility to massage the registers or stack into a state you would like.
It is also like building your own baby-shellcode piece by piece.
In the above example we are looking for a gadget that looks something like this:
pop ebx; ret;
Our goal is to clear the argument off of our stack to make room for our next function address.
The POP was all we cared about in this case so of course pop anyuselessregister
would do.
But if we need to do the 64-bit case of a similar problem we have to use something like this to pass any arguments via registers.
OK so what would our payload look like now?
payload=b"A"*offset + b"xOBP" +
p32(func1Address) + p32(stack_clear_gadget_address) + p32(func1arg1) +
p32(func2Address) + p32(stack_clear_gadget_address) + p32(func2arg1) +
p32(func3Address) + p32(stack_clear_gadget_address) + p32(func3arg1)
So you'll see that now we can make this "chain" as long as we would like by having these little triplets that jump to some location with an argument then clean up the stack after.
Of course if you need to pass more than one argument you'll want some gadget that does more than one POP (one POP per argument).
Now how do you find such gadgets?
Grab a challenge binary https://sec.prof.ninja/challenge/pwn_stuff/5leap_frog/zipline and
in your terminal run ROPgadget --binary zipline
ROPgadget is a great little command line tool for identifying possible gadgets for building your ROP chain.
So write-ups are the primary way of learning new techniques and tools.
They are community-made micro-tutorials showing your process for a particular problem.
If you are overwhelmed by a particular problem go hunting for write-ups of problems that seem similar. Those write-ups will have keywords, insights, and clever concepts that will grow you.
Solve https://sec.prof.ninja/challenge/pwn_stuff/5leap_frog/zipline by following this student-made write-up: