Exploitation of Buffer Overflows Under Windows XPSince the dawn of the computer age, coders and admins alike have been plagued with a fearsome and
powerful enemy. This creature is difficult to avoid, since it takes advantage of the very design system of modern computers
to live. Rarely taking the same form twice, this beast was originally created by the combination of a lack of foresight during
the creation of some of the worlds most popular and powerful languages, and was supported wholly
by the unsuspecting systems it has plagued.
Hitchhiker's World (Issue #8)
http://www.infosecwriters.com/hhworld/
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++ Exploitation of Buffer Overflow Vulnerabilities Under Windows XP ++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++ Exploiting User Applications: A Case Study ++
+++++++++++++++++++++++++++++++++++++++++++++++++++
++ WideChapter.exe ++
++ http://www.widechapter.com ++
+++++++++++++++++++++++++++++++++++++++++++
++ By Peter Winter-Smith ++
++ [peter4020@hotmail.com] ++
+++++++++++++++++++++++++++++++++++
Section 1. A General Introduction to Buffer Overflows
=====================================================
Since the dawn of the computer age, coders and admins alike have been plagued
with a fearsome and powerful enemy. This creature is difficult to avoid, since
it takes advantage of the very design system of modern computers to live.
Rarely taking the same form twice, this beast was originally created by the
combination of a lack of foresight during the creation of some of the worlds
most popular and powerful languages, and was supported wholly by the
unsuspecting systems it has plagued.
For you see, this work of evil is deceptive; the system on its own is blind
and perhaps foolishly trusting. On it's own it would not be able to recognise an
attack being mounted against it even after it had been carried out. It is this
ability which gives the creature it's unique nature. There are many ways in
which it can achieve a successful attack, and it is often able to outwit the
very people who created the conditions under which it was able to thrive.
Although you may feel unaffected by this, I can say with total and complete
confidence that if you have ever used a computer which had access to the outside
world, no matter how important it was, you were vulnerable to attack. If you
have not been attacked you can be sure that luck had a huge role to play in
that.
One famous application was designed to infiltrate system after system. It was
one of the first of it's kind. Instead of taking the form of an attacker
attempting to gain unauthorised access it used the design flaws to upload itself
to the victim, and then went on to replicate itself, and search for others to
attack.
It was commonly known as the Morris Worm, after it's author Robert Morris was
convicted upon the grounds of substantial evidence arising from his research
work.
Two other, more recent worms, both of which were spread on a much larger scale
than the Morris Worm, are the SQL Slammer, and most recently the MSBlaster
worm, both of which took advantage of widespread stack based buffer overflows in
Microsoft Windows systems. The holes existed in Microsoft SQL Server, and the
Windows RPC Interface respectively, and caused many computers to become infected
over the period of a few days.
Although these malicious applications can cause hold-ups, loss of money and
business, and pose many a potential problem to the remote systems, you can often
consider yourself lucky if your computer was infected, because it's highly
likely that otherwise a remote attacker would have been able to assume complete
control over the system, and could have used it whatever malicious ends he
desired.
The more observant of you will probably have noticed that I have not yet
actually attempted to explain what a buffer overflow is, how it can occur, and
where they are commonly found; so I had better make haste to do that!
To cut a long story short, a buffer overflow condition arises when more data
is allowed to be written to a specific point in the memory than was set out to
hold that data. Often data will be written to the stack memory area, which is
where buffers local to a specific procedure are usually created.
When a function is called, a return address is placed onto the stack by the
application, which the function uses to know where to return to in the
previously run executable code once the function has completed.
Often the base pointer is placed onto the stack by the function, the stack
pointer is placed into the base pointer register, and a pre-defined amount of
space is created on the stack by subtracting a value from the stack pointer
register. Data is written on to the stack by instructions such as 'push', and is
placed at the address contained in the stack pointer register.
When the function has completed, the 'leave' instruction moves the base pointer
back into the stack pointer register, then 'pops' the saved base pointer off of
the stack so that the stack pointer is pointing at the saved return address.
Then the 'retn' instruction (or some close variant) pops that off the stack into
the instruction pointer register which causes the execution flow to go back to
the application code, one instruction after where it executed the call.
A lot of the functions work with strings, such as strcpy(), which copies a
string from a memory location to another memory location, strcat() which adds
one string of data onto another in the memory, and gets(), which takes user
input from stdin, and places it into a buffer. Much of the time these functions
are used with input which the user of the software can control, such as a
request for a username, or a password, or even a the path of a file - basically
any string input area is potentially vulnerable depending on how the coder has
worked with the data afterwards. When the afore mentioned instructions (along
with many others) are used with user input, the combination is *lethal*.
Strings are asciiz in win32, which means that they are only considered as having
ended when a null byte (00h) is encountered. Strings in C and C++ are declared
with a fixed length, for example 'char string[16];' would create a 16 byte
buffer, and 'char string2[]="THISSTR";' would create an eight byte buffer.
Strings are dealt with in multiples of four (rounding up), so if you declare a
character array of 10 bytes, it will be 12 bytes long, and if you declare one of
37 bytes length, it will be 40 in memory.
If you take a moment to think about what each of these instructions do, you will
notice that each of them will just take data from one area of memory, and place
it into another area. So, here is the big question, how do they know when to
stop copying? When they copy data from one area of memory, what makes the
function think 'okay, we've reached the maximum character count of the buffer'?
The truth is, for these functions there is no such inhibitive intuition which
the application possesses, and so it just stops copying when it reaches a null
byte in the memory area which is having data taken from it, copying/moving byte
by byte into the target buffer until it reaches that null. This procedure is
fatal.
The reason this procedure is fatal, is the fact the buffer often lies right
behind the values placed onto the stack after a function is called. Supply
enough data, and you can leak out of the buffer and overwrite those values, most
dangerously the return address, which would mean that when the function reached
the 'retn' instruction, it would try and continue to execute code from an
address which you supplied!
From here you have a wealth of options, including:
(a) Crash the application by pointing to a bad memory area which it cannot read
from.
(b) Cause the application to jump to a restricted area of code within itself,
for example to b