0% found this document useful (0 votes)
120 views95 pages

Software Vulnerabiliites

Software vulnerabilities can occur when flaws, faults or failures exist in a program. A flaw is a problem in a program, while a fault is a mistake in the code, data or process. A failure occurs when something goes wrong during execution. Buffer overflows are a common type of security flaw that occur when more data is written to a fixed-length buffer than it can hold, overwriting adjacent memory and potentially allowing execution of malicious code. Stack buffer overflows specifically overwrite return addresses on the stack and can be exploited to execute attacker-controlled code and compromise systems. Many internet worms like the Morris worm and Code Red exploited buffer overflow vulnerabilities to spread. While patching flaws is important, it can sometimes introduce new issues and vulnerabilities if not

Uploaded by

Bhoomi
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
120 views95 pages

Software Vulnerabiliites

Software vulnerabilities can occur when flaws, faults or failures exist in a program. A flaw is a problem in a program, while a fault is a mistake in the code, data or process. A failure occurs when something goes wrong during execution. Buffer overflows are a common type of security flaw that occur when more data is written to a fixed-length buffer than it can hold, overwriting adjacent memory and potentially allowing execution of malicious code. Stack buffer overflows specifically overwrite return addresses on the stack and can be exploited to execute attacker-controlled code and compromise systems. Many internet worms like the Morris worm and Code Red exploited buffer overflow vulnerabilities to spread. While patching flaws is important, it can sometimes introduce new issues and vulnerabilities if not

Uploaded by

Bhoomi
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 95

Software Vulnerabilities

Basically based on material by


Pfleeger & Pfleeger

Flaws, faults, and failures


A flaw is a problem with a program
A security flaw is a problem that affects
security in some way
Confidentiality, integrity, availability

Flaws come in two types: faults and


failures
A fault is a mistake behind the scenes
An error in the code, data, specification,
process, etc.
A fault is a potential problem

Flaws, faults, and failures


A failure is when something actually goes
wrong
Goes wrong means deviation from desired
behaviour,
not necessarily from specified behaviour!

A failure is the user/outside view


The quantity and types of faults in
requirements
design
and
code
implementation are often used as evidence
of a products quality or security

Finding and fixing faults


Once you find some faults, fix them
Usually by making small edits (called patches)
to the program
This is called penetrate and patch

Patching sometimes makes things worse!


Pressure to patch a fault is often high
Fault may have caused other failures and a
partial fix may cause inconsistencies or other
problems
The patch for this fault may introduce new
faults, here or elsewhere!

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

But from a security / privacy point of view,


extra behaviours could be bad!
When implementing a security or privacy
relevant program, consider and nothing else to
be implicitly added to the spec

Types of security flaws: Genesis


Some flaws are intentional
Malicious flaws are intentionally inserted to
attack
If it's meant to attack some particular system, we call it
a targeted malicious flaw

Nonmalicious (but intentional) flaws are often


features that are meant to be in the system
are correctly implemented,
but can cause a failure when used by an attacker

Most security flaws are


unintentional program errors

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

work in computer security was based on the paradigm of


"penetrate and patch,"
analysts searched for and repaired faults
test a system's security by attempting to cause it to fail
The test was considered to be a "proof" of security
if the system withstood the attacks, it was considered secure
Unfortunately, the proof became a counterexample
The problem discovery in turn led to a rapid effort to "patch" the
system to repair or restore the security
However, the patch efforts were largely useless, making the
system less secure rather than more secure because they
frequently introduced new faults

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

Boundary condition violation: failure on first or last case


occur due to omission of checks to assure that constraints (table
size, file allocation, or other resource consumption) are not
exceeded

Inadequate identification and authentication: basis for


authorization
permits operations to be invoked without sufficiently checking the
identity and the authority of the invoking entity

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]);

Buffer overflows problem?


The gets and strcpy functions don't check
that the string they're copying into the
buffer will fit in the buffer!
Some languages would give an exception
here, and crash the program.
Is this an OK solution

C doesn't even notice something bad


happened

So, whats a buffer overflow?


