From 8723db212b448269de3734dd4055242155f0129b Mon Sep 17 00:00:00 2001 From: "Simon L. B. Nielsen" Date: Sat, 30 Sep 2006 19:58:07 +0000 Subject: Correct multiple vulnerabilities in OpenSSH. Security: FreeBSD-SA-06:22.openssh Approved by: so (simon) --- UPDATING | 3 +++ crypto/openssh/auth.h | 1 + crypto/openssh/deattack.c | 24 ++++++++++++++++++++++-- crypto/openssh/deattack.h | 1 + crypto/openssh/defines.h | 5 +++++ crypto/openssh/log.c | 14 ++++++++++++++ crypto/openssh/log.h | 1 + crypto/openssh/packet.c | 13 ++++++++++--- crypto/openssh/session.c | 2 +- crypto/openssh/ssh_config | 2 +- crypto/openssh/ssh_config.5 | 2 +- crypto/openssh/sshd.c | 4 +++- crypto/openssh/sshd_config | 2 +- crypto/openssh/sshd_config.5 | 2 +- crypto/openssh/version.h | 2 +- sys/conf/newvers.sh | 2 +- 16 files changed, 67 insertions(+), 13 deletions(-) diff --git a/UPDATING b/UPDATING index 9fdb427036bb..128f241f5045 100644 --- a/UPDATING +++ b/UPDATING @@ -8,6 +8,9 @@ Items affecting the ports and packages system can be found in /usr/ports/UPDATING. Please read that file before running portupgrade. Important recent entries: 20040724 (default X changes). +20060930: p37 FreeBSD-SA-06:22.openssh + Correct multiple vulnerabilities in sshd(8). + 20060929: p36 FreeBSD-SA-06:23.openssl Correct problem in the 2006-09-28 patch concerning the handling of excessively large DH moduli. diff --git a/crypto/openssh/auth.h b/crypto/openssh/auth.h index 83841b6591aa..1edc516ac518 100644 --- a/crypto/openssh/auth.h +++ b/crypto/openssh/auth.h @@ -49,6 +49,7 @@ typedef struct KbdintDevice KbdintDevice; struct Authctxt { int success; + int authenticated; /* authenticated and alarms cancelled */ int postponed; /* authentication needs another step */ int valid; /* user exists and is allowed to login */ int attempt; diff --git a/crypto/openssh/deattack.c b/crypto/openssh/deattack.c index 8b55d668681a..1ed12a01ab70 100644 --- a/crypto/openssh/deattack.c +++ b/crypto/openssh/deattack.c @@ -27,6 +27,24 @@ RCSID("$OpenBSD: deattack.c,v 1.19 2003/09/18 08:49:45 markus Exp $"); #include "xmalloc.h" #include "deattack.h" +/* + * CRC attack detection has a worst-case behaviour that is O(N^3) over + * the number of identical blocks in a packet. This behaviour can be + * exploited to create a limited denial of service attack. + * + * However, because we are dealing with encrypted data, identical + * blocks should only occur every 2^35 maximally-sized packets or so. + * Consequently, we can detect this DoS by looking for identical blocks + * in a packet. + * + * The parameter below determines how many identical blocks we will + * accept in a single packet, trading off between attack detection and + * likelihood of terminating a legitimate connection. A value of 32 + * corresponds to an average of 2^40 messages before an attack is + * misdetected + */ +#define MAX_IDENTICAL 32 + /* SSH Constants */ #define SSH_MAXBLOCKS (32 * 1024) #define SSH_BLOCKSIZE (8) @@ -87,7 +105,7 @@ detect_attack(u_char *buf, u_int32_t len, u_char *IV) static u_int16_t *h = (u_int16_t *) NULL; static u_int32_t n = HASH_MINSIZE / HASH_ENTRYSIZE; u_int32_t i, j; - u_int32_t l; + u_int32_t l, same; u_char *c; u_char *d; @@ -133,7 +151,7 @@ detect_attack(u_char *buf, u_int32_t len, u_char *IV) if (IV) h[HASH(IV) & (n - 1)] = HASH_IV; - for (c = buf, j = 0; c < (buf + len); c += SSH_BLOCKSIZE, j++) { + for (c = buf, same = j = 0; c < (buf + len); c += SSH_BLOCKSIZE, j++) { for (i = HASH(c) & (n - 1); h[i] != HASH_UNUSED; i = (i + 1) & (n - 1)) { if (h[i] == HASH_IV) { @@ -144,6 +162,8 @@ detect_attack(u_char *buf, u_int32_t len, u_char *IV) break; } } else if (!CMP(c, buf + h[i] * SSH_BLOCKSIZE)) { + if (++same > MAX_IDENTICAL) + return (DEATTACK_DOS_DETECTED); if (check_crc(c, buf, len, IV)) return (DEATTACK_DETECTED); else diff --git a/crypto/openssh/deattack.h b/crypto/openssh/deattack.h index ddccdea50594..cd3d7aa3b5a7 100644 --- a/crypto/openssh/deattack.h +++ b/crypto/openssh/deattack.h @@ -25,6 +25,7 @@ /* Return codes */ #define DEATTACK_OK 0 #define DEATTACK_DETECTED 1 +#define DEATTACK_DOS_DETECTED 2 int detect_attack(u_char *, u_int32_t, u_char[8]); #endif diff --git a/crypto/openssh/defines.h b/crypto/openssh/defines.h index 9b72afecb43c..01b55d580285 100644 --- a/crypto/openssh/defines.h +++ b/crypto/openssh/defines.h @@ -511,6 +511,11 @@ struct winsize { # undef HAVE_UPDWTMPX #endif +#if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT) && \ + defined(SYSLOG_R_SAFE_IN_SIGHAND) +# define DO_LOG_SAFE_IN_SIGHAND +#endif + #if !defined(HAVE_MEMMOVE) && defined(HAVE_BCOPY) # define memmove(s1, s2, n) bcopy((s2), (s1), (n)) #endif /* !defined(HAVE_MEMMOVE) && defined(HAVE_BCOPY) */ diff --git a/crypto/openssh/log.c b/crypto/openssh/log.c index 0c4d5123a63b..36d2f54437a0 100644 --- a/crypto/openssh/log.c +++ b/crypto/openssh/log.c @@ -127,6 +127,20 @@ error(const char *fmt,...) va_end(args); } +void +sigdie(const char *fmt,...) +{ + va_list args; + +#ifdef DO_LOG_SAFE_IN_SIGHAND + va_start(args, fmt); + do_log(SYSLOG_LEVEL_FATAL, fmt, args); + va_end(args); +#endif + _exit(1); +} + + /* Log this message (information that usually should go to the log). */ void diff --git a/crypto/openssh/log.h b/crypto/openssh/log.h index ca4d7bf6da97..73ca3c25200f 100644 --- a/crypto/openssh/log.h +++ b/crypto/openssh/log.h @@ -64,6 +64,7 @@ LogLevel log_level_number(char *); void fatal(const char *, ...) __attribute__((format(printf, 1, 2))); void error(const char *, ...) __attribute__((format(printf, 1, 2))); +void sigdie(const char *, ...) __attribute__((format(printf, 1, 2))); void logit(const char *, ...) __attribute__((format(printf, 1, 2))); void verbose(const char *, ...) __attribute__((format(printf, 1, 2))); void debug(const char *, ...) __attribute__((format(printf, 1, 2))); diff --git a/crypto/openssh/packet.c b/crypto/openssh/packet.c index daae9ffaaa2a..bd1bceccccdd 100644 --- a/crypto/openssh/packet.c +++ b/crypto/openssh/packet.c @@ -940,9 +940,16 @@ packet_read_poll1(void) * (C)1998 CORE-SDI, Buenos Aires Argentina * Ariel Futoransky(futo@core-sdi.com) */ - if (!receive_context.plaintext && - detect_attack(buffer_ptr(&input), padded_len, NULL) == DEATTACK_DETECTED) - packet_disconnect("crc32 compensation attack: network attack detected"); + if (!receive_context.plaintext) { + switch (detect_attack(buffer_ptr(&input), padded_len, NULL)) { + case DEATTACK_DETECTED: + packet_disconnect("crc32 compensation attack: " + "network attack detected"); + case DEATTACK_DOS_DETECTED: + packet_disconnect("deattack denial of " + "service detected"); + } + } /* Decrypt data to incoming_packet. */ buffer_clear(&incoming_packet); diff --git a/crypto/openssh/session.c b/crypto/openssh/session.c index 3f9049f3593e..bcf5b6df4e97 100644 --- a/crypto/openssh/session.c +++ b/crypto/openssh/session.c @@ -2266,7 +2266,7 @@ do_cleanup(Authctxt *authctxt) return; called = 1; - if (authctxt == NULL) + if (authctxt == NULL || !authctxt->authenticated) return; #ifdef KRB5 if (options.kerberos_ticket_cleanup && diff --git a/crypto/openssh/ssh_config b/crypto/openssh/ssh_config index 2ca4469fec6d..0ca3060ba233 100644 --- a/crypto/openssh/ssh_config +++ b/crypto/openssh/ssh_config @@ -36,4 +36,4 @@ # Cipher 3des # Ciphers aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,arcfour,aes192-cbc,aes256-cbc # EscapeChar ~ -# VersionAddendum FreeBSD-20060123 +# VersionAddendum FreeBSD-20060930 diff --git a/crypto/openssh/ssh_config.5 b/crypto/openssh/ssh_config.5 index e74530b42422..3e89c9c04006 100644 --- a/crypto/openssh/ssh_config.5 +++ b/crypto/openssh/ssh_config.5 @@ -719,7 +719,7 @@ Note that this option applies to protocol version 2 only. Specifies a string to append to the regular version string to identify OS- or site-specific modifications. The default is -.Dq FreeBSD-20060123 . +.Dq FreeBSD-20060930 . .It Cm XAuthLocation Specifies the full pathname of the .Xr xauth 1 diff --git a/crypto/openssh/sshd.c b/crypto/openssh/sshd.c index 22c2e3d0a535..54a374a7dad0 100644 --- a/crypto/openssh/sshd.c +++ b/crypto/openssh/sshd.c @@ -314,7 +314,7 @@ grace_alarm_handler(int sig) kill(pmonitor->m_pid, SIGALRM); /* Log error and exit. */ - fatal("Timeout before authentication for %s", get_remote_ipaddr()); + sigdie("Timeout before authentication for %s", get_remote_ipaddr()); } /* @@ -1509,6 +1509,8 @@ main(int ac, char **av) } authenticated: + authctxt->authenticated = 1; + /* * In privilege separation, we fork another child and prepare * file descriptor passing. diff --git a/crypto/openssh/sshd_config b/crypto/openssh/sshd_config index 77816ba38051..d701370a97a2 100644 --- a/crypto/openssh/sshd_config +++ b/crypto/openssh/sshd_config @@ -14,7 +14,7 @@ # Note that some of FreeBSD's defaults differ from OpenBSD's, and # FreeBSD has a few additional options. -#VersionAddendum FreeBSD-20060123 +#VersionAddendum FreeBSD-20060930 #Port 22 #Protocol 2 diff --git a/crypto/openssh/sshd_config.5 b/crypto/openssh/sshd_config.5 index d13c72935228..fff5d4121b9b 100644 --- a/crypto/openssh/sshd_config.5 +++ b/crypto/openssh/sshd_config.5 @@ -660,7 +660,7 @@ The default is Specifies a string to append to the regular version string to identify OS- or site-specific modifications. The default is -.Dq FreeBSD-20060123 . +.Dq FreeBSD-20060930 . .It Cm X11DisplayOffset Specifies the first display number available for .Nm sshd Ns 's diff --git a/crypto/openssh/version.h b/crypto/openssh/version.h index cac15808b53d..372cc49a8a45 100644 --- a/crypto/openssh/version.h +++ b/crypto/openssh/version.h @@ -5,7 +5,7 @@ #define SSH_VERSION (ssh_version_get()) #define SSH_VERSION_BASE "OpenSSH_3.8.1p1" -#define SSH_VERSION_ADDENDUM "FreeBSD-20060123" +#define SSH_VERSION_ADDENDUM "FreeBSD-20060930" const char *ssh_version_get(void); void ssh_version_set_addendum(const char *add); diff --git a/sys/conf/newvers.sh b/sys/conf/newvers.sh index 01c8caed7f29..6b6581943d1b 100644 --- a/sys/conf/newvers.sh +++ b/sys/conf/newvers.sh @@ -32,7 +32,7 @@ TYPE="FreeBSD" REVISION="5.3" -BRANCH="RELEASE-p36" +BRANCH="RELEASE-p37" RELEASE="${REVISION}-${BRANCH}" VERSION="${TYPE} ${RELEASE}" -- cgit v1.2.3