lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Thu, 19 Jul 2012 22:37:59 -0400
From: valdis.kletnieks@...edu
To: Glenn and Mary Everhart <everhart@....com>
Cc: full-disclosure@...ts.grok.org.uk
Subject: Re: A modest proposal

On Thu, 19 Jul 2012 21:08:47 -0400, Glenn and Mary Everhart said:

> If every copy of a program is laid out differently, and data gets moved
> around also from copy
> to copy, the job of the attacker would seem to get much harder.

As is the job of the software development team.  It's really easy to write code
that uses different combos of opcodes to achieve the same result (heck, just
feed the program to hydan and stand back) - but that doesn't help because 'char
a[50];  for (i=0;i<50;i++) a[i+1]=a[i];'  remains exploitable no matter what
set of opcodes you use to implement it.

So indeed, you need "different in form but same in function".  This is a lot
harder than it looks - download the source for Firefox, or Emacs, or any other
large package.  Find some random function that's 100-200 lines long.  Now
re-write it in a totally different form without introducing any bugs.  Now do
that 3 or 4 more times (after all, only having 2 variants doesn't make things
much harder for the attacker).  Oh.. then find a bug report against that
function, and make the code fix at least once, possibly in every version,
depending on whether or not the other 4 versions have the same bug.

And then repeat that for a semantic change to the function - it's now
passed an added parameter it has to do something with.  Implement
it correctly in all 5 versions. ;)

Now do this for several dozen or maybe a hundred or so function - you have to
do this to enough functions that for any given copy, there are enough
*different*  combination of (say) module size that you can't easily distinguish
between "sub1_variant4_sub9_variant2", "sub4_variant3_sub37_variant6", and a
large set of others.  Remember that even if there's a few billion variants, you
can iterate through them *all* and see which ones total up to the required
number in just a few seconds.   If you're a good programmer, you can
probably even fit all the data needed into just a dozen lines in the L1
cache and *really* chug through the variants.

And they really *do* need to be "same in function" - if it's a function to
apply gamma correction to an RGB image, your 5 or 6 variants need to produce
bitwise identical results (or the users will file bug reports)  And they need
to run in roughly the same amount of time, both to prevent timing attacks to
determine which variant is in use, and to avoid "every 37th call to
gamma_correct() takes far too much CPU time" bug reports.

And you *will* get bitten by the difference between the function's documented
behavior, and the actual behavior that other functions depend on.  Wander over
to the linux-kernel mailing list, and look at how often a developer will
replace a function with a new implementation - only to have it flame out on one
CPU type/speed due to a timing issue, or crashes because locking is done in a
subtly different way, or because the new code reveals a hidden assumption in
some *other* piece of code, or...

Your software debugging team will hate you as well.  Rather than nice easy
replicatable bugs when function A calls B which calls C, you'll have one crash
when A1 calls B7 calling C2, incorrect output when A1 calls B5 calling B2, a
hang anytime A4 calls B1, and a totally unexplained data corruption issue once
in every several thousand runs that you may or may not find before your heavy
drinking causes cirrosis of the liver...

tl;dr: We don't know how to efficiently write and maintain non-buggy complex
software - if we did, we'd not need defenses against things that exploit bugs.
Adding *more* complexity can't possibly improve the situation (do the math - if
there's N exploitable bugs per K-line of code, how many additional exploitable
holes do you add when you toss in 27K more lines of code to implement multiple
versions of 12 functions?)


Content of type "application/pgp-signature" skipped

_______________________________________________
Full-Disclosure - We believe in it.
Charter: http://lists.grok.org.uk/full-disclosure-charter.html
Hosted and sponsored by Secunia - http://secunia.com/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