Hacking

Windows Exploit Mitigation Technology – Part 1

SecRat
February 13, 2015 by
SecRat

The spree of exploits on Windows has led to the creation of a certain type of exploit protection mechanism on Windows. Protection from things like buffer overflow, heap overwrite and return originated exploits have been deployed on Windows compilers and OS.

They can be either OS specific or compiler based protections. EMET can be used to apply some of these protections on Windows binaries.

What should you learn next?

What should you learn next?

From SOC Analyst to Secure Coder to Security Manager — our team of experts has 12 free training plans to help you hit your goals. Get your free copy now.

According to Microsoft:

"The Enhanced Mitigation Experience Toolkit (EMET) is a utility that helps prevent vulnerabilities in software from being successfully exploited. EMET achieves this goal by using security mitigation technologies. These technologies function as special protections and obstacles that an exploit author must defeat to exploit software vulnerabilities. These security mitigation technologies do not guarantee that vulnerabilities cannot be exploited. However, they work to make exploitation as difficult as possible to perform."

Compiler protections included in MSVC are:

[plain]
/GF enable read-only string pooling /Gm[-] enable minimal rebuild

/Gy[-] separate functions for linker /GS[-] enable security checks

/GR[-] enable C++ RTTI /GX[-] enable C++ EH (same as /EHsc)

/EHs enable C++ EH (no SEH exceptions) /EHa enable C++ EH (w/ SEH exceptions)

/EHc extern "C" defaults to nothrow

/Qfast_transcendentals generate inline FP intrinsics even with /fp:except

/GL[-] enable link-time code generation /GA optimize for Windows Application

/Ge force stack checking for all funcs /Gs[num] control stack checking calls

/Gh enable _penter function call /GH enable _pexit function call

/GT generate fiber-safe TLS accesses /RTC1 Enable fast checks (/RTCsu)

/RTCc Convert to smaller type checks /RTCs Stack Frame runtime checking

/RTCu Uninitialized local usage checks

/clr[:option] compile for common language runtime, where option is:

pure - produce IL-only output file (no native executable code)

safe - produce IL-only verifiable output file

oldSyntax - accept the Managed Extensions syntax from Visual C++ 2002/2003

initialAppDomain - enable initial AppDomain behavior of Visual C++ 2002

noAssembly - do not produce an assembly

/Gd __cdecl calling convention /Gr __fastcall calling convention

/Gz __stdcall calling convention /GZ Enable stack checks (/RTCs)

/QIfist[-] use FIST instead of ftol()

/hotpatch ensure function padding for hotpatchable images

/arch:<SSE|SSE2|AVX> minimum CPU architecture requirements, one of:

SSE - enable use of instructions available with SSE enabled CPUs

SSE2 - enable use of instructions available with SSE2 enabled CPUs

AVX - enable use of Intel(R) Advanced Vector Extensions instructions

/Qimprecise_fwaits generate FWAITs only on "try" boundaries, not inside "try"

/Qsafe_fp_loads generate safe FP loads
[/plain]

So it makes exploitation difficult but does not ultimately protect against it.

Stack-Based OverRun Detection (GS)

This is the oldest and most famous protection available in Visual C++. The goal of the /GS compiler flag is simple: reduce the chance that maleficent code will execute correctly. The /GS option is on by default in Visual C++ 2003 and later, and it detects certain kinds of stack smash at run time. It goes about doing this by including a desultory number in a function's stack just before the return address on the stack, and when the function returns, the function epilogue code checks this value to ascertain it has not transmuted. If the cookie, as it's called, has been mutated, execution is halted.

So GS stack cookie basically protects against tampering of return addresses. Now let's go into detail how it works:

Consider the following C code compiled using /GS parameter of Microsoft C compiler:

{c]
#include

void vuln()

{

unsigned char x[10] = {0};

int i = 0;

while (i != 100)

x[i++] = 'A';

}

int main(int argc, char **agrv)

{

vuln();

}

[/c]

If we compile it using MSVC switch /GS it would get the GS stack-based protection embedded. Let's see what is added at the vuln function for GS stack protection.

Stack Cookie Resides soon after Saved EBP i.e EBP-4 as shown in the IDA disassembly:

As you can see in the beginning of the prologue of the function, the __security_cookie is retrieved and xored with EBP. So if the attacker had to overwrite the return address he needs to guess the __security_cookie as clearly we see that it will also get overwritten. Now let's see how it is generated and if it contains enough randomness in order to be secure.

This value is generated in ___security_init_cookie() function which looks like:

[plain]

___security_init_cookie proc near ; CODE XREF: $LN26#p

.text:0040267F

.text:0040267F PerformanceCount= LARGE_INTEGER ptr -10h

.text:0040267F SystemTimeAsFileTime= _FILETIME ptr -8

.text:0040267F

.text:0040267F mov edi, edi

.text:00402681 push ebp

.text:00402682 mov ebp, esp

.text:00402684 sub esp, 10h

.text:00402687 mov eax, ___security_cookie

.text:0040268C and [ebp+SystemTimeAsFileTime.dwLowDateTime], 0

.text:00402690 and [ebp+SystemTimeAsFileTime.dwHighDateTime], 0

.text:00402694 push ebx

.text:00402695 push edi

.text:00402696 mov edi, 0BB40E64Eh

