Log in

View Full Version : what about XPSP2 "Execution Protection"


0rp
March 6th, 2004, 23:44
http://msdn.microsoft.com/security/productinfo/XPSP2/memoryprotection/execprotection.aspx

will it harm "inplace" decrypting executables ?

sgdt
March 7th, 2004, 01:07
Quote:
[Originally Posted by 0rp]http://msdn.microsoft.com/security/productinfo/XPSP2/memoryprotection/execprotection.aspx

will it harm "inplace" decrypting executables ?


They claim it's protection against buffer overrun attatck, but I doubt it's usefullness for that.

Maybe I'm stating the obvious here, but it seems like a program could call VirtualProtect and turn off the NX bit.

As anyone whos traced a convoluted protection (such as ASPR for example), pushing an address followed by a return is identical to a dirrect jump. In a buffer overrun attack, your writing to the stack, and the ret is already in the code of the reader. You vaporize the functions return address with parameters to VirtualProtect, and the functions return address with the call to virtual protect, and when the routine "returns", you now have executable code whereever you want.

I mean, isn't it the exact same problem as before? I mean, didn't they learn ONE SINGLE THING from when Sun gave a "NX" bit to the Sparc's claiming they were no longer vunerable to buffer overrun attacks? (That lasted a day or so, gotz ta luv marketing people!)

What it DOES buy Microsoft has a little bit to do with CRM, though. But that's just a wild ass guess...

If they really wanted to stop buffer overrun attacks, they should teach people to check their return values once in a while and maybe not use stack space to store stuff that could be coming from a hostile enviroment. Simply using the virtual protect of today, setting a read-only section just past where they KNOW the buffer is supposed to end and wrapping in a try...except is more than enough protection.

But that wouldn't let them control what plug-ins can do for Media Player...

mmk
March 7th, 2004, 04:45
If you want to prevent buffer overflows, don't code in C/C++. Use Java, C# and similar safer languages. If you absolutely must use C++, use safe classes to manipulate buffers (that includes strings). That NX bit will only make it slightly harder, but it definitely won't make it impossible to exploit a buffer overflow.

With Visual C++ .NET's stack-based buffer overflow prevention option, you would have to take control of the SEH handler. That was easy => option useless.

With the NX bit (which is only present in some of the newest x86 CPUs, such as AMD x86-64 and future Intel processors) you could do as sgdt just said and call VirtualProtect() to make the stack executable again.

If both are enabled, take control of the SEH handler, return to VirtualProtect() and return to your code on the stack. It could be difficult to find the right return addresses to make this work, but it's not impossible.

Once again, use a safer language if you want to prevent buffer overflows!

SiNTAX
March 7th, 2004, 07:03
Quote:
[Originally Posted by mmk]
With the NX bit (which is only present in some of the newest x86 CPUs, such as AMD x86-64 and future Intel processors) you could do as sgdt just said and call VirtualProtect() to make the stack executable again.


Note: ia32e (= Intel's version of AMD64) still doesn't have an NX bit.

Anyway the problem will be calling VirtualProtect(). It will be a tad more difficult, as you can't directly execute your own code anymore, so you need to push the right params on the stack (VirtualProtect() address + it's params + return to the stack location + your code). However, if they also add some form of randomization, then it will be almost impossible to do.

BTW: recent Linux RedHat kernels already have this. It's called exec-shield and is combined with prelink randomization. So shared libs load addresses are randomized every 24 hours and the prelinker tries to randomize them to an address < 0x01000000, so that you will always have a null byte in the address, which makes 'string' buffer overruns harder as the null byte terminates the string. (exec-shield also has no-exec stack protection)

see hxxp://people.redhat.com/mingo/exec-shield/ANNOUNCE-exec-shield for more info on exec-shield.

mmk
March 7th, 2004, 07:35
Quote:
[Originally Posted by SiNTAX]Anyway the problem will be calling VirtualProtect(). It will be a tad more difficult, as you can't directly execute your own code anymore, so you need to push the right params on the stack (VirtualProtect() address + it's params + return to the stack location + your code).


Without the cookie protection, it's very easy to call any function with any argument.

