Software Vulnerabiliites
Software Vulnerabiliites
Unexpected behaviour
When a program's behaviour is specified,
spec usually lists the things the program
must do
Most implementers wouldn't care if it did
additional things as well
caused
by
Fixing Faults
You might argue that a module in which
100 faults were discovered and fixed is
better than another in which only 20 faults
were discovered and fixed
more rigorous analysis and testing had led to
the finding of the larger number of faults
Fixing Faults
Early
Types of Flaws
Most common sources of unintentional
security flaws
Buffer overflows (Buffer is intended to hold predefined amount of data in memory)
Incomplete mediation
An application needs to ensure that what user
has entered constitutes a meaningful request
Verifying that the subject is authorized to
perform the operation of an object is called
mediation
Incomplete mediation occurs when the
Types of Flaws
Serialization: program flow order
permit asynchronous behavior of different system components to
be exploited (TOCTTOU- time-of-check-to-time-of-use)
Race Condition
Two processes execute concurrently and the outcome of the
computation depends on the order in which instructions of the
processes execute
Buffer overflows
The single most commonly exploited type of
security flaw
Simple example:
#define LINELEN 1024
char buffer[LINELEN];
gets(buffer);
or
strcpy(buffer, argv[1]);
Memory Exploits
Simplest buffer exploit: supply executable code as
data, trick victims machine into executing it
Code will self-propagate or give attacker control over
machine
Buffer Overflows
Example
Suppose each of the ten elements of the array
sample is filled with the letter A and the
erroneous reference uses the letter B, as follows:
for (i=0; i<=9; i++)
sample[i] = 'A';
sample[10] = 'B'
In the second case, the 'B' goes into the user's program area
If it overlays an already executed instruction
no effect
Stack Buffers
Suppose a Web server contains function
void func(char *str) {
char buf[126];
strcpy(buf,str);
}
buf
sfp
Local variables
ret
addr str
Frame of the
calling function
Top of
stack
buf
overflow
str
Frame of the
calling function
Top of
stack
ret
str
Frame of the
calling function
Top of
stack
Used
for global
constants
& variables
me here d
o
S
g: elsew bere tom
n
i
rn
s
um ot
Wa gram er-n the b
w
dia w lo es at
sho ress
d
ad
Higher-numbered
addresses
Text (compiled
program code)
Initialized
global data
Uninitialized
global data
Heap
(dynamically
allocated)
Stack (procedure/
method calls)
Often
readonly
Th
i
how s diag
sta ram
I
n
t
c
s
Set on
e
som l x86 ks gro hows
code M e g s & o w o
n
r
u
load hav lti-threow oth thers;
er
e m ad
ulti ed p way
.
ple
r
sta ogram
cks
s
Calling a procedure
Given this C program:
void main() {
f(1,2,3);
}
Stack:
Overflowing buffer2
Lower-numbered
addresses
Higher-numbered
addresses
Stack:
One possible result after attack
Lower-numbered
addresses
Malicious code
Higher-numbered
addresses
Stack:
One possible result after attack
Lower-numbered
addresses
NOP sleds let attacker
jump anywhere to
attack; real ones often
more complex (to
evade detection)
Shellcode often has
odd constraints, e.g.,
no byte 0
Higher-numbered
addresses
val1
String
grows
val2
arguments
(funcp)
return address
Saved Frame Pointer
pointer var
(ptr)
buffer
(buf)
Stack
grows
slide 38
Attack code
args
(funcp)
return address
PFP
pointer var
(ptr)
buffer
(buf)
system()
slide 39
40
pointer
attack code
overflow
Legitimate function F
(elsewhere in memory)
slide 41
Syscall pointer
args
(funcp)
return address
l SFP
pointer var
(ptr)
buffer
(buf)
strcpy(buf, str);
*ptr = buf[0];
slide 42
Off-By-One Overflow
Home-brewed range-checking string copy
void notSoSafeCopy(char
*input)
{
char buffer[512]; int
i;
for (i=0; i<=512; i++)
buffer[i] = input[i];
}
void main(int argc, char *argv[]) {
if (argc==2)
notSoSafeCopy(argv[1]);
}
args
(funcp)
return address
SFP
pointer var
(ptr)
buffer
(buf)
slide 44
slide 45
Smashing elsewhere
Heap contains dynamically-allocated data
new (Java/C++), malloc (C), etc.
46
Integer Overflow
http://www.phrack.org/issues.html?issue=60&id=10
Since an integer is a fixed size (32 bits for the purposes of this
paper), there is a fixed maximum value it can store. When an attempt
is made to store a value greater than this maximum value it is known
as an integer overflow.
Most compilers seem to ignore the overflow, resulting in an
unexpected or erroneous result being stored.
This can get dangerous if the calculation has to do with the size of a
buffer or how far into an array to index.
What happens then!!
a = 0xffffffff
b = 0x1
r = a + b r = (0xffffffff + 0x1) % 0x100000000
r = (0x100000000) % 0x100000000 = 0
This is often called a "wrap around", as the result appears to wrap around to 0.
Example 2
#include <stdio.h>
#include <stdio.h>
int main(void){
unsigned int num =
0xffffffff;
printf("num + 1 = 0x
%x\n", num + 1);
int main(void){
int l;
l = 0x7fffffff;
return 0;
}
/* EOF */
The output of this program
looks like this:
num + 1 = 0x0
printf("l + 1 = %d (0x
%x)\n", l + 1 , l + 1);
return 0;
}
/* EOF */
The output of which is:
l = 2147483647 (0x7fffffff)
l + 1 = -2147483648
(0x80000000)
Range Checking!!
strcpy does not check input size
strcpy(buf, str) simply copies memory contents
into buf starting from *str until \0 is
encountered, ignoring the size of area allocated
to buf
slide 49
50
From
unsigne
d
To
Method
char
char
char
short
Zero-extend
char
long
Zero-extend
char
unsigned
short
Zero-extend
char
unsigned
long
Zero-extend
short
char
short
short
short
long
Zero-extend
short
unsigned
char
long
char
long
short
long
long
long
unsigned
char
Preserve
low-order
byte
Key:
Lost data
Misinterpreted data
From
To
Method
char
short
Sign-extend
char
long
Sign-extend
char
unsigned char
char
unsigned
short
char
unsigned long
short
char
short
long
Sign-extend
short
unsigned char
short
unsigned
short
short
unsigned long
long
char
long
short
long
unsigned char
long
unsigned
short
long
unsigned long
Misinterpreted data
Overflow Examples 1
1. int i;
2. unsigned int j;
3. i = INT_MAX; // 2,147,483,647
4. i++;
5. printf("i = %d\n", i);
i=-2,147,483,648
6. j = UINT_MAX; // 4,294,967,295;
7. j++;
8. printf("j = %u\n", j);
j = 0
Overflow Examples 2
9. i = INT_MIN; // -2,147,483,648;
10. i--;
11. printf("i = %d\n", i);
i=2,147,483,647
12. j = 0;
13. j--;
14. printf("j = %u\n", j);
j = 4,294,967,295
Implicit conversion to
smaller unsigned integer
}
large positive value of
0xffffffff
int _tmain(int argc, _TCHAR* argv[])
{
getComment(1, "Comment ");
return 0;
}
Possible to cause an overflow by creating
an image with a comment length field of 1
#define BUFF_SIZE 10
int main(int argc, char* argv[]){
int len;
len declared as a
char buf[BUFF_SIZE];
signed integer
len = atoi(argv[1]);
if (len < BUFF_SIZE){
argv[1] can be
memcpy(buf, argv[2], len);
a negative value
}
}
A negative value
bypasses the
check
Value is interpreted as an
unsigned value of type size_t
Virus
A program that searches out other programs
and infects them by embedding a copy of itself
in them
60
61
Delivery Method
How is worm code is delivered to vulnerable hosts
Self-contained Self-propagation: Each newly
infected host becomes the new source and sends
worm code to other hosts infected by it
Embedded: Embedded with infected files, such as
emails, shared files
Second Channel: The newly infected host uses
second channel such as TFTP (Trivial File Transfer
Protocol) to download the worm code from a center
source
62
Hitlist scanning
Probes addresses from an externally supplied list
Topological scanning
Uses information on the compromised host (Email worms)
63
Morris Worm
The Morris worm or Internet worm was one of the first
computer worms distributed via the Internet; it is
considered the first worm and was certainly the first to
gain significant mainstream media attention.
It also resulted in the first conviction under the 1986
Computer Fraud and Abuse Act. It was written by a
student at Cornell University, Robert Tappan Morris Jr.,
and launched on November 2, 1988 from MIT.
The worm was released from MIT to disguise the fact that
the worm originally came from Cornell.
Morris was convicted in 1990, received $10000 fine,
suspended jail sentence, and 400 hours of community
service
Effect
Morris worm was not written to cause damage,
but to gauge the size of the Internet, spread its
infection and remain undiscovered and
undiscoverable
Primary effect was resource exhaustion
Source code was supposed to check whether a
target was already infected so that the new
infector copy would terminate
An unintended consequence of the code (flaw),
however, caused it to be more damaging: a
computer could be infected multiple times and
each additional process would slow the machine
down, eventually to the point of being unusable /
Morris worm
Had three attack elements one of which was
buffer overflow
Worked by exploiting known vulnerabilities in
Unix sendmail, Finger, rsh/rexec and weak
passwords.
Main body of the worm could only infect DEC
VAX machines running BSD, and Sun systems.
Infected
sendmail
Exploit debug option in sendmail to allow shell
access
Normally runs in background awaiting signal to
send mail given by the users
rsh
Exploit trusted hosts
Password cracking
fingerd
Written in C and runs continuously
Array bounds attack
Fingerd expects an input string
Worm writes long string to internal 512-byte
buffer
Attack string
Includes machine instructions
Overwrites return address
Invokes a remote shell
Executes privileged commands
Huge and
complex
C program
Spread Infection
Spreading Infection
Shell script retrieves worm main program through a
bootstrap loader routine from the sending host
machine
Loader consisted of 99 lines of C code to be compiled and
executed on the target machine
places 40-line C program in temporary file called x$$,l1.c
where $$ is current process ID
Compiles and executes this program
Opens socket to machine that sent script
Retrieves worm main program, compiles it and runs
Target also sent a one-time password for continuation
Remote shell
Unix trust information
/etc/host.equiv system wide trusted hosts file
/.rhosts and ~/.rhosts users trusted hosts file
Password cracking
Worm was running as daemon (not root) so needed to
break into accounts to use .rhosts feature
Dictionary attack
Read /etc/passwd, used ~400 common password
machines
To avoid repeatedly typing passwords, a user specifies
a list of host/login name pairs that are assumed to be
trusted
Remote access from that host/login pair is never asked
for a password a great convenience
Often used for gaining unauthorized access to
machines
The worm tried finding machines that might trust current
machine/login being used by worm
Since trust is reciprocating, the worm would instantiate
on those machines by using remote execution (copying
itself)
Morris Infection
The vector program was installed and executed using one
of two methods
(i) Across the TCP connection to a shell:
A socket was established on the infecting machine for
the vector program to connect to (e.g., socket number
32341).
A challenge string was constructed from a random
number (e.g., 8712440).
A file name base was also constructed using a random
number (e.g., 14481910).
Morris Infection
(ii) Using the SMTP connection, it would transmit
Spread
~6000 victims i.e., 5-10% of hosts at that time
more machines disconnected from the net to avoid infection
Cost
Some estimate: $98 million
Other reports: <$1 million
Other Worms
WANK, Oct 1989, VAX/VMS/DECNet
Ramen, Jan 2001, wu-ftp daemon of RedHat Linux
6.2/7.0
Lion Worm, March 2001, BIND Transaction
Signature (Buffer Overflow)
On June 18, 2001, eEye released information about
a buffer-overflow vulnerability in IIS Web server
Microsoft released a patch on June 26
On July 12, 2001, worm began to exploit
Code Red
Initial version released July 13, 2001
Sends its code as an HTTP request
HTTP request exploits buffer overflow
Malicious code is not stored in a file
Placed in memory and then run
When executed,
Worm checks for the file C:\Notworm
If file exists, the worm thread goes into infinite sleep
state
Working of CodeRed
The buffer overflow resulted from a change in
representation of a string from ASCII to Unicode
The routine was DecodeURLEscapes() and
converts escape sequences in a web parameter
string into their interpretable values
E.g. enter is \0a, So, Decode changed it two 0x000a
(2 bytes per character)
The calling procedure called idq.dll passed the
length of string in ASCII and not in Unicode, but
string was in Unicode
String overwrites/overflows the stack
Overflow
overwrites
Exception handler
Heap
Working of CodeRed
Execution continues but a routine MSVCRT.DLL
signals an error eventually
The string overflowing the stack overwrote the
address in the stack of the exception handler
When error was signaled, control should transfer to
exception handler. Here, exception handlers
address was that of address written by attacker
As the address was that of the main worm code i.e.
code to begin running the exploit
Further, larger part of the malicious code was
already stored in the heap area which was 300bytes
from start of the exploit code in the attack
Overflow
overwrites
Exception handler
Heap
CodeRed Infection
Worm first checks if the date is between 1 and 19
If so, it generates a random list of IP addresses,
spawns 99 threads, probes each machine for
vulnerability (however, used static seed and thus
generated identical list of IP addresses)
Included its own copy of Windows File Explorer
program
On 20th of every month the worm is programmed to
stop infecting other machines and proceed to its
next attack phase in which it launches a DoS attack
against www1.whitehouse.gov
The worm is dormant on days of the month
following the 28th
CodeRed
Had little impact on local resources
V1 was memory resident, so an infected machine
can be disinfected by simply rebooting it
The worm cashed on Windows NT servers
Executed on Windows 2000 systems
Later versions created trapdoor by copying
cmd.exe to four locations
First ran the original explorer.exe and later
changed registry entries to disable certain file
permissions
Reseted registry every 10 minutes
Later versions attacked neigbouring IP address
To propagate worm created 300 or 600 threads