Finding Weaknesses On a System

How do attackers find technical weaknesses in the first place?

They can find the vulnerabilities themselves:

  • Source code can be studied for vulnerabilities, when attacking a system where the source is available. - Even when a system is closed-source, it may be derived in part from a system with available source code.
  • Disassembly listings of programs and libraries can be manually searched, looking for opportunities. For example, an attacker could look for bufferhandling code or calls to format functions. While this may sounds daunting, it is never wise to underestimate the amount of free time an attacker will dedicate to a task like this.
  • Instead of poring over disassembly listings, an attacker can reconstruct a facsimile of the target program's source code using tools for reverse engineering, like decompilers. This provides a slightly higher-level view onto the target code.
  • Vulnerabilities can be discovered even without direct access to the target program or its source code. Treating the target program as a "black box" might be necessary if the target program is running on a remote machine for which the attacker doesn't have access."

For example, an attacker can look for buffer overflows by feeding a program inputs of various lengths until a suspicious condition is seen, like abruptly-terminated output. More information, such as the buffer's length, can be found through trial-and-error at that point by performing a binary search using different input lengths.

Computers excel at repeating such mundane tasks, and finding the length of a buffer can be automated. In general, any research on automated program-testing can be applied by an attacker. Such methods have a demonstrated ability to find long sequences of inputs which cause a program to misbehave.

The other option an attacker has is to wait for someone else to find a vulnerability, or at least point the way:

  • There are a number of full disclosure mailing lists. Advocates of full disclosure argue that the best way to force software vendors to fix a vulnerability is to release all its details, and possibly even code that exploits the vulnerabilities.

The extreme contrast to this is security through obscurity, which holds that hiding security-related details of a system means that attackers will never be able to figure them out.

Again, underestimating an attacker is a bad strategy. An exploit made available on a full-disclosure list can either be used directly, or might be used to indicate the direction of more serious problems in the targeted code.

  • A vendor security patch is a wealth of information. Either the patch itself can be studied to see what vulnerability it fixed, or a system can be compared before and after applying a patch to see what changed.

Tools are available to help with the comparison task. All but the most trivial alteration to the patched executables will result in a flurry of binary changes: branch instructions and their targets are moved; information about a program's symbols changes as code moves around; new code optimization opportunities are found and taken by the code's compiler.

For this reason, tools performing a straight binary comparison will not yield much useful information to an attacker. Useful binary comparison tools must filter out nonessential differences in the binary code. This is related to the problem of producing small patches for binary executables.

Any observed difference between two executables must be characterized as either a primary change, a direct result of the code being changed, or a secondary change, an artifact of a primary change.

For example, an inserted instruction would be a primary change; a branch offset moved to accommodate the insertion is a secondary change. Spotting secondary changes can be done several ways:

  • An architecture-dependent tool effectively disassembles the code to find instructions like branches which tend to exhibit secondary changes.
  • An architecture-independent tool can guess at the same information by assuming that code movements are small, only affecting the leastsignificant bytes of addresses.

Naturally an attacker would only be interested in learning about primary changes, after probable secondary changes have been identified. Other binary comparison approaches build "before" and "after" graphs of the code, using information like the code's control flow.

A heuristic attempt is made to find an isomorphism between the graphs; in other words, the graphs are "matched up" as well as possible. Any subgraph that can't be matched indicates a possible change in the corresponding code.

The Holy Grail for an attacker is the zero-day exploit, an exploit for a vulnerability that is made the same day as the vulnerability is announced - hopefully the same day that a patch for the vulnerability is released.

From an attacker's point of view, the faster an exploit appears, the fewer machines that will be patched to plug the hole. In practice, software vendors are not always fast or forthcoming, and an exploit may be well-known long before a patch for the vulnerability manifests itself.