.text:0040269B mov ebx, 0FFFF0000h

.text:004026A0 cmp eax, edi

.text:004026A2 jz short loc_4026B1

.text:004026A4 test ebx, eax

.text:004026A6 jz short loc_4026B1

.text:004026A8 not eax

.text:004026AA mov dword_408004, eax

.text:004026AF jmp short loc_402716

.text:004026B1 ; ---------------------------------------------------------------------------

.text:004026B1

.text:004026B1 loc_4026B1: ; CODE XREF: ___security_init_cookie+23#j

.text:004026B1 ; ___security_init_cookie+27#j

.text:004026B1 push esi

.text:004026B2 lea eax, [ebp+SystemTimeAsFileTime]

.text:004026B5 push eax ; lpSystemTimeAsFileTime

.text:004026B6 call ds:GetSystemTimeAsFileTime

.text:004026BC mov esi, [ebp+SystemTimeAsFileTime.dwHighDateTime]

.text:004026BF xor esi, [ebp+SystemTimeAsFileTime.dwLowDateTime]

.text:004026C2 call ds:GetCurrentProcessId

.text:004026C8 xor esi, eax

.text:004026CA call ds:GetCurrentThreadId

.text:004026D0 xor esi, eax

.text:004026D2 call ds:GetTickCount

.text:004026D8 xor esi, eax

.text:004026DA lea eax, [ebp+PerformanceCount]

.text:004026DD push eax ; lpPerformanceCount

.text:004026DE call ds:QueryPerformanceCounter

.text:004026E4 mov eax, dword ptr [ebp+PerformanceCount+4]

.text:004026E7 xor eax, dword ptr [ebp+PerformanceCount]

.text:004026EA xor esi, eax

.text:004026EC cmp esi, edi

.text:004026EE jnz short loc_4026F7

.text:004026F0 mov esi, 0BB40E64Fh

.text:004026F5 jmp short loc_402707

.text:004026F7 ; ---------------------------------------------------------------------------

.text:004026F7

.text:004026F7 loc_4026F7: ; CODE XREF: ___security_init_cookie+6F#j

.text:004026F7 test ebx, esi

.text:004026F9 jnz short loc_402707

.text:004026FB mov eax, esi

.text:004026FD or eax, 4711h

.text:00402702 shl eax, 10h

.text:00402705 or esi, eax

.text:00402707

.text:00402707 loc_402707: ; CODE XREF: ___security_init_cookie+76#j

.text:00402707 ; ___security_init_cookie+7A#j

.text:00402707 mov ___security_cookie, esi

.text:0040270D not esi

.text:0040270F mov dword_408004, esi

.text:00402715 pop esi

.text:00402716

.text:00402716 loc_402716: ; CODE XREF: ___security_init_cookie+30#j

.text:00402716 pop edi

.text:00402717 pop ebx

.text:00402718 leave

.text:00402719 retn

.text:00402719 ___security_init_cookie endp

[/plain]

Firstly, it will compare __security_cookie with the default value:

[plain]

mov edi, 0BB40E64Eh

mov ebx, 0FFFF0000h

[/plain]

And if matched it will continue to generate a random one. The random value for __security_cookie is generated as a combination of xors for time, processid, threadid, tickcount and QueryPerformanceCounter() values.

And then xored and multiplied.

[plain]

or eax, 4711h

shl eax, 10h

[/plain]

In the epilogue of a function protected by GS stack cookie you will see a call to __security_check_cookie() function which verifies the __security_cookie, and if it is manipulated the process terminates. So done in this way before returning to the attacker controlled area which leverages ret instruction is prevented.

SAFESEH

SAFESEH was added from Windows XP Sp2. It is an operating system protection technique by which we can protect against SEH overwrites. This technique isn't available on 64 bit systems, as 64 bit Windows uses a different mechanism for exception handling, which is quite similar to what is used on SAFESEH.

A binary is only protected by SAFESEH only if it is explicitly mentioned on the PE header. To check the existence of that header, we can use the Dumpbin tool by Microsoft by using the following command line:

[plain]
dumpbin sample.exe /LOADCONFIG

File Type: EXECUTABLE IMAGE

Section contains the following load config:

00000048 size

0 time date stamp

0.00 Version

0 GlobalFlags Clear

0 GlobalFlags Set

0 Critical Section Default Timeout

0 Decommit Free Block Threshold

0 Decommit Total Free Threshold

00000000 Lock Prefix Table

0 Maximum Allocation Size

0 Virtual Memory Threshold

0 Process Heap Flags

0 Process Affinity Mask

0 CSD Version

0000 Reserved

00000000 Edit list

00408310 Security Cookie

00407840 Safe Exception Handler Table

3 Safe Exception Handler Count

[/plain]

Safe Exception Handler Table

Address

--------

00402390

00403FD0

00405040

When an exception occurs, th exception is transferred to the SAFESEH handler in ntdll.dll and it checks if the exception target is present in the SAFESEH list. Following is the implementation of RtlCaptureImageExceptionValues on Windows XP sp2.

What should you learn next?

What should you learn next?

From SOC Analyst to Secure Coder to Security Manager — our team of experts has 12 free training plans to help you hit your goals. Get your free copy now.

If the target address isn't present in the list, then RtlCallKernel32UnhandledExceptionFilter is called to terminate the program.