SSH: reutilizando claves públicas y hombre conocido en el medio

6

Generalmente, las personas recomiendan usar un solo par de claves público-privadas en todas partes (si no estamos hablando de una posibilidad de comprometer la clave privada):

  1. Práctica recomendada:" Una clave ssh por usuario "o" varias claves ssh por host "
  2. Reutilización de claves públicas / privadas
  3. enlace

    Parece que esto resultaría en una vulnerabilidad al usar la autenticación de certificado de cliente a través de SSH. Ya que es muy popular sugerirlo, sospecho que el "algoritmo" a continuación no funcionará. Pero simplemente no entiendo qué es exactamente lo que está mal.

He intentado hacer mi descripción lo más detallada posible, para minimizar posibles discrepancias, así que, discúlpeme por la extensión ...

Condiciones previas

  • PC1 tiene ambas huellas digitales ( S1_id_rsa.pub y S2_id_rsa.pub ) en sus hosts conocidos.
  • Server1 de alguna manera sabe acerca de la existencia de la cuenta de PC1 en Server2 .
  • teclas:
    • PC1 : tiene P1_id_rsa , S1_id_rsa.pub , S2_id_rsa.pub .
    • Servidor1 , el atacante: tiene S1_id_rsa , P1_id_rsa.pub , S2_id_rsa.pub .
    • Servidor2 : tiene S2_id_rsa , P1_id_rsa.pub

Algoritmo

Esto es algo así como un conocido ataque Man-in-the-middle , pero un poco diferente.

  1. PC1 envía "Hola" a Servidor1
  2. Servidor1 envía "Hola" a Servidor2
  3. El servidor comparte su clave pública

    1. Servidor2 envía Servidor1 S2_id_rsa.pub
    2. Server1 envía PC1 S1_id_rsa.pub (en lugar de S2_id_rsa.pub )
    3. PC1 acepta la huella digital de S1_id_rsa.pub (como se la conoce)
  4. Se generan dos túneles separados de secreto compartido usando Diffie-Hellman :

    1. "Servidor1 - Servidor2"

      1. Server2 genera DH1.a, y envía DH1.A, firmado con S2_id_rsa , a Server1
      2. Server1 genera DH1.b y envía DH1.B a Server2
      3. Túnel establecido
    2. "PC1 - Servidor1"
      1. Server1 genera DH2.a y envía DH1.A, firmado con S1_id_rsa , a PC1
      2. PC1 genera DH2.b y envía DH2.B a Servidor1
      3. El túnel está establecido.
  5. Autenticación del cliente ( Servidor2 ahora quiere estar seguro de que está hablando con PC1 )

    1. PC1 envía P1_id_rsa.pub a Servidor1
    2. Servidor1 envía P1_id_rsa.pub a Servidor2
    3. Server2 genera un desafío, que solo se puede resolver con P1_id_rsa y lo envía a Server1
    4. Servidor1 solo desafía los túneles a PC1
    5. PC1 resuelve el desafío y envía la respuesta a Servidor1
    6. Los túneles Servidor1 responden a Servidor2
    7. Hecho.
  6. Hecho

P.S. He consultado criptografía de clave pública y man-in-the-middle attack en Wikipedia, y esta respuesta bastante detallada (mi punto de vista de todo el proceso se basa en gran parte en ello), pero no he encontrado la respuesta ...

No pude encontrar un "proceso completo de autenticación y cifrado ssh para dummies" ...

Ya hice la misma pregunta en Server Fault, pero se sugirió para volver a publicarlo aquí.

    
pregunta Igor 21.01.2013 - 17:16
fuente

4 respuestas

3

Finalmente, creo que lo tengo.

En primer lugar, en mi descripción he mezclado los protocolos ssh v1 y ssh v2. La autorización de desafío-respuesta es de ssh v1.

En el cliente ssh v2 simplemente firma un paquete específico con su clave privada y el servidor lo comprueba usando una clave pública almacenada. Este paquete se describe en rfc, aquí :

To perform actual authentication, the client MAY then send a
signature generated using the private key.  The client MAY send the
signature directly without first verifying whether the key is
acceptable.  The signature is sent using the following packet:

  byte      SSH_MSG_USERAUTH_REQUEST
  string    user name
  string    service name
  string    "publickey"
  boolean   TRUE
  string    public key algorithm name
  string    public key to be used for authentication
  string    signature

The value of 'signature' is a signature by the corresponding private
key over the following data, in the following order:

  string    session identifier
  byte      SSH_MSG_USERAUTH_REQUEST
  string    user name
  string    service name
  string    "publickey"
  boolean   TRUE
  string    public key algorithm name
  string    public key to be used for authentication

