Handling Computer Worms

Work on handling worms, from a defender's point of view, can be classified three ways: defense, worm capture and containment, and automatic countermeasures. Most of the techniques described here can be illustrated on a network like the one in Figure 1.

An internal network is connected to the Internet through some computer at the network's perimeter.

The nature of this perimeter computer has been left deliberately vague; it can be a dedicated network router or a generalpurpose computer, which may be performing a variety of defensive tasks in addition to shuffling network packets back and forth.

The internal network has a critical subnet, a set of machines which special pains must be taken to protect. There is the user and their computer, which is a host on the network.

Finally, a computer acting as a "honeypot" may be present, whose role will be described later. First, defense.

Defense

How can worms be kept out in the first place? Looking at the path from the Internet to the user in Figure 1, defensive measures can be taken at any point along that path.

User

User education can't be forgotten. Education is especially useful to prevent the propagation of email worms that require an attachment to be run by a human. Users can also be thought of as finely-attenuated sensors which detect the most insignificant slowdowns in network speed, a fact to which any network administrator can attest. Network traffic from worms that is otherwise hidden may be detected by users.

Host

The next line of defense is the user's computer; defenses deployed here are called host-based defenses. Some of the best defenses against worms are the most mundane: applying patches, limiting the amount of available services on a machine.

From there, defenses specific to likely attack vectors are the next step, followed by anti-virus software being used on the host to look for worms.

Patching - Many intrusions by malware are completely preventable. A lot of worms do not exploit previously-unknown vulnerabilities, but use known vulnerabilities for which a patch is available. Illustrated in Figure 8.2, the rate of patching is an exponential decay curve which never reaches zero.

In other words, many machines remain vulnerable for a long period of time after a patch is available, and some machines are never patched. The situation is even worse: the overall patching rate does not change dramatically even when a widely-publicized worm is circulating, exploiting the vulnerability.

Studies of a number of security vulnerabilities for which patches are available have shown similar, discouraging results. There may be a variety of excellent reasons for the laxity of patching.

Qualified personnel may not be available to apply a patch, or may not have time. People may not know about the patch. Bureaucratic issues may preclude proper maintenance, or policy matters may prevail.

For example, some companies require updates to be tested before distributing them. This policy may be seen to be a prudent precaution, because applying some patches (especially hastilyprepared ones made in response to a vulnerability) may break more software than it fixes.

New commodity operating systems (e.g., Windows, MacOS) have automated update systems which notify a user that updates are available, and lead them through the process of downloading and installing the updates.

Not everyone runs the newest version of an operating system, and policy may trump the use of automated updates, but in the long term, automated update systems will probably have a positive impact on security.

Limiting Available Services - The reasoning for limiting available services comes from two premises:

  1. Worms exploit technical weaknesses, like buffer overflows, in network servers. (Here, a server refers to the program that supplies a particular service.)
  2. Technical weaknesses are likely to evenly manifest themselves throughout network server code.

Based on these premises, the conclusion can be drawn that the more network servers a machine runs, the likelier it is that some technical weakness is exposed that a worm can exploit. The corollary is that the fewer network servers a machine runs, the more secure it is.

While the soundness of this logic may be debated, the general idea of reducing potential attack vectors to defend against worms is a good one. There are pragmatic aspects to limiting network servers, too, in that it also limits the amount of software to patch.

The hard part is determining which servers to shut down. This can involve much trial-and-error even for experts, turning off one server after another to see if it affects the machine's operation. Some effects may only be apparent after an extended period of time, if a server is shut down that only sees occasional use.

Countermeasures against - Specific Weaknesses Besides trying to reduce the number of running servers that might contain weaknesses, countermeasures can be used to guard against specific kinds of technical weakness that are exploited by worms. A number of these were presented later, such as:

  • Canaries to detect buffer overflows.
  • Randomizing memory locations to make finding memory addresses harder.
  • Code monitoring to watch for unusual behavior.

Countermeasures to specific technical weaknesses are certainly an important part of worm defense. However, such countermeasures are based on assumptions about how worms are likely to break into a system.

They are of little use against any new types of technical vulnerability that do not happen to be guarded against, and they do not catch worms that use social engineering to spread.

Anti-Virus Software - Anti-virus software can and does look for worms, but there are three major problems that hamper anti-virus software's effectiveness:

  1. To function properly, anti-virus software detecting known worms needs an up-to-date virus database, but virus database updates cannot be prepared and deployed fast enough to counter rapidly-spreading worms.
  1. Some powerful anti-virus techniques are unusable: integrity checking and emulation certify a program as malware-free at the start of the program's execution. These techniques are useless against a worm that injects its code into a running program which has already been declared clean.
  1. A worm need not reside someplace that anti-virus software can analyze. Many anti-virus techniques are geared to catch malware that writes itself somewhere in a computer's filesystem; a worm that exploits a buffer overflow in a long-running network server can remain in memory only, undetected.

This suggests that anti-virus software is no panacea for worm defense. The last problem, detecting in-memory threats, can at least be addressed.

