Date: Thu, 8 Feb 2001 18:02:33 -0500
From: BindView Security Advisory
advisory+ssh1crc@BOS.BINDVIEW.COM
To: BUGTRAQ@SECURITYFOCUS.COM
Subject: BindView advisory: sshd remote root (bug in
deattack.c)
Remote vulnerability in SSH daemon crc32 compensation attack
detector
Issue date: 8 February 2001
Author: Michal Zalewski <lcamtuf@razor.bindview.com>
Contact: Scott Blake <blake@razor.bindview.com>
CVE: CAN-2001-0144
Topic:
Remotely exploitable vulnerability condition exists in most ssh
daemon installations (F-SECURE, OpenSSH, SSH from ssh.com,
OSSH).
Tested against:
** Vulnerable:
SSH 1.2.x (ssh.com) — all recent releases
F-SECURE SSH 1.3.x — all recent releases
OpenSSH prior to 2.3.0 (unless SSH protocol 1 support is
disabled)
OSSH 1.5.7 (by Bjoern Groenvall) and other ssh1/OpenSSH derived
daemons
** Not vulnerable:
SSH2 (ssh.com): all 2.x releases NOTE: SSH2 installations with
SSH1 fallback support are vulnerable
OpenSSH 2.3.0 (problem fixed)
SSH1 releases prior to 1.2.24 (vulnerable to crc attacks)
Cisco SSH (own implementation)
LSH (SSH protocol 1 not supported)
** Other SSH daemons: not tested
Overview:
An integer-overflow problem is present in common code of recent
ssh daemons, deattack.c, which was developed by CORE SDI to protect
against cryptographic attacks on SSH protocol.
Impact:
Insufficient range control calculations (16-bit unsigned
variable is used instead of 32-bit, which causes integer overflow)
in the detect_attack() function leads to table index overflow
bug.
This effectively allows an attacker to overwrite arbitrary
portions of memory. The altered memory locations affect code that
is executed by the daemon with uid 0, and this can be leveraged to
obtain general root access to the system.
Details:
When the condition described above occurs, a 32-bit local
variable, which is set to 65536 for large input buffers, is
assigned to a 16-bit local variable, effectively causing it to be
set to 0. Due to specific malloc(0) behavior, memory allocation
routine will be passed, creating buffer of size
(malloc_usable_size) 12. Next:
for (i = HASH(c) & (n – 1); h[i] != HASH_UNUSED;
We can see n-1 here, and n is equal to 0. Because i is an
unsigned 32-bit integer, it would cause integer overflow. This code
will be equal to i = HASH(c) & 0xffffffff. Binary AND operator
reduces this to i = HASH(c). Pointer ‘c’ is referencing
client-provided cryptographic packet, and HASH function is simply
responsible for changing byte order in input stream.
Then, detect_attack() routine is trying to access h[i], causing
segmentation fault due to table index overflow bug.
To reproduce this condition, run your sshd server on localhost
under gdb with ‘-d’ switch (to avoid forking). Then try (using
OpenSSH client – ssh.com client software crops the login name):
$ ssh -v -l `perl -e ‘{print “A”x88000}’` localhost
Program received signal SIGSEGV, Segmentation fault. 0x806cfbd in detect_attack ( ..., len=88016, IV=0x0) at deattack.c:138 136 for (i = HASH(c) & (n - 1); h[i] != HASH_UNUSED; We can inspect the table index (SEGV happened during h[i] != HASH_UNSIGNED comparsion): (gdb) printf "%xn",i
Results may vary with every connection, depending on the entropy
seed used by the client, crypto keys, etc. You can easily produce a
wide 32-bit range of indexes by changing client parameters or
simply reconnecting. It is obvious there wouldn’t be a problem to
specify very large index that would point outside our table, but
will cause address space wrap to point accessible memory (stack or
another segment). Then, few lines below, in the same loop, we can
find following statement:
h[i] = j;
…where j is a simple block counter.
Conclusion:
By carefully preparing encrypted data, an attacker can point
used, accessible memory (that would pass check in line 136 without
SEGV), and then, he will able to alter dword at chosen address,
replacing it with value of j. The attacker can alter stack
variables, alter malloc structures, etc, and attack later due to
improper execution of daemon code. This condition is relatively
difficult to exploit, but there are no technical reasons that would
make this impossible.
Currently, we are not aware of working exploits for this
vulnerability.
Note that the attacker needs to make a TCP connection from an IP
address for which sshd will enter into a key-exchange dialogue. If
the attacker’s packets have a source IP address that is disallowed
by (for example) DenyHosts in the sshd configuration file, the key
exchange will not happen and the attacker will not have an
opportunity to compose the required exploit data.
Solution:
Included are a few patches for various versions/implementations
of SSH. This is not meant to be an all-inclusive list, as there are
a number of implementers of SSH daemons that are not open source.
If you *do* have the source code for SSH, it should be fairly
simply to study the patches below, see what has been done, and
patch your own code. Note that this is a fix for the one issue that
we’ve found, and should not be construed as the results of a
complete audit of the code.
SSH1 software:
--- deattack.c.orig Wed Feb 7 13:53:47 2001 +++ deattack.c Wed Feb 7 13:54:24 2001 @@ -79,7 +79,7 @@ detect_attack(unsigned char *buf, word32 len, unsigned char *IV) { static word16 *h = (word16 *) NULL; - static word16 n = HASH_MINSIZE / HASH_ENTRYSIZE; + static word32 n = HASH_MINSIZE / HASH_ENTRYSIZE; register word32 i, j; word32 l; register unsigned char *c;
Bjoern Groenvall's ossh (ftp://ftp.pdc.kth.se/pub/krypto/ossh/):
--- deattack.c.orig Wed Feb 7 14:11:23 2001 +++ deattack.c Wed Feb 7 14:11:46 2001 @@ -91,7 +91,7 @@ detect_attack(const unsigned char *buf, word32 len) { static u_int16_t *h = (u_int16_t *) NULL; - static u_int16_t n = HASH_MINSIZE / HASH_ENTRYSIZE; + static u_int32_t n = HASH_MINSIZE / HASH_ENTRYSIZE; register word32 i, j; word32 l; const unsigned char *c, *d;
OpenSSH: Upgrade to 2.3.0 or above. If you have 2.2.0:
--- deattack.c.orig Wed Feb 7 14:18:23 2001 +++ deattack.c Wed Feb 7 14:19:33 2001 @@ -84,7 +84,7 @@ detect_attack(unsigned char *buf, u_int32_t len, unsigned char *IV) { static u_int16_t *h = (u_int16_t *) NULL; - static u_int16_t n = HASH_MINSIZE / HASH_ENTRYSIZE; + static u_int32_t n = HASH_MINSIZE / HASH_ENTRYSIZE; register u_int32_t i, j; u_int32_t l; register unsigned char *c;
Vendor Response:
CORE SDI has issued their own advisory detailing fix information
and has also pointed out that SSH1 clients are also vulnerable.
Bjorn Gronvall – OSSH
Fixed in version ossh-1.5.8
AppGate
The default configuration of the AppGate server is not vulnerable
since it has SSH-1 support disabled. However customers who need
ssh1-support can contact support@appgate.com to get patches.
Mindbright
The MindTerm client does not have this vulnerability.
SSH
Current release 2.4.0 is not vulnerable. Previous versions of SSH1
are not supported but a fix has been commited to the source tree.
SSH recommends customers upgrade to SSH2.
F-Secure
Unfortunately, after many attempts to contact F-Secure via email
and telephone no response has been received.
Thanks:
Special thanks to Mark Loveless for his significant
contributions to the Fix section. Thanks to RAZOR team members Todd
Sabin, Scott Blake, and Steve Manzuik for their assistance with
this issue. Thanks also to Ivan Arce of CORE SDI for his patience
with us.