Stack Overflows - Defeating Canaries, ASLR, DEP, NX

  • To prevent buffer overflows, there are several protections available such as using Canary values, ASLR, DEP, NX. But, where there is a will, there is a way. I am researching on the various methods an attacker could possibly bypass these protection schemes. It looks like there is no one place where clear information is provided. These are some of my thoughts.

    Canary - An attacker could figure out the canary value and use that in his buffer injection to fool the stack guard from detecting an exploit

    DEP, NX - If there are calls to VirtualAlloc(), VirtualProtect(), the attacker could try to redirect code to these functions and disable DEP, NX on the pages that he wants to inject arbitrary code on.

    ASLR - No clue . How do ASLR and DEP work?

    This 2014 paper describes a technique they call Blind Return Oriented Programming (BROP) that is like ROP but doesn't even require knowledge of the source or binary.

  • Polynomial

    Polynomial Correct answer

    9 years ago

    Canary
    Stack canaries work by modifying every function's prologue and epilogue regions to place and check a value on the stack respectively. As such, if a stack buffer is overwritten during a memory copy operation, the error is noticed before execution returns from the copy function. When this happens, an exception is raised, which is passed back up the exception handler hierarchy until it finally hits the OS's default exception handler. If you can overwrite an existing exception handler structure in the stack, you can make it point to your own code. This is a Structured Exception Handling (SEH) exploit, and it allows you to completely skip the canary check.

    DEP / NX
    DEP and NX essentially mark important structures in memory as non-executable, and force hardware-level exceptions if you try to execute those memory regions. This makes normal stack buffer overflows where you set eip to esp+offset and immediately run your shellcode impossible, because the stack is non-executable. Bypassing DEP and NX requires a cool trick called Return-Oriented Programming.

    ROP essentially involves finding existing snippets of code from the program (called gadgets) and jumping to them, such that you produce a desired outcome. Since the code is part of legitimate executable memory, DEP and NX don't matter. These gadgets are chained together via the stack, which contains your exploit payload. Each entry in the stack corresponds to the address of the next ROP gadget. Each gadget is in the form of instr1; instr2; instr3; ... instrN; ret, so that the ret will jump to the next address on the stack after executing the instructions, thus chaining the gadgets together. Often additional values have to be placed on the stack in order to successfully complete a chain, due to instructions that would otherwise get in the way.

    The trick is to chain these ROPs together in order to call a memory protection function such as VirtualProtect, which is then used to make the stack executable, so your shellcode can run, via an jmp esp or equivalent gadget. Tools like mona.py can be used to generate these ROP gadget chains, or find ROP gadgets in general.

    ASLR
    There are a few ways to bypass ASLR:

    • Direct RET overwrite - Often processes with ASLR will still load non-ASLR modules, allowing you to just run your shellcode via a jmp esp.
    • Partial EIP overwrite - Only overwrite part of EIP, or use a reliable information disclosure in the stack to find what the real EIP should be, then use it to calculate your target. We still need a non-ASLR module for this though.
    • NOP spray - Create a big block of NOPs to increase chance of jump landing on legit memory. Difficult, but possible even when all modules are ASLR-enabled. Won't work if DEP is switched on though.
    • Bruteforce - If you can try an exploit with a vulnerability that doesn't make the program crash, you can bruteforce 256 different target addresses until it works.

    Recommended reading:

    Excellent post, minor question: I've never heard the term "NOP spray" but it seems equivalent to a "NOP sled" or "NoOP sled" which more closely describes the action of sliding over the intervening memory to get somewhere good. Is that one and the same as you're referring to, or is there a subtle distinction that makes "NOP spray" a separate thing? Thanks...

    Yep, a NOP spray and a NOP sled are exactly the same thing. I've just been playing with heap sprays recently, so I went for the terminology that was on the top of my head.

    @Polynomial : In your answer here :http://security.stackexchange.com/questions/18556/how-do-aslr-and-dep-work you had mentioned hardware enforcement of NX. So, will bypassing DEP using ROP (using `VirtualProtect()`) still work if NX bit is hardware enforced ?

    Yes. The NX bit just provides hardware enforcement of the executable memory page protection flag. With NX disabled, it's trivial to execute pages that don't have the executable bit set, because the processor won't recognise the difference. With NX enabled, you cannot execute non-executable pages. However, `VirtualProtect` alters the protection flags on the page, so it actually is marked as executable, which the CPU will then allow.

    @Polynomial : It seems it don't apply to heap overflows, isn’it ?

    @user2284570, please don't post the same comment under every answer. Yes, it applies to heap overflows.

    An observation reg NX: on Linux 2.6.38 onwards on the IA-32, if the cpu supports it the NX bit will _always_ be enabled regardless of the BIOS setting of the same. See the commit here: https://github.com/torvalds/linux/commit/ae84739c27b6b3725993202fe02ff35ab86468e1

License under CC-BY-SA with attribution


Content dated before 7/24/2021 11:53 AM