Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

What is return-oriented programming? Recursion?


Return-oriented programming is an exploit technique that relies on reusing snippets of existing code (called gadgets) in a program in order to carry out attacker code. Each gadget generally ends with a return instruction, which causes it to read the address of the next gadget off the stack and jump to it. In this way, arbitrarily complex code can be built up by chaining together sequences of gadgets controlled by an initial set of return addresses on the stack.

It's used as a way to defeat DEP (Data Execution Prevention); with DEP the attacker can no longer write code into memory and then execute it, so instead they just set up the stack cleverly so they can carry out a return-oriented payload (most commonly, these payloads just disable DEP and then move on to a more traditional second stage).

More info:

The paper that introduced the name ROP (though some would argue that the techniques existed before this paper): https://cseweb.ucsd.edu/~hovav/dist/geometry.pdf

Wikipedia: https://en.wikipedia.org/wiki/Return-oriented_programming


If you're interested in learning about exploit writing, you might want to check this page : https://www.corelan.be/index.php/articles/ .


It looks like it's an exploit technique where the stack is modified to set up malicious calls to functions: https://en.wikipedia.org/wiki/Return-oriented_programming


That's not really the essence of ROP because other attack techniques often also need to manipulate the stack. The key novel idea in ROP is to use data in unintended ways. This is based on the insight that the memory often contains short sequences of bytes (e.g. a .jpg image) that can be interpreted as machine instructions. For example an mp3 file might contain the sequence 99 19933, 16 which translates to

    increment register 16
    return
in the ambient machine language. Call that "dual use data". ROP searches the memory for sufficient "dual use data" and then builds an ac-hoc compiler with "dual use data" as target language. Then the attack software compiles to "dual use data" and then runs the compiled code.

Of course one may ask: can we always find enough "dual use data" to build a Turing-complete set of instructions as a compilation target. Turns out that with high probability that is the case.


ROP gadgets are usually harvested from libraries loaded into the program, not MP3 files.

The key novel idea in ROP is to use instruction sequences in unintended ways. ROP is a refinement of ret2libc, improving on it by returning into arbitrary locations in functions rather than their entry points. That, and of chaining together gadgets with returns. Hence the name.


It is true that "ROP gadgets are usually harvested from libraries loaded into the program, not MP3 files", but that's not because there's something intrinsically wrong with mp3s as source of gadgets, it's just that mp3s are often not executable. I have emphasised mp3s and jpgs precisely to emphasise what' novel about ROP, namely that any data can be used as machine language.


Yeah this just doesn't seem like an illuminating example in practice. In practice, gadgets for ROP chains are harvested from program text. It's for that reason that so much effort is expended in many exploits on memory leaks that reveal the locations of libraries loaded into memory.


Thanks. Is this because it's mostly programs that live in executable space on a well-maintained machine or because gadgets can be precomputed (at least in parts) which makes compilation easier? (Not that that is mutually exclusive!)


Both of those are true.


None of that should be marked executable, though. The real risk in ROP is using little bits of legitimate functions to bypass DEP.


That is true, I should have been more clear about this but you don't use the "legitimate function"'s intended functionality, you only use the fact that it can be execute (and the byte-string that is it's code).

I used mp3s and jpgs as extreme examples of data that was never intended to be executed, but still can be interpreted as code. In ROP, you don't care about the intended meaning of the bytes that make up "legitimate functions" (or any other data you may use) for it's unlikely to have the sought functionality. Instead you use you search for "dual use code" too, and piece together the functionality you need.


Well, but you missed that data can not be executed.

Unless you store your MP3s and jpegs in .text, the memory pages all that stuff is in are marked not executable and will only cause a crash if you jump to it. Regardless of whether the bytes make useful instructions.


Data can be executed if it is in the executable part of the memory. There is quite a lot of such data. In particular, code is data!


Why is this post downvoted? This idea of (mis)using code is part of the essence of ROP! Could somebody please explain where I'm wrong, so I can learn?


I didn't downvote it, but I feel like your comments have been technically correct but practically misleading.

It's possible to have executable data, but if you do, you generally have bigger problems: the exploit can simply write a complete first-stage into the data and execute it directly, and not bother going through return-oriented contortions.

The reality is that gadget harvesting is about analyzing program text --- actual binary machine instructions --- not about looking for ways to interpret JPEGs or MP3s or (I wrote DOCX and then PDF and then thought "huh bad examples") RTF files as instruction streams.

It's also true that you can exploit insane x86 encoding to synthesize unintended instructions, but that's (I think) less important than the simpler idea of taking whole assembled programs, harvesting very small subsequences, wiring them together with a forged series of stack frames, and achieving general computation.


Right. But in practice ROP targets the executable portions - any and all of them. If someone leaves something executable that they shouldn't, it'll use that. If only code is left executable, it's still often able to use that.

Remember, x86 can be parsed differently depending on offset. You jump into the middle of a multibyte instruction you get an entirely different instruction stream. And x86 doesn't have any real protection against that.


You may however be able to get different legitimate instructions than originally intended by jumping to an address in the middle of a multi-byte instruction that happens to decode into a useful series of operations. It follows that there are more usable "returns" in a body of code than just those written in the original source.


There are a multiple usable "returns" in functions because "return" is just "pop" then "jump", so a block that has the effect of manipulating the stack and then transferring control can often be used to the same effect as a return.


on 32-bit x86 the RET instructions are 0xC3 and 0xCB. Any other instruction containing these bytes can be subverted into a return if you can make the processor read the preceding instructions from the wrong starting point.


Sure; the authors in the Roemer paper found a couple of those. The best place to get a sense of how this works is the "Gadget Catalog" section of that paper.


Don't forget the variants with a stack-adjusting immediate, 0xC2 and 0xCA. Those can also come in handy.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: