4

How do exploit developers counter control-flow integrity (CFI) used to prevent ROP-based buffer overflow attacks?

Originally, return-oriented programming (ROP) was invented to counter the no-execute (NX) protection of the stack, by jumping from different memory locations (executable) to execute code (gadgets).

However, control-flow integrity (CFI) is meant to prevent ROP-based execution by dynamically checking the destinations of jumps for validity, i.e., it is no longer possible to jump to arbitrary locations in executable code (only to the beginning of functions etc.)

How does exploit developers counter CFI to exploit NX-protected programs using buffer overflows?

  • @forest - I wasn't aware that there were different types of CFI. Although there is no way to bypass it for ROP, has something entirely different been invented that make buffer-overflows feasible? Or are buffer-overflows impossible, given that the CFI protecting is good enough. – Shuzheng Nov 4 '18 at 11:31
  • I never said there is no way to bypass it, I said there is no way to bypass ideal CFI (forward and backward edge, fine-grained, and deterministic), but 99% of things that call themselves CFI are not like that. – forest Nov 5 '18 at 2:17
4

There are many types of CFI. However, CFI that supports both forward and backward edge protection, is deterministic, and is also fine-grained is very rare to come by (the only concrete example I know of is the commercial version of PaX RAP). Most CFI is coarse-grained, which means that a function can return not to only that one function, but to a number of functions with the same function signature (that is, the same return type and exact same arguments). Forward edges come from jumps and calls, whereas backward edges come from returns. The vast majority of CFI only supports one or the other (such as Microsoft's CFG or Clang's CFI), vastly limiting its capabilities.

Another issue with CFI is that it is often probabilistic, using some secret value. Any infoleaks that expose that secret value could be used to break the CFI. Deterministic CFI does not suffer from this, but most deterministic CFI is very coarse-grained. In summary:

  • Most CFI is not both forward and backward edge, severely limiting its capabilities.

  • Most CFI is probabilistic, making it vulnerable to infoleaks that can break it.

  • Most CFI is coarse-grained, letting you return to groups of functions with the same signature.

You can learn a lot more about actual CFI implementations by checking out kCFI and PaX RAP, the only two which I know of that provide full forward and backward edge protection. Unfortunately, since CFI is such a complex topic and there's no one implementation or even technique for CFI, there's no way to answer exactly how an attacker can bypass it without specifying the implementation.

  • Thank you @forest for a very good answer. Why don't Microsoft use PaX RAP then? Is it because the program suffers to much w.r.t. time and size? – Shuzheng Nov 4 '18 at 13:44
  • @user111854 Actually, RAP has almost no perf impact and does not increase program size. The reason it is not used is because it is owned by Open Source Security Inc. and they do not like giving it out for free (in fact, the commercial version is very, very expensive). CFI in real-world products is actually a rather new thing, and not many people know how to do it correctly. Not to mention, it requires modifying the program to be compatible (more precisely, modifying it to be "correct", since things like bad fptr casts will break it). – forest Nov 5 '18 at 2:16
  • Ahh, so you actually have to make your program compatible. CFI is not just another compiler pass, which is completely transparent from the user's point of view. I guess, it will be hard to adapt HUGE projects to be compatible with CFI? – Shuzheng Nov 6 '18 at 16:36
  • @user111854 It is indeed hard to adapt huge products, but it is absolutely possible. And there are some (weaker) forms of CFI which do not require extensive modifications to source code, but that kind of CFI is also a lot easier to bypass. – forest Nov 6 '18 at 22:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.