Por lo tanto, el paquete firmado contiene el "identificador de sesión" que se calcula de la siguiente manera :

  H = hash(V_C || V_S || I_C || I_S || K_S || e || f || K)
  <…..>
  mpint     K, the shared secret  

Es decir, la firma depende del secreto compartido, y los secretos compartidos son diferentes para P1 < - > S1 y S1 & lt ; - > S2 túneles.

    
respondido por el Igor 11.02.2013 - 14:44
fuente
3
  

Generalmente, las personas recomiendan usar un solo par de claves público-privadas en todas partes (si no estamos hablando de una posibilidad de comprometer la clave privada)

Tenga en cuenta que hay dos pares de claves involucrados en una conexión SSH:

  • uno para identificar el servidor host (el servidor tiene la clave privada);
  • uno para identificar al usuario (el cliente tiene la clave privada), si usa una autenticación de clave pública.

Las recomendaciones que cita son sobre las claves de usuario. Tener una única clave privada por usuario es un modelo viable, aunque no lo recomiendo particularmente (el costo de tener pares de claves separados por host o sitio no es tan alto). Las claves del servidor, por otro lado, nunca se duplican. Se generan de nuevo cuando se instala el servidor SSH.

Sobre este tema, más allá de las publicaciones que ha citado en su pregunta, consulte también ¿Cuál es la diferencia entre authorized_keys y known_hosts para SSH?

En el ataque que describe, ha mezclado los roles de las teclas. Estas son las claves de host, ssh_host_rsa , y no las claves de usuario. Esto no es directamente relevante en cómo funciona el ataque que describe, pero puede ser parte de su confusión.

El punto fijo está en el paso 3.3:

  

PC1 acepta la huella digital de S1_id_rsa.pub (como se la conoce)

Hay dos casos.

  • Si la PC1 se conectó a S2 anteriormente, entonces la PC1 (o más precisamente la cuenta del usuario en la PC1) ha memorizado la clave pública del host de S2 en su archivo known_hosts . Por lo tanto, si S1 envía la clave de host de S2, el cliente SSH en PC1 detectará que la supuesta clave de host no coincide con la clave de host registrada y abortará la conexión con un mensaje aterrador:

    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    @    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
    Someone could be eavesdropping on you right now (man-in-the-middle attack)!
    It is also possible that the RSA host key has just been changed.
    

    Por lo tanto, el ataque es imposible en este escenario (a menos que el usuario salga de su camino para evitar la comprobación, OpenSSH lo hace difícil a propósito).

  • Si la PC1 nunca se ha conectado a S2, entonces la PC1 aceptará con gusto cualquier cosa que S1 diga ahora que es la clave de S2. Dado que PC1 no tiene conocimiento previo de ninguna asociación entre el nombre S2 y una identidad criptográfica, ni ninguna forma de contactar a un tercero de confianza que conozca dicha asociación (es decir, una infraestructura de clave pública), no hay manera de evitar que esto ocurra. ataque en el medio.

respondido por el Gilles 21.01.2013 - 18:23
fuente
1

El problema es que el cliente sabría que está hablando con el servidor 1 debido al uso del certificado del servidor 1. Si server1 tiene un certificado válido que indica que son server2, entonces el cliente no sabría si no se había conectado a server2 anteriormente. Sin embargo, la mayoría de los clientes SSH rastrean la huella digital del certificado al que se conectan para un servidor determinado. Cuando el cliente se conecta y termina con una conexión al servidor 1, incluso si el certificado está firmado, es probable que el usuario reciba una advertencia de que la huella digital ha cambiado.

En cuanto a una conexión conocida con S1 que intenta ser s2, si s2 conoce con precisión la clave privada de p1, s si 01 quiere hablar con s2 a s1, entonces debe cifrar para s2 y s2 luego se cifrará para p1 . Cuando p1 no obtiene un intercambio de claves desde s2, sabrá que hay un problema ya que s1 no puede firmar un intercambio con p1 como s2.

    
respondido por el AJ Henderson 21.01.2013 - 18:14
fuente
0

En realidad, se trata de una vulnerabilidad conocida con certificados resquebrajados en la lista de confianza y por qué son necesarias las listas de revocación.

Para que este ataque funcione, debe haber 2 agujeros:

  1. PC1 debe pensar que se está comunicando con server2 mientras que en realidad se está comunicando con server1.
  2. PC1 debe tener S1_id_rsa.pub como certificado de confianza y apunta a la dirección del servidor2 (de otra manera, PC1 sabrá que está hablando con server1 en lugar de server2 en el paso # 4.3).

El # 1 puede suceder en una red que no es de confianza, mientras que el # 2 solo puede suceder cuando ha ocurrido una violación anterior que permitió al servidor1 insertarse como parte confiable.

    
respondido por el ratchet freak 21.01.2013 - 17:48
fuente

Lea otras preguntas en las etiquetas