Finding and Exploiting Bugs
by Astroman66
Bugs are an inherent part of any software system, large or small. It is estimated that there are 15 bugs per 100 lines of code in larger systems, and while companies try their hardest to decrease this proportion, it will never get to zero.
In this article, I will try and make three major points:
- That no matter what system one is working on, there are bugs in it.
- How to find bugs in software systems.
- How to exploit those bugs.
The nature of developing a software system (by this I mean a large base of code that may contain up to millions of lines of code but may be several hundred thousand, referred to as either software or firmware) is basically this: the developers write the code, the testers test the code and report the defects found back to the developers who try and fix as many as they can. They then hand it back to the testers, who test it and hand it back to the developers. This process goes on until either the budget runs out or the time constraints expire, at which time the product is released. There will still be bugs in the code. The point when developing software/firmware is not to eliminate bugs - that is literally impossible. It is to minimize the affect of those bugs on everyday use of the product.
Everyday use. This is central to the issue of finding bugs in software systems. Code-paths that are routinely taken are honed down to virtual perfection. But development simply cannot focus as much attention on the rarely take code-paths and therefore there is some degree of vulnerability in those sections of code. When trying to find bugs in software systems, these are the areas to focus on. These parts of code are where the bugs are.
How to Find Bugs
I will outline three general methods for finding bugs in software systems.
The most obvious place to start looking for bugs are at maxima and minima points in the variables. This is formally called Boundary Testing. Extreme values for variables are always a problem for software. If the variables are designed to manipulate small numbers, try overloading them or using very large values, and vice versa if the variables are designed to use large numbers. What happens when the elements in a particular array are maxed out? What if they are all empty?
Why are there bugs at maxima and minima points? Variables are generally used to hold a particular range of values - they serve a very distinct purpose, and therefore are expected to handle very distinct values. That is their general use. If you alter that, or push the boundaries of those variables, you are entering an area of the system that rarely gets exercised. When a part of the system is rarely used, bugs stay hidden - until you run across them.
Whereas variables are part of the lowest level of code, the next level up is the code-path. By traversing through remote parts of code, you could very easily run into a bug. Because most, if not all, of the time you will be doing "black box" analysis (meaning you cannot access the code itself), it can be difficult to understand where in the code you are moving. But you need not think of it in terms of traversing through source code. Use parts of the program that never get used, and combine them with commonly used sections, then try going the other way (from common to rare). If you stumble across a particularly removed command, use it in conjunction with ever other command or function you can think of. Remember, what doesn't normally get used didn't get tested extensively while being developed. There are bugs in there, you just have to find them.
The third place bugs are common is at error-handling points in a software system. After all, at error-handling points something has already gone wrong and now the system must recuperate from that error. This is not always a clean process. here are a number of things that could happen if the process fails, from locking the system to dropping you out of the program to the shell.
Try generating errors, but from an odd perspective. Say a certain password program fires up when your computer is undisturbed for five minutes. That this little program must look up your password makes it interesting enough, but what happens if some error should occur while it is doing so? Is this program, or part of a larger system, designed to handle all combination of characters given it? What about system (or reserved) character combinations? What about maxing out the arrays? It's worth a try...
Finding bugs from scratch is a difficult task. What's better is when you have bugs, fixed or not, to work with.
Exploiting Bugs
Exploiting bugs is the process by which one uses an existing condition (that resembles a malfunction of the program in some way) to cause a condition to occur that is beneficial to the user.
For example, I was perusing the alt.computer.security newsgroup the other day, and found that someone had noticed that Microsoft had left a port open on one of their web servers. While the person describing this said he couldn't get anything to happen while logged on to the port, he was asking if there was still some prospect of exploiting this "bug." He found a malfunction in the programming of Microsoft's web server and, based on that behavior, wanted to cause the server to function to his advantage. This is exploitation.
Of course, exploitation requires that a particular bug is known. Fortunately, known bugs are very easy to come by. If you are working off an upgrade version of software (that is, anything besides ver. 1.0), look at what features were upgraded. Each one of those items were at one time a problem-spot in the software. Not only were there bugs in those sections of code, but there are probably bugs still there. This gives you a clear indication of which part of the software to "test."
Scan the computer security newsgroups - there are constantly reports of bugs and exploits explained in those posts. This can give you a direct target to work on. Security web pages abound on the net - use them to your advantage. Learn as much about the software you are testing. Oftentimes if you know what is supposed to happen, you will notice when some anomaly takes place; you might not have noticed it otherwise.
So you've found a bug that you want to target - and let's say it has already been fixed. So much for exploiting that particular bug. But it is characteristic of software systems that bugs appear in groups, in sections of code, not so much individually.
Normally, with code that has been developed by numerous programmers working under all sorts of conditions, there will be patchy sections of code that hold more bugs than others. So the particular bug you have found has been fixed - more than likely there are other bugs hiding in surrounding code. How do you find out? Use the bug-tracking techniques outlined in the previous section of this article. Just focus your attention on and around the bug already known.
This method of software testing is often called "Exploratory Testing." It is often, informally, referred to as ad hoc testing. Exploratory testing is the process by which the tester will systematically move through various conditions in order to expose bugs in the area of an already existing bug. Informally, this could be called "tweaking" the program, a little bit at a time. Change things here and there, try this, do such-and-such, etc. If you can just mess around with the bug you already know about, chances are you could turn up another one.
Some Points to Keep in Mind
There are bugs in the software; you just have to find them.
Bugs typically show up in groups. Find one bug, and there are probably others close by.
Use Boundary Testing to push variables to the limit.
Try exercising remote code-paths.
Cause errors, but from odd angles. Try and cause a messy error handling condition.
Use Exploratory Testing to find bugs in the area of already known bugs.
Practice the techniques outlined above, and pay close attention to what happens to cause software to malfunction. You will be finding bugs in no time.
Happy hunting!