Morris, (also known as the Internet Worm or the Great Worm) is sometimes considered the first intenet worm. It was also the first worm to gain significant media attention as well as the first worm to highlight the need for better network security and brought to attention many of the vulnerabilities in some of the Unix-based systems. The worm infects Sun Microsystems Sun 3 systems, and VAX computers running variants of 4 BSD Unix, exploiting holes in the debug mode of the operating systems' sendmail program. It was actually made at Cornell, but released at MIT to hide its origin.
The worm arrives on a system by exploiting one of three vulnerabilities existing in Solaris and BSD systems of the time in rsh, fingerd and sendmail. If the worm determines that the new machine is infectable, it will send files to the new machine that download the main worm to it.
When the worm runs on a system, it performs several actions to prevent detection. It first sets its own argument to sh, which is the same process name as the Bourne Shell. This is a common command shell on Unix-based systems, so if a user were to open a list of running processes, the user would see nothing unusual. The worm's core dump size to 0 bytes (core dumps occur when a program crashes and a copy of the CPU process is placed in the memory for examination), so that the worm can never be found and examined if it crashes or is forced to crash. The worm then reads the current time and stores it for future use with its random number generator.
The worm then tries to load object files that are needed to run completely. The worm may run with a -p command line argument, which causes the worm to delete these files after loading them, and later deletes the disk copy of the running worm itself. It also tries to delete the file /tmp/.dumb, which would never be used by the worm again anyway. If it fails to load any of the files, the worm stops running. The worm will also stop running if it does not have at least one object file in its commandline, or if it has not loaded the l1.c file that it uses to spread to other systems. The worm erases the text of the argument array, again to hide its presence.
The worm scans for network interfaces, as well as their flags and addresses. It will stop running if none are found. It will load the network mask which allows it to determine what addresses are used by the local network. It then kills the process from the -p option, while changing the current process group to avoid killing itself. This action completes the initialisations and the worm calls its central routine.
After successfully infecting a system, the worm runs a routine called Cracksome, which searches for potential hosts to infect. The worm will then run another routine called other_sleep for thirty seconds. The worm will run Cracksome again and then fork into two child processes and kills the parent process. The child has all of the information that the parent had; in addition, the child has a new process number, making the worm difficult to find. The Worm then runs through the infect process. The worm will then run other_sleep again for 120 seconds. The worm will also try to send one byte to port 11357 of the address 126.96.36.199 (ernie.berkeley.edu), but this failed as the worm used the TCP command sendto rather than a UDP datagram. This was an attempt by the creator to monitor the worm's spreading over the Internet. If the worm has run for over 12 hours, it will clean up some of its host list entries. The worm checks its pleasequit variable and will stop running if it has used more than 10 words from its dictionary files for passwords.
The Morris worm then runs the Cracksome routine (Morris's actual name for it) which searches for other systems to infect and attempts to break weak passwords. The worm reads through the file /etc/hosts.equiv for one list of machines to infect. Machines found with this file are specially tagged by the worm. It may find a second list in the /.rhosts file for infection at a later time. The worm also takes advantage of a major security hole, reading the /etc/passwd file, which contains a list of all users on the machine and their passwords, which are encrypted. The Worm will then use the the /etc/passwd file to find personal .forward files, used to forward mail to other machines, to get the locations of additional machines to attack.
The worm then begins to attack the systems it found in the files it scanned. It begins by trying some really weak passwords, at which it is successful about thirty precent of the time. The worm will use its own encryption algorithm to choose a possible password, encrypt it and check it against the encrypted passwords found in the /etc/passwd file. This way the worm can try a password an infinite number of times without setting off any alarms for failed logins. The password possibilities are no password at all, the username, some variation on the username (spelled backwards, or appended to itself), the second value in the GECOS string found in /etc/passwd, remainder of the full name after the first name in the GECOS string (if the first letter is capitalized, it will be tried a second time in lower case) or the previously mentioned name in the GECOS string. The worm attacks 50 accounts each time cracksome is called and stops when it has gone through the list of accounts. Every 10 times Cracksome is called, the worm will call the other-sleep function with a 0 argument.
Once the Morris worm has gone through the entire list of accounts, it turns to a built-in dictionary. The words of the dictionary are encrypted to confuse people trying to decompile the program. The worm decrypts the dictionary and then tests the decryptions against the encrypted password in the /etc/passwd file. The dictionary mostly contains nicknames, character names and other other names and words that are not likely to be found in a standard dictionary, but are reasonable choices for passwords. The worm may take 9 hours to complete the entire dictionary.
Finally, the worm will look for words in the file /usr/dict/words, which is a huge file filled with words that would probably all be found in a standard dictionary. It will try lower case versions of words that are capitalised in the file. It was estimated that going through the entire file would take the worm 4 weeks, which never happened, as the worm was removed after only four days.
The other_sleep function attempts to find other worms on the system. There is a 1 in 7 chance that the worm will perform this function, and if so, it runs for 30 seconds for the first time and 120 for the second. The function other_sleep is called with an integer as its argument. It then checks the global variable other_fd. If this variable was negative, it would simply wait the amount of time specified by its argument, and then pick up where it left off.
If the variable is not negative, the worm would listen for signals from other worms on the network. If the Worm detected a signal that might be another worm, the worms would exchange two pre-specified numbers to verify that it is connected to another worm. If it was, the listening Worm would transmit a random number to the other worm. If the random number produced was odd, the pleasequit global variable (this, obviously, tells the worm to stop running) in the listening worm was set. Otherwise, the pleasequit variable of the other Worm was set.
The failure of the other_sleep function was what caused the worm to be such a disaster. The worm had to continue collecting usernames and systems to attack, as well as going as far as testing at least 10 words from its internal dictionary in order to stop running. Also, when several worms had infected a computer at once, they would all attempt to look for listening worms, at which none of them would succeed. They would also all attempt to become listeners, and only one would succeed at this. If several Worms started at once in the presence of a running Worm, and the running Worm looses in the decision as to which process quits, all the new Worms would, by default, win and continue with their tasks. If a machine was heavily loaded (not uncommon as the worm made its rounds) there would be too much lag time when the worms tried to listen for or send numbers, and would assume that they had received false signals and continue running. In addition, only 1 in 7 worms perform the neccessary check for the other_sleep function to even be considered for use.
The worm's Infect routine first determines whether a target system can be infected. This includes whether or not there is already a running worm on the target system, if the worm has made previous failed attempts to infect it and if it even really exists.
Once a legitimate target is found, the worm calls the other_sleep function with an argument of 1 and then begins its attack routines.The first is called try_rsh.
This attack method operates by creating a duplicate process which attempts to remotely execute on the target machine. If this child process succeeds in its task, it returns the file descriptors of the open pipe back to the main worm in order to receive the new worm process. If it fails, the file descriptors are closed, the child process is killed and attempts the try_fingerd method.
The try_fingerd attack method exploits a vulnerability in the Unix fingerd function which allows the overwriting of the buffer in which the fingerd program reads an argument string. The worm will not use this on a SunOS system, only on BSD, but it would have been possible. The Morris worm takes advantage of this, calling fingerd with a 536 character argument. This overwrites the 512 character buffer of the fingerd function. The additional 24 characters end up overwriting the system stack, which controls what functions are called next opening up command interpreter which the worm then uses to send itself to the target system. This was one of the more impressive aspects of the worm, as the Finger program is very simple and no one had thought to check for a vulnerability in the program until the worm appeared.
If either of the two techniques described above succeed, the routine sendWorm is called which sends a set of object files to the target machine, including the program l1.c, which then opens a connection to the original Worm, allowing the Worm to create a duplicate process in the new machine.
If the two other infection methods fail, the worm resorts to its try_sendmail attack routine. This routine takes advantage of a vulnerability in the TCP networks of BSD systems that allows someone to send mail to a process rather than a user account (this vulnerability was actually used by the program's creators to test it, but the vulnerability was never removed). The worm exploits this by sending a mail message with a carefully constructed recipient string. This string sets up a command that deletes the header of the message being sent and passes the body of the message to a command interpreter, causing it to subsequently compile a copy of code that then opens a connection and pulls a copy of the Worm onto the new computer. If this attack fails, the control returns to its infect function, which marks the host as immune.
A bug in the worm's code caused the worm to spread faster than its creator had expected. Computers all over the United States connected to the Internet crashed, froze or completely slowed down. The estimated cost of dealing with the worm at each installation ranged from $200 to more than $53,000. Teams of programmers from Berkeley and Purdue Universities worked overnight to stop the worm and came up with two separate solutions, as they had little ability to communicate with each other. It took several days for the Internet to return to normal, as many sites had simply disconnected altogether.
Total damages are unknown. John McAfee estimated that the damages were about $96 million, but some accused him of creating a self-serving estimate. Other estimates place the damage as high as $186 million. More reliable estimates place th e toll at a mere $1 million, citing mostly downtime while cleaning computers of the worm. The number of computers infected was originally placed at 6,200 (10% of the internet at the time), but later lowered to about 2,000.
While the worm was able to perform its infection routines, some researchers have noted that the quality of the worm's coding is mediocre at best. One researcher cites examples of unused variables, unused routines, variables called before they are initialized, unreferenced routines and bugs, among other things. In many cases calls to system routines are not checked for success. Rather than using hash buckets or sorted lists, which could be implemented by an advanced computer science student, the worm searched through linear lists, which used more system resources and takes less programming knowledge. The creator also had the worm take little advantage of the root password being broken. The creator also had apparently little experience with UNIX shell coding, as in one shell script used by the worm uses the test line if [ -f sh ] to search for the presence of a file named sh. This allowed users to prevent infection by placing a directory named sh, which causes the test to fail.
Charles Schmidt, Tom Darby. "Tour of the Worm"
Eugene H. Spafford, Department of Computer Sciences Purdue University. "The Internet Worm Program: An Analysis", Purdue Technical Report CSD-TR-823. 1988.11.29, revised 12.08
Project MAC ("Switzerland") MIT Project on Mathematics and Computation, "The Robert Morris Internet Worm."
Vmyths, Morris Internet worm 2001.01.18