0% found this document useful (0 votes)
6 views

Buffer Overloading

Uploaded by

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

Buffer Overloading

Uploaded by

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

Buffer Overflow:

One of the most common and oldest security vulnerabilities in software are buffer overflow
vulnerabilities. Buffer overflow vulnerabilities occur in all kinds of software from operating
systems to client/server applications and desktop software. This often happens due to bad
programming and the lack of or poor input validation on the application side. In this article we
will look at what a buffer overflow exactly is, how they work and how they can become serious
security vulnerabilities. We will also look at what happens when a buffer overrun occurs and
mitigation techniques to minimize their harmful effects.

What is a buffer overflow?

A buffer overflow is a situation where a running program attempts to write data outside the
memory buffer which is not intended to store this data. When this happens we are talking about a
buffer overflow or buffer overrun situation. A memory buffer is an area in the computer’s
memory (RAM) meant for temporarily storing data. This kind of buffers can be found in all
programs and are used to store data for input, output and processing.

An example of data stored in buffers are login credentials or the hostname for an FTP server.
Also other data temporarily stored before processing can be stored in buffers. This literally could
be anything from user input fields such as username and password fields to input files used to
import certain configuration files. When the amount of data written to the buffer exceeds the
expected amount of data, the memory buffer is overrun. This happens for example when a
username with a maximum of 8 bytes is expected and a username of 10 bytes is given and
written to the buffer. In this case the buffer is exceeded by 2 bytes and an overflow will occur
when it’s not prevented from happening. This often happens due to bad programming and the
lack of input sanitization.

An example of a buffer overflow when writing 10 bytes of data (username12) to an 8 byte buffer.

What happens when a buffer overflow occurs?


When a memory buffer overflow occurs and data is written outside the buffer, the running
program may become unstable, crash or return corrupt information. The overwritten parts of
memory may have contained other important data for the running application which is now
overwritten and not available to the program anymore. Buffer overflows can even run other
(malicious) programs or commands and result in arbitrary code execution.

Arbitrary code execution and privilege escalation

When a buffer overflow vulnerability is used to write malicious data in the memory and the
attacker is able to take control of the execution flow of a program, we are dealing with a serious
security vulnerability. Buffer overflows can then become serious security issues. These
security issues can be exploited by hackers to take (remote) control of a host, perform privilege
escalation or a lot more bad things as a result of arbitrary code execution. Arbitrary code
execution is the process of injecting code in the buffer and get it to execute.

Privilege escalation is performed through exploiting a buffer overflow vulnerability to execute


arbitrary code in a program that is running with system privileges. The executed code can be
shellcode which gives the attacker an OS shell with administrative privileges for example, or
even add a new (administrator) user to the system. Also with buffer overflows the executed code
happens in the context of the running application. This means that when the exploited application
runs under with administrative privileges, the malicious code will also be executed with
administrative privileges.

Denial of Service (DoS)

Not all buffer overflow vulnerabilities can be exploited to gain arbitrary code execution. Also
(remote) Denial of Service attacks can be performed when they only crash the running program.
As buffer overflows vulnerabilities can occur in any software DoS attacks are not just limited to
services and computers. Also routers, firewalls IoT devices and anything else running an OS can
be targeted. An example of this situation is the recent Cisco ASA IKEv1 and IKEv2 Buffer
Overflow exploits lately. Some of these remote exploits only crash and force reboot the
firewall resulting in a couple minutes downtime.

How to prevent buffer overflows from occurring?

Buffer overflows in software can be prevented or mitigated in several ways. Mitigation is the
process of minimizing the impact of a threat before or after the threat occurs. This is exactly
what we need to do when it comes to buffer overflows. They can be prevented from happening
before they occur (proactive). But, since buffer overflows keep occurring, despite the proactively
taken actions to avoid them, we also need mechanisms in place to minimize impact when they do
occur (reactive countermeasures). Let’s have a look at how buffer overflow prevention and
mitigation works.
Buffer overflow prevention