Buffer overflow is an event that occurs when :
Fixed-length data buffer (e.g., string)
At least one value intended for buffer is written outside that buffer's
boundaries (usually past its end)
Some definitions also include reading outside buffer
Can occur when reading input or later processing data
Buffer overflows = buffer overruns. Subtypes include:
Stack overrun. Buffer in stack; attack is called stack smashing
Heap overrun. Buffer in heap; attack is called heap smashing
Noted in Computer Security Technology Planning Study (1972)
Common problem
If exploitable
Attacker can often completely control program

Attacker can typically cause denial-of-service


Many defenses simply downgrade from control program
to DoS

Buffer overflow incidents


(just a sample!)
1988: Morris worm took down Internet
Includes buffer overflow via gets() in fingerd

1998: University of Washington IMAP (mail)


server
1999: RSA crypto reference implementation
Subverted PGP, OpenSSH, Apaches ModSSL,
etc.

2001: Code Red worm buffer overflow in


Microsofts Internet Information Services (IIS)
5.0
2003: SQL Slammer worm compromised

Programming languages &


buffer overflow
Some languages allow buffer overflow
C, C++, Objective-C, Vala, Forth, assembly
language
First three are especially common

Most languages counter buffer overflow


Ada strings, Pascal: Detect/prevent overflow
Java, Python, perl, Ada unbounded_string:
Auto-resize

Using other languages doesnt give


immunity
Most language implementations are in C/C++

Nonmalicious Program Errors


Buffer Overflows Security Implication
Attacker replaces code in the system space and
takes control back from the operating system
Attacker uses the stack pointer or return register
to execute other code
How to write buffer overflows
Smashing the Stack for Fun and Profit

Famous Internet Worms


Morris worm (1988): overflow in fingerd
6,000 machines infected (10% of existing Internet)

CodeRed (2001): overflow in MS-IIS server


300,000 machines infected in 14 hours

SQL Slammer (2003): overflow in MS-SQL server


75,000 machines infected in 10 minutes (!!)

Sasser (2004): overflow in Windows LSASS


Around 500,000 machines infected
Responsible for user
authentication in Windows

And The Band Marches On


Conficker (2008-09): overflow in Windows RPC
Around 10 million machines infected (estimates vary)

Stuxnet (2009-10): several zero-day overflows +


same Windows RPC overflow as Conficker
Windows print spooler service
Windows LNK shortcut display
Windows task scheduler

Flame (2010-12): same print spooler and LNK


overflows as Stuxnet
Targeted cyberespionage virus

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

Attack can exploit any memory operation and


need not involve code injection or data
execution
Pointer assignment, format strings, memory
allocation and de-allocation, function pointers,
calls to library routines via offset tables
slide 19

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'

Buffer Overflows (Example


Cont.)
There are four cases to
consider in deciding where
the 'B' goes

Buffer Overflows (Example


Cont.)
If the extra character overflows into the user's data space
it simply overwrites an existing variable value
perhaps affecting the program's result
but affecting no other program or data

In the second case, the 'B' goes into the user's program area
If it overlays an already executed instruction
no effect

If it overlays an instruction that is not yet executed


the machine will try to execute an instruction with operation code 0x42
the internal code for the character 'B

Spilling over into system data or code areas produces similar


results to those for the user's space: computing with a faulty
value or trying to execute an improper operation.

Process Address Space

Call Stack / Activation Record

Stack Buffers
Suppose a Web server contains function
void func(char *str) {
char buf[126];
strcpy(buf,str);
}

Allocate local buffer


(126 bytes reserved on stack)
Copy argument into local buffer

When this function is invoked, a new frame


(activation record) is pushed onto the stack
Stack grows this way

buf

sfp
Local variables

ret
addr str

Frame of the
calling function

Pointer to Execute code Arguments


previous at this address
frame
after func() finishes

Top of
stack

What If Buffer Is Overstuffed?


Memory pointed to by str is copied onto stack
void func(char *str) {
char buf[126];
strcpy does NOT check whether the string
strcpy(buf,str);
at *str contains fewer than 126 characters
}
If a string longer than 126 bytes is copied into buffer, it will overwrite
adjacent stack locations

buf

overflow

str

Frame of the
calling function

This will be interpreted


as return address!

Top of
stack

