Rene Holt
What are
buffer overflow attacks and how are they thwarted?
Ever since
the Morris worm, buffer overflows have become notorious fare in the world of
vulnerabilities
Rene Holt
The Morris
worm of 1988
was one of those industry-shaking experiences that revealed how quickly a worm
could spread using a vulnerability known as a buffer overflow or buffer
overrun. Around 6,000 of the 60,000 computers connected to ARPANET, a precursor
to the Internet, were infected with the Morris worm. Although a few positives
came from this attack, especially in pushing software vendors to take
vulnerabilities seriously and in the creation of the first Computer Emergency
Response Team (CERT), this attack was far from the last to capitalize on a
buffer overflow.
In 2001,
the Code
Red worm
infested more than 359,000 computers running Microsoft’s IIS software. Code Red
defaced webpages and attempted to launch denial-of-service attacks, including
one on a White House web server.
Then, in
2003, the SQL
Slammer worm
attacked more than 250,000 systems running Microsoft’s SQL Server software. SQL
Slammer crashed routers, significantly slowing down or even stopping network
traffic on the internet. Both the Code Red and SQL Slammer worms spread via
buffer overflow vulnerabilities.
More than
thirty years on from the Morris worm, we are still plagued by buffer overflow
vulnerabilities with all their negative consequences. Although some blame various
programming languages, or features of them, as having an unsafe design, the culprit seems to
be more the fallible use of these languages. To understand how buffer overflows
happen, we need to know a little about memory, especially the stack, and about
how software developers need to manage memory carefully when writing code.
What is a buffer and how does a buffer overflow occur?
A buffer is a
block of memory assigned to a software program by the operating system. It is a
program’s responsibility to request, from the operating system, the amount of
memory that it needs to run correctly. In some programming languages like Java,
C#, Python, Go, and Rust, memory management is handled automatically. In other
languages like C and C++, programmers have the burden of manually managing the
allocation and freeing of memory and ensuring that memory bounds are not
crossed by checking buffer lengths.
However,
whether by programmers who use code libraries incorrectly or by those who are
writing them, mistakes can be made. These are the cause of many software
vulnerabilities ripe for discovery and exploit. A correctly designed program
should specify the maximum size of memory to hold data and guarantee that this
size is not exceeded. A buffer overflow happens when a program writes data
beyond the memory assigned to it and into a contiguously located memory block
intended for some other use or owned by some other process.
As there are
two main types of buffer overflows — heap-based and stack-based — a prefatory
word is in order concerning the difference between the heap and the stack.
The stack vs. the heap
Before a
program executes, the loader assigns it a virtual address space that includes
addresses for both the heap and the stack. The heap is a block of memory that
is used for global variables and variables assigned memory at runtime
(dynamically allocated).
Much like a
stack of plates at a buffet, a software stack is built out of frames that hold
a called function’s local variables. Frames are pushed (put onto) the stack
when functions are called and popped off (removed from) the stack when they
return. If there are multiple threads, then there are multiple stacks.
A stack is
very fast compared to a heap, but there are two downsides of using the stack.
First, stack memory is limited, meaning that placing large data structures on
the stack more quickly exhausts the available addresses. Second, each frame has
a lifetime that is limited to its existence on the stack, meaning that it is
not valid to access data from a frame that has been popped off the stack. If
multiple functions require access to the same data, it is better to place the
data on the heap and pass a pointer to that data (its address) to those
functions.
Buffer
overflows can happen in both the heap and the stack, yet we will focus here on
the more common variety: stack-based buffer overflows.
Full
article on: https://www.welivesecurity.com/2021/12/06/what-are-buffer-overflow-attacks-how-are-they-thwarted/?utm_source=feedburner&utm_medium=email