I have a 0-day exploit, but don't want to tell you what it is
I have a 0-day exploit, but don't want to tell you what it is
- Subject: I have a 0-day exploit, but don't want to tell you what it is
- From: Michael Crawford <email@hidden>
- Date: Tue, 30 Jul 2013 09:42:46 +0000
A while back, I stumbled across a way to root my own box by opening a
specially-crafted document with a widely-used program.
While I expect I could supply a defect report, test case and a patch
to the maintainer, my concern is that doing so would result in
widespread breakins, that would occur to those who don't update the
software in question once my patch has been applied.
This particular exploit is not the only one I know about. I know
about lots of others, based for the most part on what others attempt
to break in to my own systems. One such exploit - which doesn't
affect me - is attempting to exploit a bug in some code that has not
been updated in several years.
Rather than fixing just this one specially-crafted document exploit, I
propose to assist the community in fixing a great many exploits. I
expect that by doing so, the ones that concern me will get fixed
before long. I have the hope that after they are patched, the fixes
will be in widespread use before they are discovered to be security
holes.
Many but not all security holes are simple bugs. For example, if you
have a simple crash bug that occurs due to a buffer overflow, there
may be a way to open a specially crafted document, or receive a
specially crafted network packet, that overwrites a subroutine return
address on the stack, with the result that an attempt to return
actually needs your code to jump into some arbitrary machine code.
Of all the things I know how to do with computers, I am the very best
at debugging code. I credit this in large part to Robert Ward's book
"Debugging C". I read the first edition; there is a second edition
with a somewhat different title that I have not read it.
Both editions are long out of print, but I expect can be had quite cheaply used.
Most coders that I know approach debugging in an Ad Hoc fashion, by
just beating their heads against bugs in hopes of fixing them somehow.
That does work to an extent, but really is not very effective, is a
poor use of your time, and is a poor use of your employer's or
client's money.
Ward, by contrast, recommends on apply The Scientific Method to each bug:
1. Observe, then document some defective behavior.
2. For a hypothesis as to what is causing the defect.
3. Design an experiment that could falsify the hypothesis.
4. Carry out the experiment.
5. If your experiment does indeed falsify your hypothesis, then you
need a new hypothesis.
6. If your experiment does _not_ falsify your hypothesis, then you may
need a new experiment. Perhaps you now have enough information to
actually fix the defect.
A common misconception of The Scientific Method is that one can
_prove_ hypotheses. In general, that is not the case. The best one
can really hope for is to falsify lots of stuff, thereby gaining some
confidence - but only _some_ confidence - in what one hopes to, but
can never really prove.
If you apply Ward's Scientific Method procedure to your defect reports
in a methodical manner, you will quickly find your defects getting
fixed.
I have a number of specific recommendations for fixing your code. If
there are any that you do not yet take advantage of, the chances are
quite good these will make your life easier.
- Use a memory debugger. There are several kinds.
Bundled with Xcode, and available to iOS in the Simulator but not on
devices, is Guard Malloc. It places each memory allocation on its own
VM pages, with unmapped pages in between. If you try to write - or
read - outside of allocated buffers, you're likely to trip an
exception.
There are a number of similar tools available for other platforms,
such as Electric Fence and BoundsChecker.
After you get your code running cleanly with Guard Malloc, use
Valgrind (http://www.valgrind.org/). Again this works for the iOS
Simulator, but not yet for devices.
Valgrind performs far-stricter validation than do MMU tools like Guard
Malloc, by running your executable in a CPU simulator, then validating
every memory reference. Guard Malloc will only catch memory
references that don't fall on a VM page, but Valgrind will catch those
that do fall on a page, but outside an allocated buffer.
I'm not completely clear, but my understanding is that Valgrind will
catch references that should go to one buffer, but addressing the
wrong buffer. For example:
char bogus;
char *ptr;
char theA = 'A';
char theB = 'B';
ptr = &theA;
bogus = *(ptr + sizeof( char ) ); // bogus is _probably_ now 'B'
When you take the address of an item, the allowable range of addresses
that you can dereference in the resulting pointer, is bound to the
range of addresses of the item whose address you took. There are lots
of ways to dereference such a pointer, that would not cause a crash,
but do result in logic errors.
If you do not yet use automated testing for your code, there are lots
of ways to do so that you're likely to find helpful. There are vast
numbers of tools and code libraries to support you in this.
The Portland Pattern Repository documents many automated testing techniques:
http://c2.com/cgi/wiki?WelcomeVisitors
A particularly powerful technique is that, once having gotten a new
test to work, to run it from time to time under a tool such as
Valgrind.
John Lakos has a great deal to say about automated testing in "Large
Scale C++ Software Design". Much of what he discusses applies just as
well to other languages than just C++.
For example his "Levelization" is not, in my experience, widely
practiced, despite being a powerful and effective technique for
improving both implementation and architectural quality.
Most test harnesses that I know about, are set up to enable unit tests
in the context of the entire executable.
By contrast, one Levelizes a codebase by simply assuming that the
operating system, and vendor- or os-supplied libraries are flawless.
One then identifies the lowest-level code modules, that depend only on
the OS and the libraries. One writes unit tests first for those
lowest-level modules.
One then identifies one's second-level modules, that depend only on
the first-levels, or on the os and libraries. One then writes unit
tests that address _only_ what is new in each second-level module.
If one finds that a second-level test is failing due to a defect in
one's first-level code, one writes a test for the first-level module
that is suspected. Only after obtaining a failing test does one
actually fix the bug.
Of course, operating systems and libraries cannot be counted upon to
be flawless. One just makes this assumption when testing one's own
code. If one's tests fail due to OS or vendor defects, then one
reports those defects to the responsible party, then either works
around the problem somehow, or awaits a fix.
In Lakos Levelization, each such unit test is a separate executable,
with only the necessary modules linked in. For a large codebase, that
will result in many small executables, but most of them will be very
simple.
If you've never levelized your own codebase, you're likely to find
that it is not at first levelizable. There are likely to be many
dependencies all over the place, so that rather than a simple,
pyramidal heirarchy of dependencies, many modules will depend on other
modules without any meaningful heirarchy.
If that's the case, you would make your life a lot easier by
refactoring your codebase so that it is levelizable.
My own "libmdc" is designed to enable this kind of levelization and
unit testing from C++. It comes with some GNU Makefiles for building
the test executables, that should be readily adaptible for most
compiled languages, not just C++:
http://www.warplife.com/source-code/libmdc/
libmdc is Free Software, published under the terms of the Boost
Software License, version 1.0:
http://www.warplife.com/source-code/libmdc/current/LICENSE_1_0.txt
Boost 1.0 is quite similar to the three-clause BSD license, but
clearly has had a good attorney improve upon the original BSD.
There is quite a lot more that I should say, but I figure what I've
written so far would be a good start.
I'm going to mark this mail up in HTML, then post it on my site at:
http://www.warplife.com/tips/code/security/fix-everything/
Just for now, there is an empty placeholder directory there. I'll get
started at marking this up after I post it to the list.
You could really help a brother out, were you to forward this mail -
or the above link, once I publish the actual page - to anyone that you
genuinely feel would be interested in, or would benefit from it.
Ever Faithful,
Mike Crawford
email@hidden
http://www.warplife.com/
Available for mobile development in or near Portland, Oregon.
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Xcode-users mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden