Bugs, Crashes, and Vulnerabilities

By Mark Webb-Johnson, Chief Technology Officer, Network Box

An application or operating system crash seems to be the norm with modern computers. We have all become used to frequently saving our work, hitting that ‘Relaunch’ button, and carrying on from where we were interrupted.

But have you ever wondered about what causes the crash, and if there are any more significant implications? Well, there is good reason to be concerned. Usually, programs crash due to some unexpected input, and that crash can be the route into your system for a malicious hacker.

What causes applications to crash?

There can be many reasons, but the vast majority is because the program did something that the operating system did not like. Either some system function was called with invalid parameters, or the application tried to access resources it should not have access to the most common is an ‘out of bounds’ memory access, where the application is attempting to access memory out of its permitted ownership.

It is simple for a programmer to ask for some input (such as a user name), and then copy that input to a storage variable for later use. In the popular ‘C’ programming language, it looks like this:

char username [32];

strcpy (username, input);

The strcpy() function is historically very commonly used, and copies a string from the second parameter (input) to the area of memory pointed to by the first (username). It stops the copy when it reaches an end-of-string marker (the byte zero).

But, what if the input provided is bigger than 32 characters (or 31, as the zero terminating byte, takes up one)? The answer is that strcpy() doesn’t care and will carry on copying. Whatever comes after the username will be overwritten. If the username variable is at the top of memory, that will result in a ‘memory out of bounds’ crash. Even if that is not the case, other things may get overwritten and mess up the program flow or cause other problems.

Another common approach is for the input to come in the form of a protocol message in a network communication stream. In many cases, such protocols encode data as

<length><message>, sending the length to expect first, followed by that number of bytes of the variable-length message. What if an attacker hand-crafts protocol messages, with malicious lengths designed to overwrite memory arbitrarily?

Of course, program developers should thoroughly validate such cases. Looking at the history of such vulnerabilities, it is evident that some (perhaps most) do not.

What are the security implications?

Let’s look at a typical computer memory architecture in use today. Code and data reside in the same memory. Code is at the bottom, global variable memory sits above that, and the stack is at the top. There may also be an area called the ‘heap’ for dynamic memory (that can be extended upwards, if necessary). The key here is that code and the global variables are fixed in size, but the stack grows downwards. It looks like this:

The stack is an interesting piece of technology. Let’s look at our strcpy() example above. What happens is that when the program calls the strcpy() function, the current address of the program is ‘pushed’ onto the stack, and then control flows to the strcpy() function itself. When that function has done its work, it calls the ‘return’ function, which ‘pops’ the return address off the stack and resumes control flow at that point. This scheme allows for functions to call other functions in a nested fashion only limited by the stack’s size.

It is also common for local variables, such as the username, to be stored on the stack. Let’s look at the memory arrangement for our original strcpy() program while running the strcpy() function:

Let’s say the attacker delivers a ‘payload’ as input:

■ 32 bytes of username (no zero characters)

■ A 4 byte pointer to the payload target (just above)

■ The rest of the payload containing code to be executed

■ Zero termination to end the strcpy()

Now, the strcpy() function dutifully copies all that into the username, overwrites the return pointer, and then overwrites the upper stack with the payload provided. The strcpy() function returns, and the CPU dutifully pops the return address (now pointing to the code in the payload provided by the attacker) and transfers control to the attacker. Game over, and the attacker wins.

The good news

The above sounds bad. But the good news is that nowadays, it is not so simple. There is an ongoing cat-and-mouse game between defenders and attackers, with the defenders adding more and more complications and controls to make things harder for the attackers. Technologies such as:

■ Tagging different memory regions as not executable, such as the stack

■ Address randomization, so the memory layout is not predictable

■ Stack canaries, unique values on the stack that if modified signal stack corruption

These all make it a lot harder for an attacker to succeed with such attacks.

Industry partnerships (such as the Microsoft Active Protection Program – MAPP – which Network Box participants in) also exist to share detailed vulnerability information. Security providers like Network Box can release protections to give users time to update their applications.

Nowadays, most popular operating systems allow you to log in and use the system as a low privilege user (only escalating to administrative privileges when required). Logging in like this initially limits the impact of any exploit to the user’s access rights, again gaining time.

That said, new vulnerabilities are announced every day (the most popular tracking service currently has more than 140,000 in its database), and while not all are exploitable, some are. The rewards for a successful zero-day exploit (one that nobody else knows about) can be in the hundreds of thousands of dollar range.

So, the next time a program crashes on you, perhaps it would be a good time to ‘check for updates’ and see if a fi­x has been released. You can also opt-in to share crash data with the application developers so that they can be notifi­ed of such problems and make iterative improvements.

Mark Webb-Johnson is the co-founder and Chief Technology Officer of Network Box. It is Mark’s technical genius that drives the cybersecurity innovation at Network Box. He and his team constantly come up with the solutions that keep Network Box ahead of the rest. Over the years, Mark has taken on numerous projects and extremely difficult technology problems, and always come up with an elegant solution. It is hardly any wonder he won the Lord Hailsham Prize for Computer Science.

Follow Brilliance Security Magazine on Twitter, Facebook, and LinkedIn to ensure you receive alerts for the most up-to-date security and cybersecurity news and information.