[HN Gopher] Fun with Gentoo: Why don't we just shuffle those ROP...
       ___________________________________________________________________
        
       Fun with Gentoo: Why don't we just shuffle those ROP gadgets away?
        
       Author : crtxcr
       Score  : 104 points
       Date   : 2023-01-26 14:57 UTC (8 hours ago)
        
 (HTM) web link (quitesimple.org)
 (TXT) w3m dump (quitesimple.org)
        
       | jiripospisil wrote:
       | I'm guessing "dev-libs/openssl shuffleld" should go into
       | "/etc/portage/package.env" instead (in the appendix).
        
         | crtxcr wrote:
         | Good catch, thx!
        
       | hermitdev wrote:
       | One 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 wrote:
         | I'll keep an eye on that, thx!
        
       | lucideer wrote:
       | > _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?
        
       | jchw wrote:
       | I 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 wrote:
         | That'd make process startup EXTREMELY slow
        
           | jchw wrote:
           | It'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.
        
             | blibble wrote:
             | I thought openbsd did it after boot?
        
               | dfox wrote:
               | OpenBSD relinks sshd. Which is relatively small thing
               | that is linked from relatively large objects (ie. it is
               | the typical modern C code). Relinking thing like glibc on
               | demand is going to be problematic, because it is
               | structured as to allow small binary sizes for static
               | linking and thus almost every function that is part of
               | glibc API is a separate compilation unit and object file.
               | Linking that into .so is slow, no mater what kind of
               | optimalization tricks you implement in the linker.
        
               | jchw wrote:
               | Yeah. That said, I'm suggesting that if it was really too
               | slow, though, it'd probably be infeasible to relink libc,
               | the kernel, etc. at bootup. It's not a direct comparison
               | to be sure.
        
       | somat wrote:
       | Openbsd also puts a fair amount of work into removing ROP
       | gadgets.
       | 
       | For example.
       | 
       | https://marc.info/?l=openbsd-cvs&m=152824407931917
        
         | rtev wrote:
         | Very 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 wrote:
         | Uh, 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.
        
       | vlovich123 wrote:
       | I 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.
        
         | notpushkin wrote:
         | For 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 wrote:
           | The 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.
        
             | dfox wrote:
             | Randomizing the link order per release does not solve
             | anything, for this to really work as an mitigation layer,
             | you need to have few different randomly linked versions and
             | randomly give these to the end users. Just randomizing the
             | build does not solve anything as there still is exactly one
             | layout that everyone uses.
             | 
             | On another note: automating this on gentoo is cool
             | exercise, but almost certainly if you just build everything
             | locally, the memory layout will be random enough that
             | writing shellcode blindly presents an interesting
             | challenge. (different compiler flags, various probabilistic
             | optimization passes... all that leads to the functions in
             | same object file having different sizes)
        
         | [deleted]
        
       | matzf wrote:
       | Don'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.
        
         | londons_explore wrote:
         | Does the C++ spec guarantee initialization order? Or is any
         | application that depends on it relying on undefined behaviour?
        
           | theg5prank wrote:
           | There'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
        
         | Asooka wrote:
         | On the contrary: _do_ do this and if you observe your program
         | crashing due to linking order, fix the damn bug.
        
           | matzf wrote:
           | Fair enough :) I just meant to point out what could go wrong.
        
           | jchw wrote:
           | Developer PoV vs User/Distro PoV here :P you're not wrong,
           | though...
        
       | phkahler wrote:
       | >> 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.
        
         | cbrozefsky wrote:
         | Control over the RNG seed, and tracking that seed as an
         | 'input', would be a way to get reproducible builds while still
         | having randomization.
        
         | Hydraulix989 wrote:
         | Why? If the dependencies are dynamically loaded libraries it
         | shouldn't matter?
        
         | withinboredom wrote:
         | Isn'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 wrote:
           | You 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 wrote:
             | > 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...
        
               | yjftsjthsd-h wrote:
               | There is: https://savannah.nongnu.org/projects/stage0/
        
             | withinboredom wrote:
             | I don't think it's possible since you'd need the original
             | compilers from the 70's and bootstrap other compilers up to
             | a modern one. Otherwise your existing compiler could taint
             | your new one.
        
               | ectopod wrote:
               | Many years ago I wrote a C compiler in assembly language.
               | It wasn't hard, and C hasn't changed that much. The
               | complexity in modern compilers is in the optimisation,
               | which you don't need if you're bootstrapping. It's not
               | impossible.
        
               | chameco wrote:
               | It'd be a fun exercise to write a tiny Forth in machine
               | code (sans assembler) and use it to write enough of a C
               | compiler to build tcc, or something along those lines.
               | From there I think you can chain old (but accessible) gcc
               | versions up to modern gcc.
        
       | kwhitefoot wrote:
       | ROP gadgets?
        
         | Karellen wrote:
         | 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 wrote:
       | I remember my Gentoo days freshman year in college. I spent more
       | time compiling updates than actually using the computer.
        
         | batman-farts wrote:
         | These days my 5950X can get through some of the big scary
         | packages quite rapidly. Firefox is done in about 8 minutes, a
         | new point release of Rust seems to take about 15.
         | 
         | I still haven't decided whether or not I should be embarrassed
         | that I mainly bought a 16-core CPU to run Gentoo.
        
         | aquafox wrote:
         | I remember praying before every 'emerge -uDav world' that I
         | won't have to deal with fixing my system for the next 2 hours.
        
         | eMPee584 wrote:
         | Same thing for me. 2003 it was .. and gentoo was a well good
         | entry vehicle into linux
        
           | atlgator wrote:
           | We're the same age! I remember printing off a ~20 page
           | runbook of instructions to manually build and configure grub
           | and gentoo. Took hours to set up.
        
             | TylerE wrote:
             | Why did I never think of printing it? I'd open it in lynx
             | on a 2nd framebuffer (I forget the proper term... the
             | things that were like Alt+Shift+an Fkey or something)
        
               | gerdesj wrote:
               | Console 8)
        
         | TylerE wrote:
         | I remember installing from stage1 on a 1ghz-ish single core.
         | Just something like kde2 would take hours, and that's not even
         | counting the dependencies. Anything bigger than a command line
         | tool was something you'd kick off before going to bed and pray
         | it didn't error. (Spoiler: It almost always did)
        
         | dzmien wrote:
         | I 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 wrote:
           | -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.
        
         | gerdesj wrote:
         | I used to keep using the boxes whilst steam billowed out the
         | sides until things started crashing.
         | 
         | I recall gcc3 -> 4. The prevailing "wisdom" was emerge --deep
         | (etc) world ... twice! My laptop was left for around a week
         | trundling through 1500 odd packages. I think I did system
         | first, twice too. I left it running on a glass table in an
         | unheated study, propped up to allow some better airflow.
         | 
         | One of the great things about Gentoo is that a completely
         | fragged system doesn't faze you anymore. Screwed glibc? Never
         | mind. Broken python? lol! Scrambled portage? Hold my beer.
         | 
         | I have a VM running in the attic that got a bit behind. OK it
         | was around eight? years out of date. I ended up putting in a
         | new portage tree under git and reverting it into the past and
         | then winding it forwards after getting the thing up to date at
         | that point in time. It took quite a while. I could have started
         | again but it was fun to do as an exercise.
        
       ___________________________________________________________________
       (page generated 2023-01-26 23:01 UTC)