Skip to content

Page389

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:

variable $username[20]
print “Enter Username:”
getstring($username)

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":

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

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.

TOCTOU/Race Conditions

Time of Check/Time of Use (TOCTOU) attacks are also called race conditions: an attacker attempts to alter a condition after it has been checked by the operating system, but before it is used. TOCTOU is an example of a state attack, where the attacker capitalizes on a change in operating system state.

Here is pseudo-code for a setuid root program (runs with super user privileges, regardless of the running user) called “open test file” that contains a race condition:

  1. If the file “test” is readable by the user
  2. Then open the file “test”
  3. Else print “Error: cannot open file.”

The race condition occurs between steps 1 and 2. Remember that most modern computers are multitasking: the CPU executes multiple processes at once. Other processes are running while our “open test file” program is running. In other words, the computer may run our program like this:

  1. If the file “test” is readable by the user
  2. Run another process
  3. Run another process
  4. Then open the file “test”

An attacker may read any file on the system by changing the file “test” from a file to a symbolic link (like a desktop shortcut), between the “if” (time of check) and “then” (time of use) statements:

  1. If the file “test” is readable by the user
  2. Attacker deletes “test,” creates symbolic link from “test” to /etc/shadow
  3. Run another process
  4. Then open the file “test” (now a symbolic link to /etc/shadow)

If the attacker wins the race (changes the status of “test” between the “if” and the “then”), “test” is a symbolic link that points to /etc/shadow. The setuid root program will then open the symbolic link, opening the /etc/shadow file.