brian e. brzezicki. this tutorial just illustrates the underlying concepts of buffer overflows by...
TRANSCRIPT
Just the basics
This tutorial just illustrates the underlying concepts of buffer overflows by way of an extremely simple stack overflow Most buffer overflow concepts derive from
these concepts This techniques is for basic understanding,
they are not advanced techniques This technique described as is will not
work in any modern OS due to compiler and OS protections
Key Terms
To understand buffer overflow requires understanding a few terms
IP register Function Stack
IP register
A special memory location directly on the CPU which holds the address in memory of the next instruction to be executed On Intel IA32 architectures it is called EIP On Intel IA64 architectures it is called RIP
* if an attacker can set the value of this register, they can direct the CPU to execute their instructions
Stack
A data structure in system memory where data is stored temporarily Stacks usually grow down from lower to
higher memory addresses, as data is added to the stack
Memory Address
Value
1000 First stack variable
9996
9992
…
Stack
A data structure in system memory where data is stored temporarily Stacks usually grow down from lower to
higher memory addresses, as data is added to the stack
Memory Address
Value
1000 First stack variable
9996 Second stack variable
9992
…
Stack
A data structure in system memory where data is stored temporarily Stacks usually grow down from lower to
higher memory addresses, as data is added to the stack
Memory Address
Value
1000 First stack variable
9996 Second stack variable
9992 Third stack variable
…
Stack
A data structure in system memory where data is stored temporarily Stacks usually grow down from lower to
higher memory addresses, as data is added to the stack
Memory Address
Value
1000 First stack variable
9996 Second stack variable
9992 Third stack variable
… …
Function
A small part of a program that performs a specific action or function Programs are comprised of many functions
main() {
char [8] string;
printf(“hi there how are you?”);
gets(string);
}
Function
A small part of a program that performs a specific action or function Programs are comprised of many functions
main() {
char [8] string;
printf(“hi there how are you?”);
gets(string);
}
* printf and gets are functions
How functions use the stack
When a function is called any parameters passed to the function are added to the stack
add(x,y);
printf(“hi there”);Memory Address
Value
1000
9996
9992
…
How functions use the stack
When a function is called any parameters passed to the function are added to the stack
add(x,y);
printf(“hi there”);Memory Address
Value
1000
9996
9992
…
How functions use the stack
When a function is called any parameters passed to the function are added to the stack
add(x,y);
printf(“hi there”);Memory Address
Value
1000 y
9996
9992
…
How functions use the stack
When a function is called any parameters passed to the function are added to the stack
add(x,y);
printf(“hi there”);Memory Address
Value
1000 y
9996 x
9992
…
How functions use the stack
After the parameters are added to the stack, the memory address of the next instruction after the function is put on the stack
add(x,y);
printf(“hi there”);Memory Address
Value
1000 y
9996 x
9992
…
How functions use the stack
After the parameters are added to the stack, the memory address of the next instruction after the function is put on the stack (return address)
add(x,y);
printf(“hi there”);Memory Address
Value
1000 y
9996 x
9992 address_of printf(“hi there”);
…
How functions use the stack
Any local variable that the function uses will be placed on the stack after the return address.
sub add(x,y) {
int total;
total=x+y;
return(total);
}
Memory Address
Value
1000 y
9996 x
9992 address_of printf(“hi there”);
…
How functions use the stack
Any local variable that the function uses will be placed on the stack after the return address.
sub add(x,y) {
int total;
total=x+y;
return(total);
}
Memory Address
Value
1000 y
9996 x
9992 address_of printf(“hi there”);
… total
How functions use the stack
Once the function completes, the local variables will be removed from the stack
sub add(x,y) {
int total;
total=x+y;
return(total);
}
Memory Address
Value
1000 y
9996 x
9992 address_of printf(“hi there”);
… total
How functions use the stack
Once the function completes, the local variables will be removed from the stack
sub add(x,y) {
int total;
total=x+y;
return(total);
}
Memory Address
Value
1000 y
9996 x
9992 address_of printf(“hi there”);
…
How functions use the stack
Finally the CPU will load the memory address that is on the stack into the IP register and continue execution at that point
sub add(x,y) {
int total;
total=x+y;
return(total);
}
Memory Address
Value
1000 y
9996 x
9992 address_of printf(“hi there”);
…
Finally the CPU will load the memory address that is on the stack into the IP register and continue execution at that point
sub add(x,y) {
int total;
total=x+y;
return(total);
}
How functions use the stack
Memory Address
Value
1000 y
9996 x
9992 address_of printf(“hi there”);
…
IP Register = address_of printf(“hi there”);
The exploit
The key of an buffer overflow is to 1. get your own code (shellcode) into
memory2. overwrite the function return
address to point to the memory location of your code
Exploitable function
interactWithUser(int x) { char msg=“please enter input”; char[8] input;
printf(“%s”,msg); gets(input); return();}
Exploitable function
interactWithUser(int x) { char msg=“please enter input”; char[8] input;
printf(“%s”,msg); gets(input); return();}
In this function the line above is vulnerable, as it takes any length input and tries to store it into the location assigned to input which is only 8 bytes long
Exploitable function
interactWithUser(int x) { char msg=“please enter input”; char[8] input;
printf(“%s”,msg); gets(input); return();}
Memory Address
Value
1000 x
9996 return address
9992 ut
9988 inp
9984 nter
9980 se e
9976 plea
9972 input variable cont
9968 input variable space
Exploitable function
interactWithUser(int x) { char msg=“please enter input”; char[8] input;
printf(“%s”,msg); gets(input); return();}
Memory Address
Value
1000 x
9996 return address
9992 ut
9988 inp
9984 nter
9980 se e
9976 plea
9972 input variable cont
9968 input variable space
Exploitable function
interactWithUser(int x) { char msg=“please enter input”; char[8] input;
printf(“%s”,msg); gets(input); return();}
Memory Address
Value
1000 x
9996 return address
9992 ut
9988 inp
9984 nter
9980 se e
9976 plea
9972 input variable cont
9968 input variable space
Exploitable function
interactWithUser(int x) { char msg=“please enter input”; char[8] input;
printf(“%s”,msg); gets(input); return();}
Memory Address
Value
1000 x
9996 return address
9992 ut
9988 inp
9984 nter
9980 se e
9976 plea
9972 input variable cont
9968 input variable space
Exploitable function
interactWithUser(int x) { char msg=“please enter input”; char[8] input;
printf(“%s”,msg); gets(input); return();}
Memory Address
Value
1000 x
9996 return address
9992 ut
9988 inp
9984 nter
9980 se e
9976 plea
9972 input variable cont
9968 input variable space
Exploitable function
interactWithUser(int x) { char msg=“please enter input”; char[8] input;
printf(“%s”,msg); gets(input); return();}
When the input is read from the user, the data will be stored in the space allocated for the input variable
Memory Address
Value
1000 x
9996 return address
9992 ut
9988 inp
9984 nter
9980 se e
9976 plea
9972 input variable cont
9968 input variable space
Exploitable function
interactWithUser(int x) { char msg=“please enter input”; char[8] input;
printf(“%s”,msg); gets(input); return();}
When the input is read from the user, the data will be stored in the space allocated for the input variable
Memory Address
Value
1000 x
9996 return address
9992 ut
9988 inp
9984 nter
9980 se e
9976 plea
9972 input variable cont
9968 input variable space
Exploitable function
interactWithUser(int x) { char msg=“please enter input”; char[8] input;
printf(“%s”,msg); gets(input); return();}
When the input is read from the user, the data will be stored in the space allocated for the input variable
Memory Address
Value
1000 x
9996 return address
9992 ut
9988 inp
9984 nter
9980 se e
9976 plea
9972 input variable cont
9968 input variable space
Exploitable function
interactWithUser(int x) { char msg=“please enter input”; char[8] input;
printf(“%s”,msg); gets(input); return();}
You could enter your own code when prompted to “please enter input”
Memory Address
Value
1000 x
9996 return address
9992 ut
9988 inp
9984 nter
9980 se e
9976 plea
9972 input variable cont
9968 input variable space
Exploitable function
interactWithUser(int x) { char msg=“please enter input”; char[8] input;
printf(“%s”,msg); gets(input); return();}
You could enter your own code when prompted to “please enter input”
Memory Address
Value
1000 x
9996 return address
9992 ut
9988 inp
9984 nter
9980 se e
9976 plea
9972 input variable cont
9968 input variable space
Exploitable function
interactWithUser(int x) { char msg=“please enter input”; char[8] input;
printf(“%s”,msg); gets(input); return();}
You could enter your own code when prompted to “please enter input”
Memory Address
Value
1000 x
9996 return address
9992 ut
9988 inp
9984 nter
9980 se e
9976 plea
9972 input variable cont
9968 your shellcode
Exploitable function
interactWithUser(int x) { char msg=“please enter input”; char[8] input;
printf(“%s”,msg); gets(input); return();}
You could enter your own code when prompted to “please enter input”
Memory Address
Value
1000 x
9996 return address
9992 ut
9988 inp
9984 nter
9980 se e
9976 plea
9972 your shellcode
9968 your shellcode
Exploitable function
interactWithUser(int x) { char msg=“please enter input”; char[8] input;
printf(“%s”,msg); gets(input); return();}
If you enter more than 8 characters, you will start overwriting the other data on the stack
Memory Address
Value
1000 x
9996 return address
9992 ut
9988 inp
9984 nter
9980 se e
9976 plea
9972 your shellcode
9968 your shellcode
Exploitable function
interactWithUser(int x) { char msg=“please enter input”; char[8] input;
printf(“%s”,msg); gets(input); return();}
If you enter more than 8 characters, you will start overwriting the other data on the stack
Memory Address
Value
1000 x
9996 return address
9992 ut
9988 inp
9984 nter
9980 se e
9976 your shellcode
9972 your shellcode
9968 your shellcode
Exploitable function
interactWithUser(int x) { char msg=“please enter input”; char[8] input;
printf(“%s”,msg); gets(input); return();}
If you enter more than 8 characters, you will start overwriting the other data on the stack
Memory Address
Value
1000 x
9996 return address
9992 ut
9988 inp
9984 nter
9980 your shellcode
9976 your shellcode
9972 your shellcode
9968 your shellcode
Exploitable function
interactWithUser(int x) { char msg=“please enter input”; char[8] input;
printf(“%s”,msg); gets(input); return();}
If you enter more than 8 characters, you will start overwriting the other data on the stack
Memory Address
Value
1000 x
9996 return address
9992 ut
9988 inp
9984 your shellcode
9980 your shellcode
9976 your shellcode
9972 your shellcode
9968 your shellcode
Exploitable function
interactWithUser(int x) { char msg=“please enter input”; char[8] input;
printf(“%s”,msg); gets(input); return();}
If you enter more than 8 characters, you will start overwriting the other data on the stack
Memory Address
Value
1000 x
9996 return address
9992 ut
9988 your shellcode
9984 your shellcode
9980 your shellcode
9976 your shellcode
9972 your shellcode
9968 your shellcode
Exploitable function
interactWithUser(int x) { char msg=“please enter input”; char[8] input;
printf(“%s”,msg); gets(input); return();}
If you enter more than 8 characters, you will start overwriting the other data on the stack
Memory Address
Value
1000 x
9996 return address
9992 your shellcode
9988 your shellcode
9984 your shellcode
9980 your shellcode
9976 your shellcode
9972 your shellcode
9968 your shellcode
Exploitable function
interactWithUser(int x) { char msg=“please enter input”; char[8] input;
printf(“%s”,msg); gets(input); return();}
Now you’ve overwrote the local stack variables… if you write more you’ll overwrite the return address
Memory Address
Value
1000 x
9996 return address
9992 your shellcode
9988 your shellcode
9984 your shellcode
9980 your shellcode
9976 your shellcode
9972 your shellcode
9968 your shellcode
Exploitable function
interactWithUser(int x) { char msg=“please enter input”; char[8] input;
printf(“%s”,msg); gets(input); return();}
If you put the address of the start of your shellcode, when the function returns the IP will be loaded with the address of your shellcode
Memory Address
Value
1000 x
9996 9968
9992 your shellcode
9988 your shellcode
9984 your shellcode
9980 your shellcode
9976 your shellcode
9972 your shellcode
9968 your shellcode
Exploitable function
interactWithUser(int x) { char msg=“please enter input”; char[8] input;
printf(“%s”,msg); gets(input); return();}
If you put the address of the start of your shellcode, when the function returns the IP will be loaded with the address of your shellcode
Memory Address
Value
1000 x
9996 9968
9992 your shellcode
9988 your shellcode
9984 your shellcode
9980 your shellcode
9976 your shellcode
9972 your shellcode
9968 your shellcode
Exploitable function
interactWithUser(int x) { char msg=“please enter input”; char[8] input;
printf(“%s”,msg); gets(input); return();}
Then the system will run your shell code instead of returning to the normal program!
Memory Address
Value
1000 x
9996 return address
9992 your shellcode
9988 your shellcode
9984 your shellcode
9980 your shellcode
9976 your shellcode
9972 your shellcode
9968 your shellcode
You control the execution
Now you have Successfully input your own code in
memory Directed the system to execute your
code
Additional things to think about / need to solve
How did we know where our shellcode’s address is in memory?
How do we determine the shellcode? Don’t programs generally generaly
filter input for un-allowed characters?
What happens if the system uses a Non-eXecutable stack / memory or Address Space Layout Randomization (ALSR)