πŸ› οΈWindows Exploit Mitigations

Mitigations Categories

  1. Windows Defender Exploit Guard (Windows Only)

  2. Compile-Time Controls

  3. OS Controls

Compile-Time Mitigations

Data Execution Prevention (DEP)

Also Known As:

  • NX / DX Bit

  • W^X

Can be Defeated by:

  • Return Orient Programming (ROP)

  • Return-to-libc

Defends Against:

Executing code from areas in the executable that weren't meant initially to be executed (such as the Heap or the Stack).

How Does it Work:

DEP is mainly a Hardware-based mitigation and It's main purpose is to prevent execution from memory sections that weren't meant to execute code such as the Heap or the Stack. Only intended memory sections would be allowed to have execute permissions such as the code segment.

  • Intel's calls the bit that is set to mark all non-executable pages the "execute disable" (XD) bit.

  • AMD calls the bit that is set to mark all non-executable pages the "no execute" (NX ) bit.

SafeSEH

Applies to 32-bit applications only

Can be Defeated by:

Defends Against:

  • SEH Overwrite - Overwriting the Structured Exception Handler pointer in the Stack and pointing to malicious code.

How Does it Work:

When a module is being compiled with SafeSEH, a table containing the addresses of each Exception Handler is created. When an attacker attempts to to overwrite a handler, a validation of the address is performed and if it doesn't match the address in the SEH Table an exception will be thrown.

In 64-bit processes the pointers to the SEH resides in the .pdata section and not on the stack as oppose to 32-bit processes

SEHOP

32-bit Processes Protection Only

Can be Defeated by:

Defends Against:

  • Structured Exception Handlers Overwrite

How Does it Work:

At a high-level, the SEH overwrite technique uses a software vulnerability to execute arbitrary code by abusing the 32-bit exception dispatching facilities provided by Windows. At a functional level, an SEH overwrite is generally accomplished by using a stack-based buffer overflow to overwrite an exception registration record that has been stored on a thread’s stack. To provide some context, an exception registration record is composed of two fields: a next pointer and an exception handler function pointer. The next pointer is used to link an exception registration record to the next record in the singly-linked list of registered exception handlers."

The mitigation works by adding a symbolic record at the end of each SEH chain on every thread, this symbolic record resides at ntdll. When an attacker overwrites the SEH Handler he has to overwrite the "Next" pointer as well, which breaks the SEH Chain.

SEHOP performs a SEH Chain walk whenever an exception triggered and attempt to reach the final symbolic record by following the "Next" pointers in the SEH Chain, if it fails to reach the final symbol it assumes the chain is corrupted and was overwritten and proceed to terminate the process safely.

Stack Canaries / Security Cookies

Can be Defeated by:

Defends Against:

  • Control Flow change via Stack Overflow

How Does it Work:

After a function is being called, amongst other things, the return address is pushed to the stack which indicates where to jump back and continue execution once the current function finishes its purpose.

Attackers may overwrite the return address and point to there own malicious code and once the RET instruction is hit, the execution flow will jump to the malicious code.

Stack Canaries are unique and random values that are push after the RET address (Lower address on the stack) and contain a specific value that gets validated before jumping to the return address.

Attackers must overwrite the canary in order to also overwrite the return address that points to their code, once the validation of the canary fails an exception occurs.

Safe Unlinking - WIP

Can be Defeated by:

  • PLACEHOLDER

Defends Against:

  • Use-After-Free Exploit - Unsafe Heap Chunk Unlink

How Does it Work:

This is extremely simplified - Read How a Heap Works or consider that this is a partial explanation

A Heap is a dynamic memory area that allows dynamic allocation of data, a certain range of memory addresses is reserved to the heap on process start which can be later extended on-demand.

The heap's memory address range and divided to "Chunks". Chunks can be Allocated or Free Chunks. If a Chunk is Free you can allocate it to a program that requests memory to be allocated to the heap. if it's already allocated it cannot be allocated.

The heap allocator manages a doubly-linked list structure of Free Chunks. Each Free chunks points to the Next free chunks (where ever it might be) and to the Free Chunks behind it.

When we call Free() to free an allocated chunks, the heap allocator calls unlink() which removes a Free chunks from the doubly-linked Free list. To maintain the correctness of the Free list, unlink() need to fix the pointers of the previous and forward chunks of the chunk we allocated so that they wouldn't point to the now allocated chunk.

Fixing the linked list pointer with the Unsafe unlink() would the the backward-pointer and forward-points of chunk we allocated and write to the respective chunks that were adjacent to the allocated chunks.

Free Chunks Doubly-linked list BEFORE unlink()

  • chunk1

    • backward-pointer -> chunk0

    • farward-pointer -> chunk2

  • chukn2

    • backward-pointer -> chunk1

    • farward-pointer -> chunk3

  • chunk3

    • backward-pointer -> chunk2

    • farward-pointer -> chunk4

Free Chunks Doubly-linked list AFTER unlink()

  • chunk1

    • backward-pointer -> chunk0

    • farward-pointer -> chunk3

  • chunk3

    • backward-pointer -> chunk1

    • farward-pointer -> chunk4

What is Unsafe here?

The Unsafe operation is that the overwrite if the pointers of the adjacent chunks occurs without verifying that the adjacent chunks points to the allocated chunks

Last updated