original stack in vulnerable func:
[locals and saved regs]
[ret addr]
[args]
[callee's local data]

after stack based buffer overflow:
#1 [locals and saved regs, most likely destroyed now]
#2 [address of newfunc]
#3 [args]
#4 [addr of destaddr which will branch to your shellcode]
#5 [input to newfunc; you control this data]

When the function returns, it will execute a RET X instruction, which will return to newfunc and remove the input arguments ([args]) from the stack. ESP is now set to #4. When newfunc returns, it will return to destaddr and remove arguments (#5) from the stack.

Replace newfunc with VirtualProtect and #5 with VirtualProtect arguments to make the stack executable, and you have an exploit to hack into any computer with that vulnerable software.

SiNTAX
March 7th, 2004, 07:50
Quote:
[Originally Posted by mmk]Without the cookie protection, it's very easy to call any function with any argument.

original stack in vulnerable func:
[locals and saved regs]
[ret addr]
[args]
[callee's local data]

after stack based buffer overflow:
#1 [locals and saved regs, most likely destroyed now]
#2 [address of newfunc]
#3 [args]
#4 [addr of destaddr which will branch to your shellcode]
#5 [input to newfunc; you control this data]

When the function returns, it will execute a RET X instruction, which will return to newfunc and remove the input arguments ([args]) from the stack. ESP is now set to #4. When newfunc returns, it will return to destaddr and remove arguments (#5) from the stack.

Replace newfunc with VirtualProtect and #5 with VirtualProtect arguments to make the stack executable, and you have an exploit to hack into any computer with that vulnerable software.


Yups.. that's also what I said :-) But.. you have to know which version of windows you are targetting as you need to know the exact address of VirtualProtect() (not that this will make it much harder, but if the target is a network app that bombs out if you try to exploit it, then you only have 1 chance... ofcourse you can finger-print the target beforehand, enough tools around to do that).

Because one can know the address of VirtualProtect(), that's also why I mentioned that if this is combined with library base randomization, that you will have a very hard time exploiting it.

mmk
March 7th, 2004, 09:45
Quote:
you have to know which version of windows you are targetting as you need to know the exact address of VirtualProtect()


Using hardcoded addresses for stack based buffer overflows is something exploit writers have always used.

You only get one chance with all stack based buffer overflow exploits. Use the wrong return address and you get a lame DoS instead of complete control of the remote system.

SiNTAX
March 8th, 2004, 04:58
Quote:
[Originally Posted by mmk]Using hardcoded addresses for stack based buffer overflows is something exploit writers have always used.

You only get one chance with all stack based buffer overflow exploits. Use the wrong return address and you get a lame DoS instead of complete control of the remote system.


I have to disagree here... if you have an executable stack and you can write the code you want on it, then you can make your exploit work on any version of windows (as long as the program you're exploiting is the same)

mmk
March 8th, 2004, 05:38
Of course you can make it work on any Windows version. The problem is finding a return address which can be used on all Windows versions. That's usually not possible so you have to scan the remote host and figure out the OS it's using, and then modify the exploit to work with that OS and Service Pack.

SiNTAX
March 8th, 2004, 14:45
Quote:
[Originally Posted by mmk]Of course you can make it work on any Windows version. The problem is finding a return address which can be used on all Windows versions. That's usually not possible so you have to scan the remote host and figure out the OS it's using, and then modify the exploit to work with that OS and Service Pack.


I think we are talking about 2 different things here... I was refering to the way it is now, ie executable stacks. If the stack is executable, you can load it with code that uses the contents of variables of the exploit target. Finding the KERNEL32 base in the target code isn't that hard. Since windows exe's load at a fixed address, the target exe address will be the same on all windows boxes. So your exploit is generic.

If the stack is non-executable, then you can only use return addresses & the target's own code, until you have called VirtualProtect(), but to find the VirtualProtect() address, you need the KERNEL32 base which you won't easily find if all you can use is the target's code & return addresses.

mmk
March 8th, 2004, 15:47
To execute your stack overflow exploit code you must use at least one hardcoded address in the app or a DLL used by it which will jump to your code.

SiNTAX
March 8th, 2004, 18:07
Quote:
[Originally Posted by mmk]To execute your stack overflow exploit code you must use at least one hardcoded address in the app or a DLL used by it which will jump to your code.


Indeed... but the app's address is fixed (even on different version of windows).. so no problem there.

mmk
March 8th, 2004, 19:19
Yes the base address (normally 400000) is usually the same. But I'm talking about how to get to the shellcode. And to do that you must use one hardcoded address usually for the return address or for the SEH handler. This address usually points to an address high up in memory because it usually can't contain any 00h bytes in it. When your code gets control you can easily find kernel32 base in 5 instructions so you don't need to know the program's base address. Just one hardcoded address and you can do anything.