Given at Black Hat USA 2008 Briefings. Aug. 2008.
We describe return-oriented programming, a generalization of return-into-libc that allows an attacker to undertake arbitrary, Turing-complete computation without injecting code.
New computations are constructed by linking together code snippets that end with a “ret” instruction. The ret instructions allow an attacker who controls the stack to chain instruction sequences together. Because the executed code is stored in memory marked executable, W^X and DEP will not prevent it from running.
W^X and DEP, along with many other security systems, make the assumption that preventing the introduction of malicious code is sufficient to prevent the introduction of malcious computation. With the return-oriented computing approach, this assumption is false: subverting control flow on the stack is sufficient to construct arbitrary computation from “known-good” code.
On the x86 one can obtain useful instruction sequences by jumping into the middle of intended instructions, but return-oriented programming is possible even on RISC platforms that are very different from the x86.