The best and most effective solution is to prevent buffer overflow conditions from happening in
the code. For example when a maximum of 8 bytes as input data is expected, than the amount of
data which can be written to the buffer to be limited to 8 bytes at any time. Also, programmers
should be using save functions, test code and fix bugs accordingly. Proactive methods for buffer
overflow prevention like these should be used whenever possible to limit buffer overflow
vulnerabilities.

Buffer overflow mitigation

Another way of safeguarding to buffer overflows is to detect them as they happen and mitigate
the situation. This is an reactive approach and focuses on minimizing the harmful impact. An
example of effective mitigation is a modern operating system which protects certain memory
areas from being written to or executed from. This will prevent an attacker from writing arbitrary
code to the memory when a buffer overflow occurred. Implementations like DEP, ASLR,
SEHOP and executable space and pointer protection try to minimize the negative impact of a
buffer overflow. This does not prevent the buffer overflow from occurring, but it does minimize
the impact.

Another way of passive buffer overflow detection is using intrusion detection systems (IDS) to
analyse network traffic. An IDS is capable of detecting signatures in network traffic which
are known to exploit buffer overflow vulnerabilities. The IDS can than mitigate the attack
and prevent the payload from executing on the targeted system.

How does a buffer overflow work and look like in code?

Let’s have a look at how a buffer overflow actually works by looking at the program code. We
explain this process using a very known function vulnerable to buffer overflow is the strcopy()
function in the c library. This functions uses 2 pointers as parameters, the source which points to
the source array to copy from and the destination pointer to the character array to write to. When
the function is executed the source array of chars will be copied to the destination array and does
not have a check for bounds when it does so. When the source buffer is larger than the
destination buffer, than the buffer is overrun.

Buffer overflow with strcpy()

The follow image is an example of the strcpy() function using a source which is overrunning the
destination buffer.
The code would look like the following image in you IDE of choice:

In this example the buffer is overrun with 2 bytes containing a harmless 1 and 2. Since the
strcpy() function does not perform a bounds check we could write anything outside the buffer
space. Also malicious code like shellcode. In the following tutorials about buffer overflows we
will learn about overrunning buffers with shellcode instead of 1’s and 2’s. We will also learn
how to control the execution flow of a program and execute the malicious shellcode outside the
buffer.

Lessons learned
We have learned that a buffer overflow is caused by certain conditions where a running program
is writing data outside the memory buffer. By injecting (shell)code and redirecting the execution
flow of a running program to that code, an attacker is able to execute that code. This is called
arbitrary code execution. With arbitrary code execution an attacker is able to gain (remote)
control of a specific target, elevate privileges or cause a denial of service on the target.

Buffer overflows can be proactively prevented and mitigated with several techniques.
Programmers should write secure code and test it for buffer overflows. When a buffer overflow
is not prevented from happening it can still be mitigated with reactive methods like protecting
memory from being written to.

We have tried to explain buffer overflow basics without to many technical details. In the
following tutorials about this subject we will get into more details regarding stack based
buffer overflows, heap based buffer overflows and how to detect and exploit buffer overflows
vulnerabilities in software. We will also be learning about shellcode and writing our own basic
buffer overflow exploits.

Defining, Understanding and Preventing Buffer Overflow Attacks

Buffer Overflows have been a critical and powerful attack


vector used for decades by cybercriminals to exploit applications. Though not as common as
attack methods such as XSS (cross site scripting) or SQL Injection, buffer overflow attacks can
allow custom code execution in a system, typically after crashing system services. This is done
by filling a buffer with data until there is no memory space left, causing code to “overflow” into
adjacent memory locations. Web applications accepting input from a user can allow malicious
cybercriminals to send more data into the server’s allocated buffers. This is possible because
applications set up fixed size data buffers, which provide spaces of memory (in RAM) designed
to act as temporary storage containers for data. Buffers are typically used when an application
needs to store data temporarily (in buffers) as the data is moved through the application. Buffers
can also be used when input/output hardware devices receive or send data. Buffers are physical
addresses in memory where data is to be stored or a reference pointing to an address in memory.
A very simple buffer overflow example is the use of a char buffer array in C, which may allocate
more data to the buffer then it was designed to hold.
Despite being regarded as a somewhat archaic attack vector, buffer overflow attacks are used to
exploit modern systems even today, while certain systems continue to remain vulnerable to the
attacks. According to the latest hacking news, security firm Senrio recently discovered that many
Internet of Things (IoT) devices are vulnerable to buffer overflows (Eslam Medhat, 2017). Other
known application and operating system buffer overflow vulnerabilities include security bugs in
the Windows OS, iOS, Android OS and Adobe Reader software applications.
Well Known Buffer Overflow Attacks
Throughout the years, there have been many minor and major buffer overflow attacks that have
brought attention to the attack vector. Such attacks could be used against minor web application
servers or large corporate computer systems to gain unauthorized, root privilege, crash systems,
execute malware, etc.
The Morris Worm Attack in 1988
The Morris Worm attack was one of the first complex cyberattacks carried out using malware
code (a worm) to instigate both a Denial of Service (DoS) and Buffer Overflow attack. The
worm attacked a buffer that was declared as the first local variable in the main function, which
ultimately resulted in opening up a reverse shell. Unintentionally, as noted above, the attack
crashed systems on ARPANET via a DoS. As a worm, the malware did not require human
activation or execution, as it both infected computer systems and self-replicated by simply being
on a host system.
While the infection was a first of its kind, it also saw the first criminal conviction of a felony
under the 1986 Computer Fraud and Abuse Act.
SQL Slammer Attack in 2003
The SQL Slammer attack was an infamous 2003 worm cyberattack conducted against unpatched
systems that were using Microsoft’s SQL Server Database System. The worm caused DNS
servers to go down, ISPs to lose internet connections, etc. mainly by overloading network
systems. The worm resided in memory and caused SQL servers to output an endless loop to
other systems. Thus the worm created a type of DoS attack as well, and targeted a buffer
overflow vulnerability in MS SQL Servers.
Buffer Overflow and The OWASP Top 10 Vulnerabilities List
Buffer overflows were a primary security vulnerability among web applications, hence making
the OWASP Top 10 security list for multiple years (2003 and 2004). Due to increasing use of
secure frameworks immune to buffer overflows, all OWASP Top 10 lists after 2004 omit the
attack vector. Secure coding practices, managed code frameworks, and programming languages
that typically conduct automatic garbage collection (memory management) make Buffer
Overflow attacks harder to exploit.