Executing Attack Code


Suppose buffer contains attacker-created
string
For example, str points to a string received from
the network as the URL
code
Attacker puts actual assembly
instructions into his input string, e.g.,
binary code of execve(/bin/sh)

ret

str

Frame of the
calling function

In the overflow, a pointer back into the buffer


appears in the location where the program
expects to find return address

When function exits, code in the buffer will be


executed, giving attacker a shell
Root shell if the victim program is setuid root

Top of
stack

Notional process memory map


Lower-numbered
addresses

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

Heap grows, e.g.,


due to new or malloc()
Heap pointer
Stack pointer (SP)
(current top of stack)
Stack grows, e.g.,
due to procedure call

Stack in a process memory


map
Memory area set aside to implement calls to a
function/method
Stack is used to implement control flow
When you call a procedure, where it came from is
pushed on stack
When a procedure returns, the where I came from
is popped from stack; system starts running code
there
Stack also used for other data (in many cases)
Parameters passed to procedures
Procedure local variables
Return values from procedure

Why use stacks for procedure calls?


First compiled languages (e.g., FORTRAN)
did not use stacks
Stored, with procedure, where program came
from
Result: Procedures could not call themselves,
directly or indirectly, as that would overwrite
stored info
Extremely limiting, easy to get wrong

If procedures can arbitrarily call other


procedures
Need to store old state so can return back

Calling a procedure
Given this C program:
void main() {
f(1,2,3);
}

The invocation of f() might generate


assembly:
pushl $3 ; constant 3
pushl $2 ; Most C compilers push in reverse
order by default
pushl $1
call f

Stack:
Overflowing buffer2
Lower-numbered
addresses

Stack pointer (SP)


(current top of stack)

Local array buffer2


Overwrite

Local array buffer1


Saved (old) frame
pointer
Return address in
main()
1
2

Higher-numbered
addresses

Frame pointer (FP)


use this to access
local variables &
parameters

Stack grows, e.g.,


due to procedure call

What happens if we write past


the end of buffer2?
Overwrites whatever is past buffer2!
As you go further, overwrite higher addresses

Impact depends on system details


In our example, can overwrite:
Local values (buffer1)
Saved frame pointer
Return value (changing what we return to)
Parameters to function
Previous frames

Common buffer overflow attack


Send data that is too large, or will create
overlarge data
Overlarge data overwrites buffer
Modifies return value, to point to something the
attacker wants us to run
Maybe with different parameters, too

On return, runs attacker-selected code


But it gets worse

Inserting code in the buffer


overflow attack (e.g., shell code)
Attacker can also include machine code
that they want us to run
If they can set the return value to point to
this malicious code, on return the victim will
run that code
Unless something else is done

Significant portion of Smashing the Stack


paper describes how to insert such code

Stack:
One possible result after attack
Lower-numbered
addresses

Malicious code

Stack pointer (SP)


(current top of stack)

Local array buffer2

Higher-numbered
addresses

Local array buffer1


Saved (old) frame
pointer
Return address in
Ptr to malicious code
main()
1
2
3

Frame pointer (FP)


use this to access
local variables &
parameters

Stack grows, e.g.,


due to procedure call

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

Stack pointer (SP)


(current top of stack)
NOP sled: \x90\x90\x90\x90\x90.
Local
array buffer2
Shellcode:
\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\
x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x
08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x
40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh

Local array buffer1


Saved (old) frame
pointer
Return address in
Ptr to malicious code
main()
1
2
3

Frame pointer (FP)


use this to access
local variables &
parameters

Stack grows, e.g.,


37
due to procedure call

Stack Corruption: General View


int bar (int val1) {
int val2;
foo
(a_function_pointer);
Attacker}
controlled
memory
int foo (void (*funcp)()) {
char* ptr = point_to_an_array;
char buf[128];
gets (buf);
strncpy(ptr, buf, 8);Most popular
(*funcp)();
target
}

val1

String
grows

val2

arguments

(funcp)

return address
Saved Frame Pointer
pointer var

(ptr)

buffer

(buf)

Stack
grows
slide 38

Attack #1: Return Address


set stack pointers to
return to a dangerous
library function
/bin/sh

Attack code

Change the return address to point


to the attack code. After the function
returns, control is transferred to the
attack code.
or return-to-libc: use existing
instructions in the code segment
such as system(), exec(), etc. as
the attack code.

args
(funcp)
return address
PFP
pointer var
(ptr)
buffer
(buf)

system()

slide 39

Other types of attacks possible


with a stack buffer overflow
Make return point to existing code that the
attacker wants us to run now
E.G., invoke a shell, debug code
Perhaps modify parameters
Change value of adjacent local variables
Change value of parameters
... and so on

40

Function Pointer Overflow


C uses function pointers for callbacks: if
pointer to F is stored in memory location P,
then another function G can call F as (*P)
()
Buffer with attacker-supplied Callback
input string

pointer

attack code

overflow

Legitimate function F
(elsewhere in memory)
slide 41

Attack #2: Pointer Variables


Attack code

Global Offset Table

Syscall pointer

Change a function pointer to point to


attack code
Any memory, on or off the stack, can be
modified by a statement that stores a
value into the compromised 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]);
}

This will copy 513


characters into the
buffer. Oops!

1-byte overflow: cant change RET, but can


change saved pointer to previous stack frame
On little-endian architecture, make it point into buffer
Callers RET will be read from buffer!
slide 43

Attack #3: Frame Pointer


Fake return
address
Fake SFP
Attack code
Arranged like a
real frame

Change the callers saved frame


pointer to point to attacker-controlled
memory. Callers return address will be
read from this memory.

args
(funcp)
return address
SFP
pointer var
(ptr)
buffer
(buf)

slide 44

Buffer Overflow: Causes and


Cures
Classic memory exploit involves code
injection
Put malicious code at a predictable location in
memory, usually masquerading as data
Trick vulnerable program into passing control to
it
Overwrite saved EIP, function callback pointer, etc.

Idea: prevent execution of untrusted code


Make stack and other data areas nonexecutable
Digitally sign all code
Ensure that all control transfers are into a

slide 45

Smashing elsewhere
Heap contains dynamically-allocated data
new (Java/C++), malloc (C), etc.

Data contains global data


Including key infrastructure control values

If attacker can overwrite beyond buffer, can


control other values (e.g., stored
afterwards)
Values of other structures
Heap: Heap maintenance data (e.g., whats
free/used)
Even 1 character overwrite can be devastating

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.

Integer Overflow Examples


Example 1

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

Many C library functions are unsafe


strcpy(char *dest, const char *src)
strcat(char *dest, const char *src)
gets(char *s)
scanf(const char *format, )
printf(const char *format, )

slide 49

Two code solution alternatives:


Bounds-checking & auto-resize
Bounds-checking to stop overwrite; then if
oversized:
Stop processing input
Reject and try again, or even halt program (turns into
DoS)

Truncate data. Common approach, but has


issues:
Terminates text in the middle at place of attackers
choosing
Can strip off critical data, escapes, etc. at the end
Can break in the middle of multi-byte character
UTF-8 character can take many bytes
UTF-16 usually 2 bytes/character, but not if its outside BMP

50

From
unsigne
d

To

Method

char

char

Preserve bit pattern; high-order bit becomes sign


bit

char

short

Zero-extend

char

long

Zero-extend

char

unsigned
short

Zero-extend

char

unsigned
long

Zero-extend

short

char

Preserve low-order byte

short

short

Preserve bit pattern; high-order bit becomes sign


bit

short

long

Zero-extend

short

unsigned
char

Preserve low-order byte

long

char

Preserve low-order byte

long

short

Preserve low-order word

long

long

Preserve bit pattern; high-order bit becomes sign


bit

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

Preserve pattern; high-order bit loses function as


sign bit

char

unsigned
short

Sign-extend to short; convert short to unsigned


short

char

unsigned long

Sign-extend to long; convert long to unsigned long

short

char

Preserve low-order byte

short

long

Sign-extend

short

unsigned char

Preserve low-order byte

short

unsigned
short

Preserve bit pattern; high-order bit loses function


as sign bit

short

unsigned long

Sign-extend to long; convert long to unsigned long

long

char

Preserve low-order byte

long

short

Preserve low-order word

long

unsigned char

Preserve low-order byte

long

unsigned
short

Preserve low-order word

long

unsigned long

Preserve pattern; high-order bit loses function as


sign bit

Key: Lost data

Misinterpreted data

Signed Integer Conversion


Example
1.
2.
3.
4.
5.

unsigned int l = ULONG_MAX;


The value of c is
char c = -1;
compared to the
if (c == l) {
value of l.
printf("-1 = 4,294,967,295?\n");
}
Because of integer promotions, c is
converted to an unsigned integer with a
value of 0xFFFFFFFF or 4,294,967,295

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

Truncation Error Example


1.
2.
3.
4.

char cresult, c1, c2, c3;


c1 = 100;
Adding c1 and c2 exceeds the max
size of signed char (+127)
c2 = 90;
cresult = c1 + c2;

Truncation occurs when the value is


assigned to a type that is too small to
represent the resulting value
Integers smaller than int are unlikely
to overflow because the actual
operations are performed on the
promoted values.

Integers smaller than int are


promoted to int or
unsigned int before being
operated on

Sign Error Example


1.int i = -3;
2.unsigned short u;
3.u = i;
4.printf("u = %hu\n", u);

Implicit conversion to
smaller unsigned integer

There are sufficient bits to represent the value so


no truncation occurs. The twos complement
representation is interpreted as a large signed
value, however, so u = 65533

Integer Overflow Example


void getComment(unsigned int len, char *src) {
unsigned int size;
0 byte malloc() succeeds
size = len - 2;
char *comment = (char *)malloc(size + 1);
memcpy(comment, src, size);
return;
Size is interpreted as a

}
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

Sign Error Example 1


Program accepts two
arguments (the length
of data to copy and
the actual data)

#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

Worm vs. Virus


Worm
A program that propagates itself over a network,
reproducing itself as it goes

Virus
A program that searches out other programs
and infects them by embedding a copy of itself
in them

Active Worm and Its Defense

60

Basic Propagation Method


Network Worm: Using port scan to find
vulnerabilities of the targets
Application Worm: Propagate through email,
Instance Messaging, file sharing on operation
systems, P2P file sharing systems, or other
applications
Hybrid Worm

Active Worm and Its Defense

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

Active Worm and Its Defense

62

Scanning Strategy (1)


Random scanning
Probes random addresses in the IP address space (CRv2)

Selective random scanning


A set of addresses that more likely belong to existing machines can
be selected as the target address space.

Hitlist scanning
Probes addresses from an externally supplied list

Topological scanning
Uses information on the compromised host (Email worms)

Local subnet scanning


Preferentially scans targets that reside on the same subnet. (Code
Red II & Nimbda Worm)
Active Worm and Its Defense

63

Scanning Strategy (2)


Routable scanning

Choose routable IP addresses as the


target of scan
DNS scanning
Choose hosts with DNS name as the target of
scan
Permutation scanning
Each new infected host gets a different IP
addresses block

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.

How an Active Worm Spreads


Autonomous
No need of human interaction
scan
probe
transfer copy
infected
machine

Infected

How Morris Worm Worked?


Determine where to spread:
1.Tried to find user accounts to invade on target machine. In
parallel, tried bug in fingerd, then use trapdoor in
sendmaild mail handler. Read ciphertext encoded user
password file, when got a match could log in, became a
user, started looking for other machines to get access.
Coincidently, Robert T Morris, Sr. along with Ken Thomson
wrote password handling program of Unix
2. Second flaw was in fingerd where input buffer could
overflow spilling into the return address stack. So, after a
fingerd call terminated, it executed other instructions found at
the new return address that caused worm to connect to a
remote shell

Three ways the worm spread


fingerd
Exploit a buffer overflow in the fgets function
Apparently, this was the most successful attack

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

Exploit used in fingerd


finger is a utility that allows users to obtain
information about other users full name and other
details
Runs as a background process or daemon
Daemon accepts requests from remote programs,
reads a single line input and sends back matching
output
Bug exploited to break fingerd involved overrunning
the buffer the daemon used for input
gets call takes input to a buffer without doing any
bounds checking
The input overran buffer allocated for it and rewrote
the stack frame

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