Memory Scanning - Searching for in-memory threats is called memory scanning. Once, memory scanning was an easy task for anti-virus software: the amount of physical memory on machines was small, and any program could read from any part of the memory. Now, two features have made their way into almost all operating systems, both of which complicate memory scanning:

  • Memory protection. Hardware protection prevents one process from accessing another process' memory unless they have both explicitly agreed to share memory. This memory protection greatly increases system stability, because it limits the effect of a misbehaving process - malicious or otherwise.

The drawback from the anti-virus point of view is that memory protection prevents a memory scanner from directly looking at other processes' memory.

  • Virtual memory. The operating system and hardware can conspire to provide virtual memory to processes. With virtual memory, each process thinks it has an enormous amount of memory to use, more memory than is physically available.

The virtual memory contents are stored on disk, and the physical memory acts as a cache for the virtual memory. The operating system, with hardware support, traps virtual memory references that refer to virtual memory pages which are not currently present in physical memory.

The operating system arranges for the absent memory pages to be loaded from disk to physical memory, possibly evicting some physical memory contents to make room. Disks are orders of magnitude slower than physical memory.

If a process were to randomly access its virtual memory, it would slow to a crawl waiting for memory pages to be loaded from disk. Fortunately, that rarely happens. Most programs naturally exhibit a high degree of locality of reference, meaning that they tend to reference only a small set of memory areas at any given time.

As a program's execution continues, the set of memory areas referenced changes to a different small set of memory areas, and so on. The memory pages currently required by a process are called its working set, and the operating system ideally keeps all processes' working sets in physical memory to minimize slow disk activity.

Virtual memory is a huge convenience for programmers, because it reduces the need to work around physical memory restrictions. The net effect of virtual memory for anti-virus software is that a memory scanner doesn't have everything immediately accessible that it needs to scan.

An operating system can have memory protection without having virtual memory; virtual memory can be supported without having strong memory protection between processes, but this is not normally done.

The remainder of this section only considers operating systems with both memory protection and virtual memory, because it is the hardest case to handle. There are several different ways that memory scanning can be implemented in such operating systems:

  • As an ordinary user process, anti-virus software can scan memory by using operating system facilities intended for debugging. Debuggers need to examine (and modify) the memory of a process being debugged, and operating systems have an API to support debuggers.

Anti-virus software can use this API, pretending to be a debugger, to examine and scan processes' memory. This avoids memory protection issues. Care must be taken when scanning the memory of a process.

Attempting to scan all the virtual memory that a process uses will force the operating system to bring in memory pages from disk, an incredibly slow operation in comparison to accessing physical memory.

The victim process being scanned would have its working set of memory pages decimated until the operating system slowly recovers them.

If possible, querying the operating system to determine what memory pages are already present in memory, and only scanning those pages, reduces unpleasantness with a process' virtual memory.

The alternative is grim: one memory scanner increased the resident memory usage of a poor process being scanned by over 2000%.

Memory scanning can further be limited, beyond restricting it to in-memory pages. Ideally, assuming that the anti-virus software already examined a process' executable code in the filesystem before it ran, the only thing that requires rescanning is memory that has been changed.

Extracting this information from the operating system is not always possible, however. Not all processes can be debugged by a user process, for security reasons.

For example, processes belonging to another user or privileged system processes will not permit just any user process to attach a debugger to them. The anti-virus software must run with escalated privileges to allow it to "debug" all other processes.

  • Some of the problems with the memory scanning implementation above can be avoided if the anti-virus software runs as part of the operating system kernel. Kernel-based anti-virus software will have permission to access all processes' memory, avoiding access problems.

A memory scanner can be integrated more deeply into the kernel for even better effect. Tying a memory scanner into the operating system's virtual memory manager would still avoid permission problems, plus give the memory scanner access to information about modified and in-memory pages.

Once a worm or other malware is discovered in memory, memory disinfection can be done by terminating the offending process completely. Riskier options are to terminate suspect threads within the infected process, or to patch the code in the infected process as it runs.

Operating systems share memory pages between processes when possible, as for shared library code or read-only program code segments, and consequently many processes may be affected by an infection - the best memory disinfection may be a reboot.

Disinfection may be an ultimately futile operation anyway, because if the infection vector was a technical weakness, then a worm can re-exploit the machine right away. Any of the above implementations of memory scanning leave another window of opportunity for worms, because the scanning is not done continuously.

Rescanning memory continuously, for each memory write, would involve a prohibitive amount of overhead except perhaps for interpreted languages that already proudly sport prohibitive overhead. Philosophically, it is not clear that memory scanning by anti-virus software is a good idea.

Memory scanning necessarily weakens the memory protection between unrelated code, in this case the anti-virus software and the process' code being examined.

Strong memory protection was implemented in operating systems for good reason, and circumventing it may only introduce new attack vectors. Anti-virus software that doesn't scan memory, in combination with other defenses, may be a wiser choice.