Computer Worm

The general structure of a worm is:

def worm() : propagate () if trigger() is true: payload()

At this level of abstraction, there is no distinction between a worm and a virus. The real difference is in how they propagate. Propagating by infecting other code is the domain of a virus; actively searching for vulnerable machines across a network makes a worm.

A worm can either be said to infest or infect its victims; the latter term will be used here. A single copy of a worm will be called a worm instance, where it's necessary to avoid ambiguity. In some cases, worms are classified by the primary method they use for transport.

A worm using instant messaging (IM) to spread is called an IM worm, and a worm using email is an email worm. For example, many email worms arrive as an email attachment, which the user is tricked into running. When run, the worm harvests email addresses off the machine and mails itself to those addresses.

Tricking users into doing something is social engineering, and this is one mechanism that worms use to infect machines. Another mechanism that worms exploit for infection are technical weaknesses.

A user doesn't have to be tricked into running an email attachment, if just viewing the email allows the worm's code to execute via a buffer overrun. A user doesn't have to be involved at all, if the worm spreads using buffer overruns between long-running network server processes on different machines.

A worm can also exploit existing, legitimate transactions. For example, consider a worm able to watch and modify network communications, especially one located on a network server machine.

The worm can wait for legitimate transfers of executable files - file transfers, network filesystem use - and either substitute itself in place of the requested executable file, or insert itself into the requested file in a virus-like fashion.

Most of the details about worms have already been covered in earlier chapters, like technical weaknesses and human weaknesses. Worms can also employ the same techniques that viruses do in order to try and conceal themselves; worms can use encryption, and can be oligomorphic, polymorphic, or metamorphic.

Xerox PARC, c. 1982

The worm used in the Xerox PARC experiments of the early 1980s wasn't intentionally malicious, despite the above quote. It was intended as a framework for distributed computation, to make use of otherwise unused CPU time.

A user would write a program to run in parallel, on many different machines - this program would sit atop the worm mechanism, and the worm would manage the mechanics of making the program run on different machines.

It would be highly unusual to see a worm now that places an artificial limit on its own propagation, but that was exactly what the Xerox worm did. The Xerox worm was composed of multiple segments, by way of analogy to real biological worms; at most one worm segment could run on any one machine.

A bounded, finite number of segments were started, and all segments kept in contact with one another. If the worm lost contact with a segment (for example, someone rebooted the machine that the segment was running on), then the other segments sought another machine upon which to run a segment. Safety mechanisms were built in to the worm.

This was done in part to assuage user concerns about having such a beast running on their computer; segments were not allowed to perform disk accesses, for example. Keeping segments in contact had a safety benefit, too, in that the entire worm could be shut down with a single command.

And was, in the case from which the above quote was taken. The worm had gone out of control through an odd set of circumstances, and had to be stopped. One of the key insights the researchers at Xerox PARC made from their worm experiments was that managing worm growth and stability are hard problems.

Internet Worm, November 1988

Whether people called it a worm or a virus, the Internet worm was a major wake-up call for Internet security. It worked in three stages:

Stage 1 - The first stage was for the worm to get a shell on the remote machine being targeted. The worm would use one of three methods to acquire a shell, mostly relying on security holes of mythic proportion:

  1. Users read and send email using mail programs which are generically called mail user agents. The actual gory details of transmitting and delivering mail across the network are handled by daemons called mail transport agents.

Mail user agents send mail by passing it off to a mail transport agent, which in turn can talk to mail transport agents on different machines, to send the mail along its merry way. Sendmail was a widely-used mail transport agent at the time of the Internet worm.

Simple commands are used to identify the connecting machine, specify the mail's sender and receiver, send the mail, and complete the connection. Older versions of sendmail also supported a "debug" command, which allowed a remote user to specify a program as the email's recipient, without any authentication. The Internet worm trivially exploited this to start a shell on the remote machine.

  1. The finger program was a user program which could be used to discover information about another Unix user; indeed, it was once common to sit in a terminal room and finger people.

The finger daemon read input from the network connection using C's gets function, which does no bounds checking on what it reads in. The Internet worm would exploit this by performing a stack smashing attack against the finger daemon to get a shell.

  1. Several utility programs used to permit a user to run commands on a remote machine. The Internet worm tried two of these in an effort to get a remote shell: rexec and rsh.

Rexec required a password to log in to the remote machine. The worm's third stage would guess at passwords, trying obvious ones like the username, and mounting a dictionary attack too.

A dictionary attack is where an attacker has a dictionary of commonly-used words, which are tried one by one as potential passwords. The worm's third stage carried a list of 432 words that it used for this purpose.

Rsh could be even more accommodating for getting a remote shell. It had a facility where users coming from specified "trusted" hosts didn't even have to supply a password.

Stage 2 - Once a shell was obtained on the remote machine, the worm would send commands to create, compile, and run a small C program on the machine being infected. This program was portable across the prevalent Unix architectures of the time, and had another technical advantage.

Because it was sent in source form, it was immune to damage from communication channels which only passed through seven bits out of eight, which would have destroyed a binary executable file.

The compiled program was a "grappling hook" which was used to pull the worm's Stage 3 executable files onto the machine being infected. When run, the grappling hook would make a network connection back to the infecting machine (whose worm instance was expecting the incoming connection).

This connection was used to transfer several Stage 3 executables, one for each architecture that the worm could infect. These executables would be tried until one succeeded in running.

Stage 3 - At this point, the worm was fully established on the infected machine, and would begin trying to propagate itself to other machines.

Some rudimentary stealth measures were deployed. The worm named itself "sh" to appear as a user shell, and modified its command-line arguments; both these would make the running worm process look unremarkable to a casual observer. Previous remnants, like temporary files used for compiling the grappling hook, were removed.

Finally, the worm prevented "core dump" files from being created - a Unix system will create core dump files for processes incurring fatal errors, or upon receipt of an explicit user request to do so. This latter step prevented easy capture of worm samples for analysis.

New target machines were selected using information from the infected machine. Information from network interfaces, network routing tables, and various files containing names of other computers were all used to locate new machines to try and infect.

The Internet worm carried no destructive payload. Worm damage was collateral, as each worm instance simply used lots and lots of machine and network resources.