Managed, or interpreted, programming languages (e.g. C#, Java, Python, etc.) have built in
buffer overflow protection, in the form of garbage collection/boundary checks and code
management. Most application’s written today use these languages, reducing the attack surface.
Buffer overflow vulnerabilities are still commonly found in operating systems (which are
primarily written in C/C++), browsers, browser extensions, and many Adobe applications.
Everything from Microsoft Edge to the Microsoft .NET framework (via remote code execution)
and Adobe Flash Playerfall prey to buffer overflow vulnerabilities.

What is a Buffer Overflow Attack?


Buffer overflow conditions occur when a program creates a fixed size object in memory, and
then stores too much information in the object. When an application processes data provided by
an attacker, there is not enough space to store the extra data, causing the program to overwrite
adjacent memory locations. For example, imagine that you have a bucket that can hold a gallon
of water. What happens if you try to pour 5 gallons of water into the bucket? The bucket will
overflow, spill onto the floor, and leave a mess to cleanup. This is exactly what buffer overflow
attacks do to your application’s memory.
When a buffer overflow occurs, custom (malicious) code allows a cybercriminal to crash a
system, and in some cases take control of it by executing commands against the system.
Types of Buffer Overflow Attacks
While a buffer is a generic term describing a set portion of memory for data allocation, specific
types of memory storages can be allocated, called the heap or the stack. The stack is a statically
allocated storage unit of memory associated with local variables (objects) that go out of scope
after program execution, while the heap is a dynamically allocated storage unit of memory
associated with global variables. While stack objects allow for automatic re-allocation after
program execution, heap memory addresses must be de-allocated by the programmer manually.
For both, memory allocation occurs at run-time.
Stack Based Buffer Overflow Attack
A stack based buffer overflow is where the buffer is allocated in the static application memory
stack as a fixed size. Writing too much data into the buffer overwrites the fixed memory location.
This vulnerability occurs because of insufficient bounds checking. Writing too much data into
the buffer causes the out of bounds exception, typically a program crash, and possibly remote
code execution.

This type of attack is related to inefficient memory management in that the stack (buffer) has
been allocated a certain amount of memory, and a user inputs data into the buffer that is greater
than the amount of memory that the stack was designed to hold. Both efficient memory
management and boundary checking (via the optimized GCC compiler at compile time for C/C+
+) can mitigate the issue and prevent cybercriminals from running custom code in the system
remotely.
Heap Based Buffer Overflow Attack
Dynamically allocated memory space is managed by the “heap”. Consider an application that
created a dynamically sized buffer on the heap at run time. Similar to stack-based attacks, this
vulnerability occurs because of insufficient bounds checking when writing data to the heap.
Writing too much data into the buffer can allow attackers to control program execution,
manipulate heap data structures, and overwrite function pointers to attacker controlled
instructions.
At the same time, in the event of an engineer not manually de-allocating objects or pointers to
memory addresses in the heap, a memory leak can result in a heap overflow in attempting to
write data to the heap that has no memory (storage space) left. Hence memory management and
boundary checks are the two primary reasons for stack or heap overflows. It is important to note,
however, that in terms of the heap, languages with automatic garbage collection (C/C++ don’t
come with GC included) will manage memory on the heap automatically by de-allocating unused
objects/data from memory addresses.
Though the size of the stack is determined upon execution (the memory is allocated at run-time)
and generally doesn’t change, the size of the heap can grow as the operator calls upon the OS for
more memory resources (hence being dynamic). This means that while the stack may be
overridden by data inputs (e.g. an endless loop call) creating a stack overflow, the heap can grow
to accommodate the system. However, common memory leaks associated with the heap can
essentially take up memory resources, which stops the heap from accommodating the system’s
needs, possibly resulting in a system crash.
What Systems Are Vulnerable to a Buffer Overflow Attack?
Typically systems built on languages that do not come packaged with garbage collection and are
unmanaged languages – C and C++ specifically. Applications and systems built on these
languages very commonly have buffer overflow vulnerabilities when engineers have not
managed memory correctly or perform boundary checking (via debugging and the use of
optimized GCC).
At the same time, certain systems are very difficult to attack via a buffer overflow. These include
systems built on languages that include automatic garbage collection (memory management),
and managed code languages. Managed code written by development teams runs inside a
protected virtual environment (Java Virtual Machine, .NET Common Language Runtime are
both examples) that provide memory management, array bounds checking, type safety, and
overflow protection. However, it is important to realize that managed frameworks (Java, .NET,
and Python) themselves call into operating system libraries that are vulnerable to buffer
overflow (C / C++). Buffer overflow vulnerabilities can occur when passing unvalidated data
into the framework’s APIs that interface with the operating system.
In line with above, even safe languages such as Java, Python, and the .NET framework have
published buffer overflow vulnerability bugs associated with their frameworks, according to
CVE Details. This can range from a heap-overflow in the JRE (Java Run-time environment), to
an integer overflow in Python, to a directory services protocol buffer overflow in the .NET
Framework.
What Damage Can be Caused by a Buffer Overflow Attack?
Writing too much data into the buffer can allow attackers to control program execution,
manipulate heap data structures, and overwrite function pointers to attacker controlled
instructions. In addition to this, system crashes, a DoS or even DDoS attack, and remote code
execution can be used in combination with malware to escalate privileges and open a reverse
shell. The end result is remote code execution, malware installation, and complete control of the
system running the vulnerable code.
Windows desktop applications, Adobe applications, many browsers, etc. often have buffer
overflow vulnerabilities associated with the use of C/C++. Microsoft Edge, the web browser
packaged with Windows 10, has a known scripting engine buffer overflow vulnerability. With
this bug, objects in memory are handled by MS Edge in such a way that a malicious person could
corrupt the memory and execute his/her own code, allowing him/her to gain the rights of an
authenticated user (root access to the system). With escalated privileges, the malicious person
could create additional accounts, install a backdoor, shut down the system, delete data, install
programs (e.g. malware), and more.
Different MS Windows Server software packages have also been susceptible to buffer overflow
attacks in the DHCP Service. This bug results in remote code execution when a malicious person
sends specially designed packets to the server, resulting in memory corruption. The end result is
control of the system and/or the crashing of the server.
Adobe applications are often susceptible to buffer overflow attacks and memory corruption via
malicious inputs of data. Some examples include an Adobe Acrobat vulnerability that could
result in a malicious PDF causing remote code execution, and an Adobe Flash Player
vulnerability that could result in remote code execution due to the use of both a stack-overflow
(associated with a bug in the application’s use of regular expressions) and social engineering.
Essentially, when a cybercriminal uses a buffer overflow against a corporate system and gains
the ability to run remote code, he/she has complete control of the system and can do almost
whatever he/she desires, assuming that such a person has root privileges.
Checking for Buffer Overflow Vulnerabilities
Conducting a code review is a good way to do a preliminary check for the existence of buffer
overflow vulnerabilities. In addition to this, compilers usually conduct boundary checks at
compile-time to ensure that buffer overflows cannot be performed. For example, the strict C++
compiler option provides applications using C++ with defense against stack overflow issues.
Typically, for optimized compilers will report an error if problems associated with a possible
buffer overflow exist.
Security engineers also conduct code reviews (as mentioned), vulnerability scans, and
penetration tests to determine if buffer overflow vulnerabilities exist. Vulnerability scans will
scan static code (based on parameters) for known buffer overflow coding patterns, while
penetration tests allow an ethical hacker to actively attempt to dynamically utilize buffer
overflow attacks on a system at run-time.
Preventing Buffer Overflow Attacks
Operating systems use Address Space Layout Randomization, or ASLR, which is a memory
protection feature that randomizes the application’s memory, making it difficult for an attacker to
predict its location. Operating systems also use Data Execution Prevention, or DEP, which is a
security feature that separates executable and non-executable data into different memory
locations. Only data placed into an executable location is allowed to run by the operating system.
Buffers placed in non-executable memory locations reduce the damage potential of an attack.
In addition to using ASLR and DEP – when it comes to other software applications – compiler
tools, such as StackShield and StackGuard, help with buffer overflow prevention. The use of safe
functions by engineers and the utilization of code audits, etc. can further ensure that buffer
overflow vulnerabilities are mitigated.
At the Application Layer Strict Input Validation on All dynamic Data
As has been noted, buffer overflows occur due to malicious user inputs, either over a
network/web application (from the client side to a server) or via a non-web software application.
Thus one of the most important methods of mitigation is via strict input validation. Some
additional processes associated with input validation that can be used are:

 String Length Checks – before assigning string data to buffers, engineers should make
sure that the data is not larger than the buffer’s capacity
 Length Checks – engineers should enforce strict length checks on dynamic data before
the data is parsed by the server
 Bounds Checks – engineers should make sure that the size of inputs will fit into a buffer
before writing data into the buffer. Check array indexes and ensure they fall in the valid
range.
 Overflow checks – When performing mathematical operations, validate the numeric
value ranges before the calculation and ensure that the return result fits into the variable it
is being assigned to.
 Avoiding the use of dangerous functions (e.g. strcat, strcpy)
 Languages with direct memory access (C/C++) have deprecated unsafe functions in favor
of secure implementations that are immune to buffer overflow.
 Applications written in C should use the secure methods provided by the Safe C Runtime
library, also known as Safe CRT.
 Applications written in C++ should use the Standard Template Library classes, often
called STL, which automatically detects overflow conditions and throws an exception.
The use of strict input validation on all dynamic data will ensure that only validated, safe inputs
are processed by the application, which will ensure that buffers are not overflowed with data.

You might also like