Third flaw exploited

Huge and
complex
C program

3. In the debugging mode, the worm caused sendmail to


receive and execute a command instead of connecting the
destination address
Opens TCP connection to machine's SMTP port
Invokes debug mode
Sends a RCPT TO that pipes data through shell
Worm would issue DEBUG command to sendmail and
then specify recipient of the message as a set of
commands instead of a user address
This feature can be used by testers to run programs to
display the state of the mail system without sending mail
or establishing a separate login connection
After this

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

Worm exploited trust information


Examining files that listed trusted machines
Assume reciprocal trust
If X trusts Y, then maybe Y trusts X

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

Exploit involving use of trusted


logins
BSD Unix feature of executing tasks on remote

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 Worm Working


The worm consisted of two parts: a main program
and a bootstrap or vector program.
Main program, once established on a machine,
would collect information on other machines in the
network to which current machine could connect
(read data, run system utility programs and run sh)
Establish bootstrap on each of those remote
machine on each of those machines
99 lines of C code would be compiled and run
Source would further be transferred to a victim
machine (address/port/magic number)

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

Morris Worm Working


If the server worm on remote host and port did not
receive the same magic number it would
immediately disconnect
If a failure occurred during transfer the worm would
exit after deleting all files (Remember exec/fork system
calls)
Transfer binary files to local machine and also a
copy of itself for use in infecting other systems
Load and link these files with local versions of
library
Once run, it deleted copies from the disk
If none of the files ran, it would delete everything

Remain Undiscovered and Undiscoverable


Program is called 'sh'
Clobbers argv array so a 'ps' will not show its name
Periodically changed its name and pid, so ps will be unable to show anything

Opens its files, then unlinks (deletes) them so can't be found


Since files are open, worm can still access their contents

Tries to infect as many other hosts as possible


When worm successfully connects, forks a child to continue the
infection while the parent keeps trying new hosts
During transmission error, loader deleted all code already transferred and exited
Once full code was received, it brought code to memory, encrypted it and deleted
copies from the disk. No traces!! No memory dump could expose it!!

Worm did not:


Delete system's files, modify existing files, install trojan horses, record
or transmit decrypted passwords, capture superuser privileges,
propagate over UUCP, X.25, DECNET, or BITNET

The Morris Worm of 1988


First worm program (Also called Internet Worm)
Released by Robert T Morris of Cornell University
Affected DECs VAX and Sun Microsystemss Sun 3 systems

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

Triggered the creation of CERT (Computer Emergency


Response Team) at CMU

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

Creates new threads


If the date is before the 20th of the month, the next 99
threads attempt to exploit more computers by targeting

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

Code Exploitation of Buffer


Overflow
Stack

Overflow
overwrites

Exception handler

Main Worm Code

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

Code Exploitation of Buffer


Overflow
Stack

Overflow
overwrites

Exception handler

Main Worm Code

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

Code Red of July 13 and July 19


Initial release of July 13
1st through 20th month: Spread
via random scan of 32-bit IP addr space
20th through end of each month: attack.
Flooding attack against 198.137.240.91
(www.whitehouse.gov)
Failure to seed random number generator linear growth

Revision released July 19, 2001.

White House responds to threat of flooding attack by changing


the address of www.whitehouse.gov
Causes Code Red to die for date 20th of the month.
But: this time random number generator correctly seeded
i.e. randomized
Slides: Vern Paxson

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

Slide: Vern Paxson

Measuring activity: network telescope

Monitor cross-section of Internet address space, measure traffic


Backscatter from DOS floods
Attackers probing blindly
Random scanning from worms
LBNLs cross-section: 1/32,768 of Internet
UCSD, UWiscs cross-section: 1/256.

Spread of Code Red


Network telescopes estimate of # infected hosts: 360K.
(Beware DHCP & NAT)
Course of infection fits classic logistic.
Note: larger the vulnerable population, faster the worm
spreads.
That night ( 20th), worm dies
except for hosts with inaccurate clocks!
It just takes one of these to restart the worm on August 1 st

Slides: Vern Paxson

Slides: Vern Paxson

You might also like