Re: [Fwd: Truth about ssh 1.2.27 vulnerabiltiy]

From: Sylvain Robitaille (sylat_private)
Date: Wed Sep 29 1999 - 13:59:48 PDT

  • Next message: Richard L. Goerwitz: "Re: Sun's TTSESSION Vulnerability"

    > I'm surprised that nothing further has been reported to Bugtraq about
    > this, but the problem appears to be that under Linux, a bind() to a
    > Unix-domain socket will follow a dangling symlink, whereas most other
    > Unixes appear to return an EADDRINUSE error.
    
    A number of folks have provided results of their testing on various
    operating systems, so some of this may seem redundant, but then again
    the additional data might be useful.
    
    I've tested the published exploit on each of Linux-2.0.36, Digital Unix
    4.0e, and Solaris-2.7. Both Linux-2.0.36 and Solaris-2.7 appear to do
    the right thing. Digital doesn't.
    
    Since we can't count on the commercial OS vendors to provide fixes as
    quickly as the OpenSource OSes, I'd like to propose the following patch
    (appended below my signature) to ssh-1.2.27. Whether the Ssh developers
    use it in a future release is entirely up to them of course. I believe
    it has been clearly established that the problem isn't with Ssh itself,
    but with the OS.
    
    With this patch, the authentication-forwarding fails if the filename
    which is about to be used already exists as anything other than a
    socket. If a socket already exists by that name, we can be pretty sure
    it's a remnant from an earlier session (perhaps the machine crashed
    while the socket was open?)
    
    If the file *does* exist *and* is a symbolic link, it's likely that
    someone is trying the exploit, so I've added code to mail the host's
    sysadmin with vital stats of the symbolic link, (so the offending
    account can be dealt with accordingly). Otherwise we continue without
    authentication forwarding since it's likely that something strange is
    up, but not an attempt to use this exploit.
    
    I don't promise the most impressive code, but it has been tested (on
    Digital Unix) and I believe it works correctly. Comments are of course
    welcome...
    
    --
    ----------------------------------------------------------------------
    Sylvain Robitaille                              sylat_private
    
    Systems Manager                                   Concordia University
    Instructional & Information Technology        Montreal, Quebec, Canada
    ----------------------------------------------------------------------
    --- newchannels.c.original	Wed May 12 07:19:27 1999
    +++ newchannels.c	Wed Sep 29 14:35:50 1999
    @@ -16,6 +16,11 @@
     */
    
     /*
    + * Revision 1.50unoff 1999/09/29 14:27:52  <sylat_private>
    + *      ssh-agent symlink DoS exploit protection added
    + */
    +
    +/*
      * $Id: newchannels.c,v 1.49 1999/02/22 08:14:01 tri Exp $
      * $Log: newchannels.c,v $
      * Revision 1.49  1999/02/22 08:14:01  tri
    @@ -317,7 +322,77 @@
    
     #define STATUS_TERMINATE                0x003f
    
    -/* Data structure for channel data.  This is iniailized in channel_allocate
    +/*
    + * 1999/09/29 Sylvain Robitaille: Used for mailing to the sysadmin(s) if
    + *            we catch someone trying the exploit to cause the agent
    + *            socket to be created at the other end of a sym-link.
    + */
    +#define MAIL_RECIPIENT "sysadm"
    +#define MAIL_COMMAND   "/usr/bin/mailx -s 'URGENT: POSSIBLE SSH-AGENT SYMLINK ATTACK' " MAIL_RECIPIENT
    +
    +/*
    + *  Mail a complaint to the sysadmin.
    + */
    +void mail_report(char *dirname, char *linkname, struct stat *st)
    +{
    +   FILE *mail_pipe;
    +   struct passwd *pw;
    +   struct group  *gr;
    +   char usrname[17];
    +   char grpname[17];
    +   char target[PATH_MAX];
    +   char filename[PATH_MAX];
    +   int  count;
    +
    +   if ((mail_pipe = popen(MAIL_COMMAND, "w")) == NULL)
    +   {
    +      snprintf(target, sizeof(target) - 1, "can't open pipe to %s\n",
    +               MAIL_COMMAND);
    +      log_msg(target);
    +      exit(1);
    +   }
    +
    +   /* reconstruct the full path to the file */
    +   if (dirname[strlen(dirname)] == '/') dirname[strlen(dirname)] = 0;
    +   snprintf(filename, sizeof(filename) - 1, "%s/%s", dirname, linkname);
    +
    +   /* Figure out who owns the file. */
    +   pw = getpwuid(st->st_uid);
    +   if (!pw) {
    +      snprintf(usrname, sizeof(usrname) - 1, "%d", st->st_uid);
    +   } else {
    +      snprintf(usrname, sizeof(usrname) - 1, "%s", pw->pw_name);
    +   }
    +
    +   gr = getgrgid(st->st_gid);
    +   if (!gr) {
    +      snprintf(grpname, sizeof(grpname) - 1, "%d", st->st_gid);
    +   } else {
    +      snprintf(grpname, sizeof(grpname) - 1, "%s", gr->gr_name);
    +   }
    +
    +   /*
    +    * Get the link's target. NOTE: The target may not necessarily
    +    * already exist, so we don't bother getting stats on it, but we
    +    * do want to know its path.
    +    */
    +   count = readlink(filename, target, sizeof(target) - 1);
    +   if (count < 0) {
    +      snprintf(target, sizeof(target) - 1, "unreadable!");
    +   } else {
    +      target[count] = '\0';
    +   }
    +
    +   (void) fprintf(mail_pipe, "File: %s exists as a symbolic link\n", filename);
    +   (void) fprintf(mail_pipe, "Owner: %s.%s\n", usrname, grpname);
    +   (void) fprintf(mail_pipe, "Target: %s\n", target);
    +   (void) fprintf(mail_pipe, "Mode: %o\n", 07777 & st->st_mode);
    +   (void)  fflush(mail_pipe);
    +
    +   (void) pclose(mail_pipe);
    +}
    +
    +/* Data structure for channel data.  This is initialized in channel_allocate
        and cleared in channel_free. */
    
     typedef struct
    @@ -2395,6 +2470,33 @@
           return 0;
         }
    
    +  /*
    +   * 1999/09/28 Sylvain Robitaille: Check that there isn't already a
    +   *            file by the same name. If there is, and it's a symbolic
    +   *            link, we probably have a DoS attempt. Else, if the file
    +   *            exists and is not already a socket, complain and fail.
    +   *
    +   *            File exists but is a socket is acceptable, since that
    +   *            socket might be a remnant (did the machine crash while
    +   *            that socket was still open?)
    +   */
    +  ret = lstat(channel_forwarded_auth_socket_name, &st);
    +  if (!ret && S_ISLNK(st.st_mode)) {
    +    packet_send_debug("* Remote error: Agent socket creation failed: File exists as a symbolic link.");
    +    packet_send_debug("* Remote error: Authentication fowarding disabled.");
    +    log_msg("Agent socket creation failed: File %s is a symbolic link.",
    +            channel_forwarded_auth_socket_name);
    +    mail_report(channel_forwarded_auth_socket_dir_name,
    +                channel_forwarded_auth_socket_name, &st);
    +    return 0;
    +  } else if (!ret && !S_ISSOCK(st.st_mode)) {
    +    packet_send_debug("* Remote error: Agent socket creation failed: File exists and is not a socket.");
    +    packet_send_debug("* Remote error: Authentication fowarding disabled.");
    +    log_msg("Agent socket creation failed: File %s is not a socket.",
    +            channel_forwarded_auth_socket_name);
    +    return 0;
    +  }
    +
       /* Create the socket. */
       sock = socket(AF_UNIX, SOCK_STREAM, 0);
       if (sock < 0)
    



    This archive was generated by hypermail 2b30 : Fri Apr 13 2001 - 15:05:57 PDT