OSCE3 | OSCE | OSCP
We all know what ROP chains are right? No? If you want to do binary exploitation of any kind then you need to understand ROP, this post is about Call-oriented programming (COP) so I’m going to be lazy and post a link: Return-oriented Programming.
Studying for my OffSec Exploitation Expert (OSEE) exam, more specifically the VMWare escape use case, we find that one of the ROP chains contains a call rsi
instruction. Becasue of the way call
instructions work this presents a problemm as they modify the stack which disrupts the normal flow of a ROP chain. Whenever I hear the term ‘call-oriented programming’ I get a little bit shaky/nervous, turns out I needn’t!
The case presented was to build a ROP chain to call the WIndows GetProcAddress
API, the API has the following signature:
FARPROC GetProcAddress(
[in] HMODULE hModule,
[in] LPCSTR lpProcName
);
Using the __stdcall
calling convention this means moving the module address into rcx
and a pointer to the function name string into rdx
, fairly standard stuff so far. The problem is that there are no gadgets which contain mov rdx, r62
. There is actually one gadget but it presents a problem:
mov rdx, rax ; call rsi ;
The problem is that a valid call address must be in rsi
before this is called and call
instructions push the saved return address on to the stack which alters the ROP chain on the stack.
I decided to understand this a bit better. I decided to step through and document the stack/registers as I went along. I started with the following ROP chain snippet (notice the call
instruction and the absence of a ret
instruction in that gadget):
...
pop rsi ; ret ;
pop rax ; ret ; (executed by call rsi)
mov rdx, rax; call rsi ;
pop rax ;
[temporary storage address of kernelbase.dll base address]
mov rcx, [rax] ; mov rax, [rax + 8] ; add rax, rcx ; ret ;
...
This is what the stack and the registers look like at this point, remember that the objective is to get the value in rax
moved into rdx
:
When the pop rsi ; ret ;
gadget is executed the address of pop rax ; ret ;
gadget will be popped in to rsi
. This adds 0x10
to rsp
, the stack/registers now look like the following:
The next gadget mov rdx, rax ; call rsi ;
moves rax
into rdx
(as intended) and then makes the call to the address we popped in to rsi
.
When a call
is made the saved return address is pushed on to the stack and rsp
points to it, effectively not moving the stack pointer from our viewpoint but the gadget address we are executing has been overwritten (which is fine). The clever part comes next:
We have pushed a pop ret
gadget into rsi
so when the gadget is executed it pops the saved return address into rax
, which adds 0x8
to rsp
restoring our ROP chain nicely:
This gadget pops the KerneBase.dll
address into rax
, and the final ROP gadget in our snippet dereferrences the address in to rcx
and our objective is completed:
Now I understood this I wondered if there was a ‘general’ workflow I could apply to these scenarios.
If I need to use Call-oriented programming gadgets in my ROP chains I will be sure to step through them to understand how they work and that I get the intended result. As a general rule for the scenario discussed I think this works:
Granted, I need to test this theory out with more examples.
Thank you, and goodnight!
Feel free to leave comments or questions for this blog post. Please be respectful, I will moderate comments and reserve the right to remove them.