Bugtraq mailing list archives

Preventing /*exploitation with*/ rebasing


From: "Riley Hassell" <rhassell () eeye com>
Date: Wed, 5 Feb 2003 17:42:13 -0800


So the course of this talk with most likely go into generating a totally
dynamic address space and once again, end in another theoretical solution,
to an overly complex problem.

Defeating Rebasing
-------------------------------------

Many operating systems with fault handling features and refined
multitasking, reference address spaces with segments to permit these
features and aid general performance. The majority of this behavior can be
studied by following process creation and task switching. Start from the
user API and step through until the entry point of the executable is
reached.

TEB: Thread Environment Block
TIB: Thread Information Block
PEB: Process Environment Block

The TEB/TIB fs:[] segment references originated in the OS2 days and have
since passed down into 9x client systems, and of course, Windows NT. During
the process creation the PEB and TIB are initialized into the new virt and
can be referenced by the fs segment. Modifying the address space referenced
by fs and how fs is setup is possible... but by the time you're done you're
designing a new operating system.

As Ryan might say... It's all data ;) The data referenced in this delta can
be referenced during a ret. You just need to find a set of bytes that forms
the needed instruction. You may be able to modify this arena in a way that
you can insert your own instructions. Maybe some of the TLS storage can be
controlled by supplying malformed sizes in your exploit session... ;)

Note: PEB locking pointers can be overwritten with format bugs and control
structure based heap overflows.

7FFDF000  00010000
7FFDF004  FFFFFFFF
7FFDF008  01000000  <- Executable image base ;)
7FFDF00C  00071E90
7FFDF010  00020000
7FFDF014  00000000
7FFDF018  00070000
7FFDF01C  77FCF170  <- PEB fast Lock entry point
7FFDF020  77F8313C  <- PEB lock entry point
7FFDF024  77F8316D  <- PEB unlock entry point

Brett Moore wrote me several months ago with a very interesting exploit
concept using multiple writes. The first write you insert your needed
instruction into writeable memory somewhere. The second write you overwrite
some writeable entry point or hook, with the address of the inserted
instruction.

There's not much out there if you're interested in learning about the TIB
and the PEB. If you really want to understand these structures and general
loading behavior, learn Polish and Russian, then hit up some VX'er archives.
If you end up talking to any of them, tell them that somebody is trying to
stop exploits by rebasing dll's :)

Rebasing... There's a reason why relocation sections exist. While doing your
own relocations is possible, the design of such a system is extremely, and
I'll say again, extremely complex. Just differentiating all the instructions
from data is a fairly painful process. Maybe the ETCH guys did this at one
point but as far as I know this has been a big hurdle in image modifcation
for quite some time.

Michal Zalewski provided some great examples of issue's you'll run into:

MZ> Also, what if I wanted to pass a value 4325404 (0x42001c) to this
MZ> function, and it is not a pointer, only looks this way? For example,some
MZ> FOO_ASYNC flag is defined as 0x400000, FOO_LOCK as 0x020000, and
voila,OR
MZ> them and you have "a pointer".
MZ> In other cases, say, with register calls, it is getting even nastier,
MZ> because even if, one way or another, you managed to find out how every
MZ> single function is going to use its parameters (not likely), register
MZ> calls are still black magic.

GetProcAddress ACL's...


It is possible to intercept every call to GetProcAddress and determine
whether or not the call should be authorized based on a predetermined list
of known valid callers (runtime call stack analysis).

Simply rewrite a micro GetProcAddress. GetProcAddress is basically an
overstuffed RVA engine. This is defeated by "The payload brings the tools
concept". Most userland hooking schemes can also easily be bypassed by using
direct gates "Ex: Interupts Gates". You could also intercept a thread that
has the neccesary privelege by snagging a hook in it's path.

This list of authorized callers must be constructed through the use of
forensic profiling
tools in the case of other people's binaries, but can be constructed with
the help of additional API calls in the case of one's own code. Call a
profiling/tracing API before calling GetProcAddress. After compilation but
before deployment to production boxes you simply execute the code in
profile
mode to generate a list of authorized callers. This list is then
configured
as a static security setting adhered to by the security layer that sits
between GetProcAddress and the rest of the virtual world.

Who's an authorized caller?

Someone who has a "safe" caller address on the stack....

If a the attacker start's offering instructions to your CPU... kiss your ass
goodbye.
Research AV/VX trends from the late 80's and early 90's.

-R

Riley Hassell
Security Research Associate
eEye Digital Security

[DOW]



Current thread: