Hi. You're still with me?
Good. This time, we'll talk about the classic security risk,
the buffer overflow problem.
This problem is a combined hardware and software problem.
It occurs with the x86 instruction set,
because the call instruction which is used to call subroutines,
pushes the return address from the call onto the stack.
The RET instruction returns by popping the top of the stack to the program counter.
The exploit hinges on the ability to corrupt the value on top of the stack,
to redirect the execution flow.
In other processors, MIPS and ARM for example,
the jump and link MIPS instruction or the branch and link
ARM instruction store the return address in a special register.
Register 31, case of MIPS,
register 30 in the case of ARM.
Nested subroutine calls while taken care of automatically by
the x86 instruction set, requires the programmer,
and we're on the assembly language level here,
to manually store nested return addresses on the stack of the called subroutines.
Nevertheless, there are a lot of x86 processors out
there and they're the ones who are vulnerable to this attack.
Next we need to understand how a stack is used in the x86 world.
In a method which is not to say in the global space,
temporary storage needed by the method is automatically allocated on the stack.
If your subroutine requires an integer and a 20-character buffer declared in that order,
then the method is called,
the return address is written on the top of the stack,
the stack pointer is pushed 24 bytes further down.
The 20 character string is stored at the address pointed to by a stack pointer,
and the four byte integer will be at the stack pointer plus 20.
If everything works normally,
when the RET instruction is called,
the stack pointer is moved 24 bytes up and
the next word is popped off the stack written to the program counter.
The stack pointer is moved up four more bytes and the return is complete.
If we write a value to the integer on the stack,
a four byte word will always be stored at
the location the machine understands as integer.
The processor will always write four bytes there,
no more no less.
However the case of a string is different.
If the string is created by the subroutine itself,
chances are, you won't make it longer than the 20 character buffer you created.
However, if the source of your string is outside your program,
there is a danger that it will be longer than the allocated buffer.
The normal string copy method simply copies byte for byte,
until it reaches a zero byte.
It doesn't know how large the allocated buffer is.
Therefore if you have a 23 byte string with zero in the 24th byte,
you will start writing at the beginning of your string buffer,
and go past the end of it overwriting the integer variable that you had declared.
If you write four bytes further than that,
you're overwriting the return address.
So here is the exploit.
You can redirect the program flow to a location of your choice.
To make this work,
you have to know where you want to jump to.
You also need to know how calling parameters are laid out on the stack.
In C and C++, calling parameters for a method are pushed onto
the stack in right to left order before the call instruction is executed.
So if the method you're calling by replacing
the return address on the stack requires calling parameters,
they will be written in the string example
after the return address is overwritten on the stack.
A defense against this is called address space layout randomization, ASLR.
It attempts to thwart attacks by moving
the operating system routines around in memory at boot time.
ASLR, like many other defenses have been defeated by
side channel attacks on the branch prediction buffer.
So a successful exploit would first involve using a buffer overflow to execute your code,
then figuring out where
the key entry points in the operating system are currently located,
and then using those to go do your work.
Other defenses exist too.
The paging system, marked pages as containing executable code, as read-only.
It marks read-write pages as not executable.
There are also techniques for circumventing these protections.
Alright so what's the point?
It looks like all defenses set up to mitigate
a buffer overflow attack can be compromised.
So get rid of the root cause.
This is either not checking a string for length,
or having string variables declared on the stack.
It's also being careful when using pointers.
These mitigations can be included in coding standards and
policies which you as a designer can control.
So like Nike says, just do it.
I hope you've gotten a general idea of how some exploits work.
And most critically, the notion that they are both hardware and software dependent.
Your attackers have studied the situation from both angles.
You should too. Thanks for your time.