10 ms·
Fun with Gentoo: Why don't we just shuffle those ROP gadgets away?
- somat 4y agoOpenbsd also puts a fair amount of work into removing ROP gadgets. For example. https://marc.info/?l=openbsd-cvs&m=152824407931917 https://marc.info/?l=openbsd-cvs&m=152824407931917
- rtev 4y agoVery cool, thank you for sharing! Not only does ROP facilitate traditional binary exploitation, but it’s also used in cutting-edge evasive techniques. By abusing ROP instead of direct calls, red teamers are able to heavily obfuscate activities from endpoint detection and response.
- rtepopbe 4y agoUh, yeah... The post opens with a mention of being inspired by OpenBSD and goes into some detail on differences between their approach and OpenBSD's throughout.
- saagarjha 4y agoThough, much less effective than reordering gadgets.
- matzf 4y agoDon't try this with C++, unless you're certain that there are no interdependencies or side-effects in global variable initialisation. The link order (usually) affects the order in which initialisers are executed.
- Asooka 4y agoOn the contrary: do do this and if you observe your program crashing due to linking order, fix the damn bug.
- londons_explore 4y agoDoes the C++ spec guarantee initialization order? Or is any application that depends on it relying on undefined behaviour?
- theg5prank 4y agoThere's no mandated order between compilation units. It's a problem significant enough to have its own snarky name: the Static Initialization Order Fiasco https://en.cppreference.com/w/cpp/language/siof https://en.cppreference.com/w/cpp/language/siof
- frankjr 4y agoI'm guessing "dev-libs/openssl shuffleld" should go into "/etc/portage/package.env" instead (in the appendix).
- crtxcr 4y agoGood catch, thx!
- lucideer 4y ago> The potential issue comes from the assumption that all .o files will be given continuously in the command line. The assumption appear to hold, but could blow up down the road. But well, it's hack. Other than this issue (which may well be a large / unsolvable one), I wonder what other disadvantages to this approach there might be. Does this hack have any potential for a Gentoo profile or mainlining?
- phkahler 4y ago>> As a side-effect, reproducible builds, which this technique breaks, are less of a concern anyway (because you've compiled your system from source). Reproducible builds verify the source code and build process (including options) were the same. Not sure how important each aspect is. Also, if for some reason you rebuild a dependency, you'll need to relink everything that depends on that. This could get messy, but it's still interesting.
- Hydraulix989 4y agoWhy? If the dependencies are dynamically loaded libraries it shouldn't matter?
- cbrozefsky 4y agoControl over the RNG seed, and tracking that seed as an 'input', would be a way to get reproducible builds while still having randomization.
- withinboredom 4y agoIsn’t it impossible to have truly from-scratch reproducible builds? IIRC, you have to trust the compiler which can’t be built from scratch.
- ectopod 4y agoYou can bootstrap the compiler. It's a chore but not impossible. More usefully, you can check that your builds are identical to other people's, so at least your compiler isn't uniquely compromised.
- londons_explore 4y ago> You can bootstrap the compiler. It's a chore but not impossible. And specifically, only one person needs to do this once... I'm surprised there isn't some project doing this...
- 4y ago
- vlovich123 4y agoI wonder if just shuffling it on every release (even minor) isn’t sufficient (and actually even publishing that order). That doesn’t have full security benefit (attackers have a finite set of options) but keeps reproducible builds and the ability to distribute pre-linked binaries while raising the attack complexity significantly since no two machines are likely running the exact same version. That means an exploit has to try several different versions. Taking this a step further, create link N randomly sorted copies per version and randomly distribute those. Now the space to search through is large and the probability of picking the correct gadget variant goes down with 1/MN where there are M releases being attacked and N variants per release that might be installed (a targeted attack or an attack of a specific version only gets 1/N). Additionally, deterministic builds maintain your ability to audit binaries and their providence fairly easily (only grows linearly) while the risk of noticing the attempt without a successful exploit is N-1/N. I’m not saying it’s perfect but it seems like a reasonable defense for binary distribution. As someone who used to run Gentoo, I’d say most people are in favor of the faster times to install a new package. EDIT: extending this idea further, I wonder if compilers can’t offer a random seed to supply that causes a random layout of the sections within a built execution so that even statically linked binaries benefit from this.
- deleted 4y ago[deleted]
- notpushkin 4y agoFor binary distributions, how about shipping object files and linking them on install with mold? This should be faster than compiling from source, just marginally slower than installing pre-linked binaries, and each build will be as unique as it gets.
- vlovich123 4y agoThe size of the distributed binary gets very large because you're shipping a lot of code that ends up getting eliminated by the linker. Also if you want to do any kind of LTO, then I don't see how you do it in your model. (which is significant for the larger applications like Chrome that have the likely attack surface). Not every binary on the system actually needs this either. Finally, the main problem with this idea is that you can't audit malware because there's no way to maintain a source of truth about what the binary on a given system should be. Distributing randomly linked copies solves that because you can have a deterministic mapping based on machine characteristics (you do have to keep this hash secure but it's feasible). You'd basically be maintaining N copies of your distro with randomly built binaries with the user being given a random one to install. And to be clear, my better idea is to do this at the compiler level so that you randomize the relative location of functions. That way it's impossible to find any gadget to grab onto and you have to get information leakage from the machine you're attacking & this information leakage has to be repeated for each machine you want to compromise.
- jchw 4y agoI like this idea. I have an idea for something that would be cool, if impractical: Imagine a GCC wrapper that doesn't actually link, but produces a bundle that performs the linking in randomized order in realtime and then runs. I think that you could do this quite well on NixOS, and I'm now intrigued to try to rig up a proof-of-concept when I can find the time. Side-effect: Does not work for libraries without a significantly more complex wrapper that certainly could not work for all libraries. Though, you could re-order the objects within a static library fairly easily.
- xxpor 4y agoThat'd make process startup EXTREMELY slow
- jchw 4y agoIt's pretty much what OpenBSD is doing at bootup. Truthfully though you're right, using typical linkers, this would be pretty slow; at least a few seconds for large binaries, to minutes for things as large as web browsers. However, for many binaries, linking can be done much faster; mold claims to be only 50% the runtime of using `cp` on the object files, which is fast enough to even re-link Firefox on-the-fly without it being unusable. You could imagine writing a linker specifically for this case, that encodes information about the object files directly into the resulting bundle.
- hermitdev 4y agoOne gap to this approach: gcc can use argument files (pass a file that contains the actual arguments). I've only really seen this with build systems that expect to work on large numbers of arguments that will not fit on the command line. Still, something to be aware of.
- crtxcr 4y agoI'll keep an eye on that, thx!
- kwhitefoot 4y agoROP gadgets?
- Karellen 4y agohttps://en.wikipedia.org/wiki/Return-oriented_programming https://en.wikipedia.org/wiki/Return-oriented_programming > Return-oriented programming (ROP) is a computer security exploit technique that allows an attacker to execute code in the presence of security defenses[1][2] such as executable space protection and code signing.[3] > In this technique, an attacker gains control of the call stack to hijack program control flow and then executes carefully chosen machine instruction sequences that are already present in the machine's memory, called "gadgets".[4][nb 1] Each gadget typically ends in a return instruction and is located in a subroutine within the existing program and/or shared library code.[nb 1] Chained together, these gadgets allow an attacker to perform arbitrary operations on a machine employing defenses that thwart simpler attacks.
- atlgator 4y agoI remember my Gentoo days freshman year in college. I spent more time compiling updates than actually using the computer.
- dzmien 4y agoI do all world updates overnight for this very reason. But on my R5 3600, the longest emerge is, by far, qtwebengine, which takes just under 1.5 hours. Plus, Gentoo provides -bin versions of many packages notorious for protracted build times, such as Rust, Chromium, Firefox, etc...
- gerdesj 4y ago-bin seems like a strange thing when you are doing Gentoo, which is all about compile locally. Gentoo has always been about choice and -bin is a choice. However you lose USE flag choice decision with a -bin. The possible combinations that Gentoo allows looks to me like a sort of Linux immune system in action. Quite a few "unpopular" flags will get used (lol USEd) somewhere by someone that will be more motivated on average to log a bug somewhere. Gentoo also got the console shell look (colours, fonts etc) right way before any other distro. It's copied widely.
- account42 4y agoSure, binary packages don't reduce choice though since they are available in addition to the normal packages (except for stuff that is not open source at all). Wanting to have control over config via use flags for your system doesn't mean that there aren't packages were you don't really need that. Like if you only use Libre Office a couple times per year on your aging laptop, do you really care enough about the exact USE config to justify compiling it yourself? Even more so if you need it on short notice. Or if you only use Chromium/whatever to check that your website works with that browser but don't actually use it yourself, why bother compiling it. IIRC there used to be a Gentoo fork (forgot the name) that extended this concept to all packages, so if you used default USE flags you did not need to compile things yourself.
- 4y ago
- yazzku 4y agoDeep feels from that web design. Simple, aesthetic, functional.
- gigel82 4y agoHow does this work with dynamic libraries (shared objects). In Windows land, you get a .lib with a .dll and afaik that has hardcoded function addresses. You statically link the "import library" .lib with your exe, so if you randomize the function addresses and rebuild just the .dll later, it blows up (you need to rebuild all exes as well). Is dynamic linking in Unix world truly runtime-only (a-la "GetLibrary" / "GetProcAddress")?
- account42 4y agoUnix/ELF doesn't have seperate .lib and .dll files - you link directly against the .so (or a linker script, but those are typically only used for special system libraries). The main thing this does is record the name from the DT_SONAME field of the .so as a requied dependency in your binary. But I also don't think that this would be a problem on Windows. After all, you can generally replace DLLs with entirely different versions and you'll be fine as long as all the required symbols are present and ABI-compatible. The main difference between ELF and PE dynamic linking is that with PE you have a list of required symbols along with the libraries to load those symbols from while with ELF you have a list of required libraries and a list of required symbols but not information recorded about which symbols should come from which libraries.
- ngneer 4y agoWhy not prevent control transfer to the ROP gadget?
- PeterisP 4y agoBecause we are unable to do that, and we've tried for decades. There are all kinds of things we're doing (e.g. rewriting things in memory-safe languages) to make it less likely for an attacker to become able to control a jump to somewhere, however, we don't expect to fully succeed any time soon, and this is defense in depth against cases when attackers once again do find a way to control transfer to some arbitrary gadget.
- deleted 4y ago[deleted]
- ShredKazoo 4y agoLack of reproducible builds seems like a big cost here. I wonder if there's a way to do just-in-time random relinking such that the performance cost is low, but the security benefit is still strong. Just-in-time gets you reproducible builds, and also addresses the "local attackers who can read the binary or library" problem. There would be a performance cost in terms of startup time, but since the number of possible permutations is a factorial function of the number of possible linking orders, it seems like even a very coarse-grained random relinking can go a long way. You could accomplish this by doing static analysis of a binary to generate a file full of hints for ways to rewrite the binary such that its behavior is provably equivalent to the original. Then there could be a wrapper (perhaps at the shell or OS level) which uses the hints to randomly relink on the fly just prior to execution. Another advantage is that this approach should be feasible on an OS like Ubuntu where everything is precompiled. However the static analysis part could be a little tricky? I'm not familiar with the state of the art in static analysis of compiled binaries. Performance-sensitive users could be given a way to turn the feature off, in cases where fast startup time was more important than security.
- lxgr 4y agoDo reproducible builds even matter if you're building/linking and executing a binary on the same system? The biggest benefit seems to be in making it infeasible/dangerous for a malicious actor to distribute binary versions containing different behavior from the published source. On a local machine, when and with what would you compare your binaries?
- ShredKazoo 4y agoSure, just think of it as a way to get the same benefit on a precompiled system like Ubuntu I guess.
- deleted 4y ago[deleted]