nice thread...

Anyhow...Attacks using techniques like your talking about, work on the principle that it is possible under the right circumstances to alter the return address of a function to allow execution of an attackers code. When the code must branch and follow another execution path, it must have a way to remember where the split occured, so that it can continue execution there when it's done. Basically the value of EIP is pushed unto the stack; a branch of code is ran; and then EIP is pop'ed back of the stack and execution continue's there. So now you should be getting a clearer picture of how it's possible to alter the return address of a function, by writing data to the stack.

As far as the NOP sled thing...
sec_ware is totally right...It's to simplify the exploitation. Shellcode can be written that uses
precise addresses. However, this takes considerable more time to code, and isn't really portable at all because so many variables come into play that effect where and how the code is loaded into memory, that an attack has to be VERY specific (For this OS version, running binaries X,Y,Z, but not W...ect)...The NOP sled simply avoids all this by giving you some padding to point EIP.