Friday, April 1, 2011

Evolution of race condition exploits (CVE-2011-0727 trickery)

I recently did a PoC for CVE-2011-0727. It was possible
to have a one shot exploit for a race condition which
is just a few (2 or 3 or so) syscalls in range.
I compared it with an old exploit I did in 2002
for OpenBSD/FreeBSD against pppd. I uploaded it for
historical reasons so you can see the evolution of
race condition exploits.


In userland almost all race
conditions (time of check - time of use: TOCTOU-exploits)
cook down to races in the filesystem. While in kernel
you also have other shared resources like pages in userland
or counters.


The situation around 2000 or before was that most systems only
have had one core (single CPU) and therefore there was
no real concurrency. The scheduler had to interrupt the
target process just in the right time and have the
exploit process chosen to run afterwards.
How did one achieve that in 2000? Slow down the box
with many processes which a) increases the overall chance
that the target process is put asleap inside the race
(nice(2) calls also help if applicable)
and b) having many exploitation processes increases chances
of an exploitation process to be picked up next.
As can be seen in pppdx.pl ,one process was always
switching between a real file and a symlink and another
was constantly forking of a lot of pppd processes.
Sometimes, this needed a bit of tuning, depending on how
fast the target machine was. But eventually after a few
minutes it used to succeed.


Years after that a new framework was introduced on Linux
where one could register notification hooks which were
called when a certain event happened (e.g. creating the
target file). In early times you needed to register a signal
handler which was delivered and nowadays there is
the inotify framework which allows to register hooks for
almost all use-cases. I used inotify in the KDM exploit.
It saves the exploit coder from creating a lot of
processes which constantly poll for an event because
reading from the event descriptor just returns when the
event happened. On single CPU systems one might still need
to fork a lot of processes since the scheduler must put the
target process to sleep at the right time nevertheless.


Now we have 2011, and writing race condition exploits
for file races has never been easier. Even the
cheapest mom-and-dad PC has got at least 2 cores, probably
more. Therefore we have true concurrency since we can
make the target process run on a different CPU-core than
the exploitation process. Therefore we no longer rely
on scheduler to interrupt the target at the right time.
We can just poll or sleep on an event with a single process
and are still fast enough with changing the target file.
One just has to ensure that (if more than 2 cores exist)
multiple exploitation processes do not interfer
with each other if the event happens.
The CVE-2011-0727 GDM PoC is doing exactly that.
With the KDM exploit it basically worked the same
(best on multi-core CPU systems) but with using
the inotify framework.













2 comments:

Anonymous said...

the font color and background color make your blog impossible to read

synapse said...

Great post :)