|
|
Este documento está disponible en los siguientes idiomas: English Castellano Deutsch Francais Nederlands Turkce |
por Bernard Perrot <bernard.perrot(at)univ-rennes1.fr> Sobre el autor: Bernard ha sido el Ingeniero de red y sistemas del CNRS (Centro Nacional de Investigaciones Científicas de Francia) desde 1982. Ha estado a cargo de los proyectos relativos a la seguridad del sistema informático en el "Instituto nacional de física nuclear y física de las partículas" (In2p3). Ahora, trabaja para el Instituto de investigación matemática (IRMAR) en el Departamento de ciencias físicas y matemáticas (SPM). Taducido al español por: Javier Gómez Sierras <jgomsi(at)obelix.umh.es> Contenidos:
|
Asegurando tus conexiones con SSHResumen:
Este artículo se publicó por primera vez en un número especial de Linux Magazine France enfocado a la seguridad. El editor, los autores y los traductores permitieron amablemente a LinuxFocus publicar todos los artículos de este número especial. En consecuencia, LinuxFocus los publicará tan pronto como estén traducidos al inglés. Gracias a todas las personas implicadas en este trabajo. Este resumen se mostrará en todos los artículos que procedan de la misma fuente. El propósito de este artículo es realizar un buen repaso de SSH, y por qué se usa. Esto no es un manual o guía de instalación, sino una introducción al vocabulario y las características de SSH. Los enlaces y la documentación que aparecen durante todo el artículo, te darán todos los detalles de la implementación. |
Primero de todo (e históricamente), SSH (el comando ssh) es una versión segura de los comandos rsh (y rlogin). SSH significa "Secure SHell -- shell segura" y rsh significa "Remote SHell -- shell remota". Por lo tanto, mientras que rsh te da un acceso a una shell remota fácilmente, pero sin un mecanismo de autentificación de usuario, ssh proporciona el mismo servicio pero con una seguridad multinivel muy alta.
Si quisiéramos dar una explicación muy breve a un usuario que no quiere saber nada más (o hacer nada más), uno se podría para aquí y decir el administrador ha hecho su trabajo y ha instalado el software (esto es bastante fácil hoy en día), todo lo que tienes que hacer es reemplazar los comandos telnet, rsh o rlogin por el comando ssh, y todo funcionará igual pero con más seguridad.
Por lo tanto, donde hacías:
% rlogin servidor.org (o telnet servidor.org)
ahora tienes que hacer:
% ssh servidor.org
¡y es mucho mejor!
Para terminar este breve resumen, sugeriré que hoy en día, todos los incidentes de seguridad que podrían haber sido evitados simplemente usando SSH en vez de rsh (rlogin,telnet) son principalmente consecuencia de la negligencia de las víctimas.
Para ver los detalles, aquí tienes algunos de los aspectos más importantes y frágiles de las conexiones interactivas que uno quiere ver resueltos:
Para responder a estas necesidades, existen algunas soluciones que no son del todo satisfactorias:
Y tenemos SSH, una buena solución para:
Como nada en este mundo es perfecto, existen dos versiones incompatibles del protocolo SSH: la versión 1.x (1.3 y 1.5) y la versión 2.0. Pasar de una versión a la otra no es doloroso para el usuario, teniendo a mano el cliente correcto y el servidor correcto compatible con la versión.
La versión 1 del protocolo SSH está integrada, mientras que la versión 2 ha definido el protocolo anterior en tres "capas":
Cada capa del protocolo está definida específicamente en un documento (borrador) normalizado por la IETF, seguido de un cuarto borrador que describe la arquitectura (Arquitectura del protocolo SSH, SSH-ARCH). Se pueden encontrar todos los detalles en: http://www.ietf.org/html.charters/secsh-charter.html
Sin meternos en muchos detalles, aquí tienes lo que encontrarás en SSHv2:
Las principales diferencias técnicas entre la versión 1 de SSH y la versión 2 son:
SSH versión 1 |
SSH versión 2 |
---|---|
diseño monolítico (integrado) |
separación de las funciones de autentificación, conexión y transporte en capas |
integridad via CRC32 (no seguro) |
integridad via HMAC (cifrado hash) |
un único canal por sesión |
un número ilimitado de canales por sesión |
negociación usando únicamente cifrado simétrico en el canal, identificación de sesión con una única clave en ambos lados |
negociación más detallada (cifrado simétrico, llave pública, compresión, ...), y una clave de sesión independiente, compresión e integridad en ambos lados |
sólo RSA para el algoritmo de clave pública |
RSA y DSA para el algoritmo de clave pública |
clave de sesión transmitida por el cliente |
clave de sesión negociada por el protocolo Diffie-Hellman |
clave de sesión válida para toda la sesión |
clave de sesión renovable |
Tipos de claves SSH, las definiré rápidamente:
El usuario añade una frase de paso (pass phrase) que protege la parte privada de las anteriores claves. Esta protección se asegura cifrando el fichero que contiene la clave privada con un algoritmo simétrico. La clave secreta usada para cifrar el fichero se deriva de esta frase de paso.
Hay varios métodos de autentificación de usuario, la elección depende de la necesidades definidas en las políticas de seguridad. Los métodos autorizados se activan o no en el fichero de configuración del servidor. Aquí están las principales categorías:
Este es el "tradicional" método de la contraseña: al conectar, después de haber introducido nuestro identificador, se le pide al usuario que introduzca una contraseña que se envía al servidor que la compara con la que tiene asociada a dicho usuario. El problema residual (el que causa una cifra astronómica actos delictivos en Internet) es que la contraseña se envía a la red en claro, y por lo tanto puede ser interceptada por cualquiera que que tenga un simple "sniffer" (capturador de paquetes). En este caso SSH tiene la misma apariencia (es un modo fácil usuarios inexpertos que migran de telnet a SSH, ya que no hay nada nuevo que aprender ...), no obstante el protocolo SSH cifra el canal y la contraseña en claro se encapsula.
Una variante incluso más segura, configurable si uno tiene lo
necesario en el servidor es el uso de una "Contraseña de un solo
uso -- One time password" (S/Key por ejemplo):
seguramente es mejor, obviamente más seguro, pero las limitaciones
de ergonomía lo hacen aplicable únicamente a situaciones
particulares. Este sistema opera como sigue: después de introducir
nuestro identificador, en vez de preguntar al usuario una
contraseña (estática), el servidor envia un "desafío" al que
el usuario debe responder. Dado que el desafío debe ser diferente,
la respuesta debe también cambiar. En consecuencia, la interceptación
de la respuesta no es importante ya que no puede ser reusada. La
limitación, como se mencionó, viene esencialmente de la
codificación de la respuesta que debe ser calculada (por un
token, software en el lado cliente, etc.), y la entrada es
bastante "cabalística" (seis monosílabos ingleses, en el mejor de
los casos).
En este caso la identificación es similar a la de los R-commands con ficheros como /etc/rhosts o ~/.rhosts, que "certifican" los sitios clientes. SSH sólo contribuye a una mejor identificación del sitio, y al uso de de ficheros "shosts" privados. Esto no es suficientemente recomendable desde el punto de vista de la seguridad y no recomiendo usar este método si se utiliza sin más.
En este caso, el sistema de autentificación se basa en el cifrado asimétrico (para más detalles ver el artículo sobre criptografía; básicamente, SSHv1 usa RSA, y SSHv2 ha introducido DSA). La clave pública del usuario se registra de antemano en el servidor y la clave privada se guarda en el cliente. Con este sistema de autentificación, ningún secreto viaja a través de la red ni es enviado al servidor.
Este sistema es excelente, y sin embargo, su seguridad está limitada (desde mi punto de vista) por ser casi exclusivamente dependiente de la "seriedad" del usuario (este problema no es particular de SSH, sino que creo es el EL principal problema de los sistemas de clave pública, como los actualmente populares sistemas PKI): por lo tanto, para evitar un compromiso de la clave pública del ordenador cliente, la clave se protege con una contraseña (a menudo llamada palabra de paso -- pass phrase para enfatizar la necesidad de usar más de una palabra). Si el usuario no protege cuidadosamente (o simplemente NO protege) su clave privada, alguien puede usarla fácilmente para conseguir acceder a todos sus recursos. Es por esto por lo que digo que la seguridad recae en la seriedad del usuario y su nivel de confianza, ya que en este sistema el administrador del servidor no tiene ninguna manera de saber si la clave privada está protegida o no. Hoy en día, SSH no administra listas de revocación (no lo hacen muchos, ni siquiera PKI...). Por ejemplo, si una clave privada se guarda sin una frase de paso en el ordenador de casa (no hay ningún chico malo en casa, así que para qué preocuparse por una frase de paso...) y un día se lleva al servicio de reparación de un distribuidor importante ( no os riáis, esto es lo que va a pasar cuando las firmas electrónicas sean comunes...), el encargado de la reparación ( su hijo, sus amigos ) podrán conseguir las claves privadas de cualquier ordenador que pase por sus mesas.
Configurar el mecanismo de autentificación para el usuario es ligeramente diferente si uno usa SSHv1, SSHv2, o OpenSSH, también en el caso de un cliente MacOStm o Windowstm. Los principios básicos y los pasos a recordar son:
También, es útil saber al menos dos elementos más referentes a la autentificación:
Una de las razones por las que uno no protege su clave privada es lo molesto que resulta tener que introducir la clave en cada conexión interactiva y la imposibilidad de usar conexiones ssh en scripts que corran en segundo plano. Existe un remedio, el Agente SSH -- SSH agent. Es un programa (ssh-agent), que una vez activado por el usuario, te ayuda a almacenar el identificador de tres parámetros (nombre de usuario, nombre del servidor, frase de paso), y envia por ti el identificador cuando se realiza una conexión. En el lado cliente, la contraseña se pregunta una sola vez, así que lo podríamos llamar SSO (Single Sign On -- Registro único).
Ahora que estas informado, nada te obliga a proteger tus claves privadas, pero si no lo haces, será una negligencia por tu parte, y tú serás el responsable de las consecuencias.
Puede pasar que la conexión falle por motivos que el usuario desconoce: simplemente añade la opción "-v" (viene de "verbose", "prolijo, verboso") al comando ssh. Con esta opción, aparecerán numerosos mensajes detallados en la pantalla durante la conexión, lo que a menudo te dará suficiente información para determinar la causa del fallo.
Se debe distinguir entre los que cifran los canales de comunicación (cifrando con claves secretas) y los que se usan para la autentificación (cifrando con claves públicas).
Para la autenticación, podemos elegir entre RSA y DSA con la versión 2 del protocolo, y únicamente RSA con la versión 1 (no hay elección posible...). Históricamente se eligió DSA porque RSA estaba patentado en algunos países. Desde finales del verano del año 2000, RSA está libre de derechos, y por lo tanto esta restricción ha desaparecido. No tengo preferencia sobre si la elección buena y la mala (y más cuando DSA es un producto "puro" de la NSA, aunque halla sido esta quien lo ha puesto directa o indirectamente a disposición de la criptografía pública y comercial...¿?)
Para el cifrado simétrico existen casi demasiados donde elegir... El protocolo impone un algoritmo común que tiene que estar presente en todas las implementaciones : el triple-DES con tres claves. En consecuencia, siempre se usará si la negociación entre el cliente y el servidor falla con los otros algoritmos. Si puedes, prueba a negociar con otro algoritmo, que será mejor, ya que que 3DES es hoy en día uno de los algoritmos de menor rendimiento. No obstante dejaremos de lado, a menos que sea necesario, los exóticos o antiguos (arc4, DES, RC4, ...) y nos limitaremos a:
Personalmente, me pregunto a mi mismo sobre el interés que tiene proponer tanto algoritmos: incluso aunque el protocolo permite la posibilidad de negociar "uno privado" ( para un grupo particular de usuarios, por ejemplo), algo que me parece esencial, pero para el uso normal, creo que con el tiempo, AES está llamado a convertirse en el estándar. Si AES fuera comprometido, entonces los problemas de seguridad serían mucho mayores que los que pudiese inducir SSH...
SSH permite la redirección (forwarding) de cualquier flujo de datos TCP a través de un "túnel" en una sesión SSH. Esto significa que el flujo de datos de la aplicación, en vez de ser gestionada directamente por los puertos del servidor y el cliente, es "encapsulada" en un "túnel" creado al conectar (inicio de sesión) (ver el siguiente diagrama).
Esto mismo se hace con el protocolo X11 sin ningún esfuerzo especial (por parte del usuario), con un manejo transparente de los displays y la capacidad de propagarse continuamente cuando se realizan varias conexiones.
Para otros flujos, existe una opción de línea de comandos, para
cada lado:
(ejemplo: usuario@alice% telnet bob.org)
ejemplo: usuario@alice% ssh -L 1234:bob.org:143 bob.org
este sistema permite el acceso desde "alice.org" a
el servidor imap de "bob.org",
las conexiones externas a la red local serán rechazadas.
Únicamente estarán disponibles a través del la dirección
localhost, puerto 1234, desde el cliente imap ejecutado
en "alice.org".
ejemplo: root@alice% ssh -R 1234:bob.org:143 bob.org
Esto es lo mismo que antes pero el puerto en la máquina remota se redirecciona. Únicamente root tiene los privilegios necesarios para ejecutar este comando SSH pero cualquier usuario puede usar este puerto redirigido/túnel.
Esta potente característica ha llevado algunas veces a calificar a SSH como "un túnel para pobres". Se debe comprender que la pobreza aquí significa: aquellos que no tienen privilegios de administrador en el lado cliente. Sólo en casos particulares se puede redirigir un puerto local con menos privilegios ( puertos > 1024) y sin privilegios de superusuario ("root"). Por otro lado, cuando se necesita redirigir un puerto local con privilegios, se tiene que hacer con la cuenta de root, o el cliente debe tener privilegios de superusuarios ("suid") (De hecho, un puerto local privilegiado permite la redefinición de un servicio estándar).
Como con IP, es bastante fácil meter cualquier cosa en cualquier cosa (y lo contrario), no solo es posible redirigir un flujo TCP, sino también las conexiones PPP, lo que nos permite hacer un túnel IP "real" en IP (que está cifrado, por lo tanto seguro). El método excede el objetivo de este artículo, pero puedes leer el "Linux VPN-HOWTO" para conocer los detalles y obtener scripts de instalación (también podrás encontrar soluciones nativas VPN para Linux, como "stunnel" que deberías considerar antes de realizar la elección final).
Ten presente que la primera posibilidad es redirigir los flujos de telnet: Esto podría parecer totalmente inútil, ya que SSH implementa una conexión interactiva por defecto. Sin embargo, al redirigir las conexiones telnet, podrías usar tu cliente favorito en vez del modo SSH interactivo. Esto es realmente valioso en entornos Windowstm o MacOStm donde los clientes SSH puede que no se adecuen a la ergonomía preferida por el usuario. Por ejemplo, la "emulación de terminal" parte del cliente "Mindterm" (cliente SSH en Java, presente en todos los sistemas modernos) sufre la escasez de rendimiento del lenguaje Java: puede ser ventajoso usar este cliente únicamente para abrir un túnel SSH.
De la misma manera, también puedes iniciar un cliente remoto como "xterm" (por ejemplo, usando redirección X11 automática -- automatic X11 forwarding -- en SSH), lo que nos permite usar SSH en terminales X.
Ten en cuenta que el túnel permanece abierto mientras halla un flujo de datos, incluso aunque no venga del que lo inició. Por lo tanto, el comando "sleep" es muy útil para abrir un túnel SSH para redirigir una nueva conexión TCP.
% ssh -n -f -L 2323:serveur.org:23 serveur.org sleep 60
% telnet localhost 2323
... bienvenido a serveur.org ...
La primera línea abre el túnel, lanza el comando "sleep 60" en el servidor, y redirige el puerto local número 2323 al puerto remoto (telnet) número 23. El segundo inicia un cliente telnet en el puerto local número 2323, y entonces usará el túnel (cifrado) para conectarse al demonio telnetd del servidor. El comando "sleep" terminará después de un minuto (tienes sólo un minuto para iniciar telnet) , pero SSH sólo cerrará el túnel cuando el último cliente halla terminado.
Tenemos que distinguir entre los clientes y/o servidores en las diferentes plataformas y deberías saber que la SSH versión 1 y SSH versión 2 son incompatibles. Las referencias al final del artículo te ayudarán a encontrar otras implementaciones, que no se incluyen en la siguiente tabla que se limita a los productos gratuitos con características suficientemente estables.
producto |
plataforma |
protocolo |
enlace |
notas |
---|---|---|---|---|
OpenSSH |
Unix |
versiones 1 y 2 |
detalles debajo |
|
TTSSH |
Windowstm |
versión 1 |
||
Putty |
Windowstm |
versiones 1 y 2 |
sólo beta |
|
Tealnet |
Windowstm |
versiones 1 y 2 |
||
SSH secure shell |
Windowstm |
versiones 1 y 2 |
gratuito para uso no comercial |
|
NiftytelnetSSH |
MacOStm |
versión 1 |
||
MacSSH |
MacOStm |
versión 2 |
||
MindTerm |
Java |
versión 1 |
v2 ahora comercial |
Ten en cuenta que MindTerm es tanto una implementación independiente en Java (sólo necesitas el runtime de Java ) como un servlet que se puede ejecutar dentro de un un navegador web compatible y bien diseñado. Desafortunadamente, las últimas versiones de esta excelente distribución han pasado a ser productos comerciales.
Hoy en día esta distribución es probablemente la que se debe usar en entornos Unix/Linux (soporte continuo, buen tiempo de respuesta, código abierto y gratuito).
El desarrollo de OpenSSH comenzó con la versión original (SHH 1.2.12) de Tatu Ylonen (la última realmente libre) en el proyecto OpenBSD 2.6 (via OSSH). Ahora, OpenSSH es desarrollado por dos grupos, uno desarrollando únicamente para el proyecto OpenBSD, y otro adaptando continuamente el código para hacer una versión portable.
Todo esto tiene algunas consecuencias, particularmente, el código es cada vez más y más una monstruosa adaptación constante (noto el síndrome "sendmail" apareciendo en el horizonte) y esto no es saludable para una aplicación dedicada al cifrado que debería ser extremadamente rigurosa y clara.
Además de una programación limpia y legible, otros dos puntos me molestan:
En mi opinión (y no soy el único), un producto de cifrado multiplataforma debería tener un comportamiento demostrado, determinado y constante independientemente de la plataforma, así como tomar en cuenta (eliminando) las características particulares de la plataforma y su evolución.
Dicho esto, tenemos que admitir que, las implementaciones de la competencia no son ni numerosas ni atractivas. Creo que es más pragmático considerar que hoy en día OpenSSH es la peor implementación ¡si excluimos al resto...! Un proyecto muy útil para la comunidad sería el rediseño y reescritura del código.
¡SSH no es milagroso! Cumple bien la tarea para la que fue diseñado, pero no le puedes pedir más. Particularmente no evitará conexiones "autorizadas": si una cuenta es comprometida, el intruso podrá conectarse via SSH a tu máquina, aunque este sea el único método, ya que controla la autentificación. Sólo se puede confiar totalmente en SSH si va acompañado de una política de seguridad práctica y coherente: si alguien usa la misma contraseña para todo, y no usa SHH en todos lados, el riesgo potencial sólo disminuye ligeramente. Podemos admitir que en esta situación SSH se puede "volver contra tí" ya que el intruso puede usar una conexión segura cifrada con un túnel, y podrá hacer casi todo lo que quiera sin que puedas rastrearlo de forma eficiente.
De la misma manera, uno debe tener en cuenta también los "rootkits" bien hechos que normalmente contienen un demonio SSH para hacer volver discretamente a tu sistema, pero con unas pocas modificaciones: por supuesto no escucha en el puerto 22, tiene la delicadeza de no loguear, se llama como un demonio ordinario ( por ejemplo httpd), e invisible para el comando "ps" (que también ha sido modificado de alguna manera por el rootkit).
Al contrario, uno no debe estar demasiado preocupado por el peligro que puede representar un demonio SSH que puede permitir a los intrusos estar más cubiertos todavía: deberías saber (espero) que es posible meter casi cualquier cosa en casi cualquier cosa en IP, incluyendo la "apropiación indebida" de protocolos esenciales a través de un cortafuegos: tunelización de HTML, tunelización de ICMP, tunelización de DNS, .... Así que no enciendas el ordenador si quieres un sistema 100% seguro ;-).
SSH no está exento de "agujeros" de seguridad derivados de la implementación (muchos han sido corregidos en el pasado, no hay programa perfecto), pero también a nivel de protocolo. Estos "agujeros", aunque se anuncien como muy alarmantes, normalmente afectan a debilidades que son difíciles de utilizar lo que hace que su manipulación sea técnicamente compleja: uno debe tener en mente que los incidentes de seguridad que podrían haber sido evitados por el uso de SSH son diarios, mientras que aquellos que estarían causados por puntos débiles de SSH son de alguna manera teóricos. Sería interesante leer el estudio relativo a ataques "man in the middle": http://www.hsc.fr/ressources/presentations/mitm/index.html. No obstante será necesario tener en cuenta este tipo de vulnerabilidades potenciales para las aplicaciones de "alta seguridad" (banca, militares, ....), donde los medios usados por el cracker, altamente motivado por el premio y el beneficio, pueden ser considerables.
El agresor intercepta los paquetes de ambos lados, y genera
sus paquetes para engañar a ambas partes
(diferentes escenarios son posibles, hasta el extremo de
terminar la conexión en un lado,
y continuar con el otro lado haciéndole creer que es la otra
parte habitual)
Me gusta señalar a menudo una debilidad incomprensible del protocolo respecto al "relleno -- padding" (conocido como canal cubierto): tanto en la versión 1 y 2 los paquetes, tienen una longitud que el múltiplo de 64 bits, si son rellenados con un número aleatorio. Esto es bastante inusual y por lo tanto da lugar a un fallo clásico que es bien conocido en las implementaciones de los productos de cifrado: un canal "oculto" (o "subliminal"). Normalmente, "rellenamos" con una secuencia verificada como por ejemplo, dar el valor n para el rango de bytes n (relleno autodescriptivo). En SSH, la secuencia siendo (por definición) aleatoria, no se puede verificar. Consecuentemente es posible que una de las partes en comunicación comprometiese la comunicación, por ejemplo como en el caso de una tercera parte que está a la escucha. Una también puede imaginar una implementación corrupta desconocida por las dos partes (fácil de realizar en un producto donde se proporcionen únicamente los binarios como en general es el caso de los productos comerciales). Esto se puede hacer fácilmente y en este caso uno sólo necesita "infectar" el cliente o el servidor. Dejar dicho increíble fallo en el protocolo, siendo universalmente conocido que la instalación de un canal cubierto en un producto de cifrado es EL método clásico y básico para corromper la comunicación, me parece increible. Puede ser interesante leer los comentarios de Bruce Schneier sobre la implementación de dichos elementos en productos influenciados por agencias gubernamentales. (http://www.counterpane.com/crypto-gram-9902.html#backdoors).
Para terminar quiero resaltar el error que encontré en el código de las versiones Unix anteriores a la 1.2.25, al realizar SSF, la adaptación francesa de SSH, y cuya consecuencia era que el generador de números aleatoreos producía... resultado... predecibles (esta situación es lamentable en un producto criptográfico, no entraré en detalles pero se podía comprometer una comunicación con simplemente capturar los datos). Por aquel entonces el equipo de desarrollo de SSH ya había corregido el problema (sólo había que modificar una línea), pero curiosamente sin enviar ninguna alerta, ni siquiera una mención en el "changelog" del producto... si no hubiesen querido que no se supiera, no habrían actuado de esa manera. Por supuesto esto no tiene ninguna relación con el enlace al artículo anterior.
Voy a repetir lo que escribí en la introducción: SSH, ni hace milagros, ni resuelve él solo todos los problemas de seguridad, pero hace posible el manejo eficiente de los aspectos más frágiles de los programas históricamente utilizados para las conexiones interactivas (telnet, rsh...).
Los dos siguientes libros cubren la versión 1 y 2 de SSH:
Y si te quieres gastar un poco de dinero, aquí tienes un sitio donde comenzar...:
Aquí tienes un método para explotar el canal cubierto (subliminal) consecuencia del uso el relleno aleatorio en SSHv1 (y v2). Rechazo cualquier responsabilidad sobre los ataques de corazón que les puedan dar a los más paranoicos.
Los paquetes de SSHv1 tienen la siguiente estructura:
offset (bytes) |
nombre |
longitud (bytes) |
descripción |
0 |
tamaño |
4 |
tamaño del paquete, tamaño del campo sin relleno, entonces: tamaño = longitud(tipo)+longitud(data)+longitud(CRC) |
4 |
relleno |
p =1 a 8 |
relleno aleatorio : tamaño ajustado para que la parte cifrada sea múltiplo de ocho |
4+p |
tipo |
1 |
tipo de paquete |
5+p |
datos |
n (variable >= 0) |
|
5+p+n |
suma de control (checksum) |
4 |
CRC32 |
Únicamente un campo no está cifrado: el "tamaño". La longitud de la parte cifrada es siempre un múltiplo de ocho, ajustada por el "relleno". El relleno siempre se realiza, si la longitud de los últimos tres campos es ya múltiplo de 8 entonces el relleno tendrá una longitud de ocho bytes (5+p+n resto 0 modulo 8). Sea la función de cifrado C, simétrica, usada en modo CBC, y la función de descifrado C-1. Para simplificar la demostración, cogeremos solo los paquetes con un relleno de ocho bytes. Cuando llega un paquete, en vez de rellenarlo con un número aleatorio, pondremos un valor C-1(M), de ocho bytes en este caso. Esto significa descifrar el mensaje M con la función C usada para cifrar el canal (el hecho de que M sea "descifrada" sin haber sido cifrada de antemano no tiene ninguna importancia desde un punto de vista estrictamente matemático, no voy a entrar en detalles aquí sobre la implementación). Lo siguiente es llevar a cabo el procesado normal del paquete, esto es, el cifrado en bloques de ocho bytes.
El resultado será el siguiente :
offset |
contenidos |
notas |
0 |
tamaño |
4 bytes no cifrado |
4 |
relleno de 8 bytes (cifrado) |
entonces C(C-1(M)) |
12... fin |
tipo, datos, CRC |
¿Qué es lo asombroso? El primer bloque cifrado contiene C(C-1(M)). Como C es una función de cifrado simétrica, entonces C(C-1(M)) = M. ¡Este primer bloque se envia sin cifrar en un flujo de datos cifrado! Eso simplemente significa que cualquier persona espiando la comunicación que conozca la estratagema sabrá como explotar la información. Por supuesto, uno puede asumir que el propio mensaje M está cifrado (mediante una clave pública, por ejemplo, lo que evita poner la clave dentro del código pervertido), lo que permite que alguien que no esté informado no la pueda descifrar.
Por ejemplo, son suficientes tres paquetes de este tipo para pasar la clave de sesión triple-DES (168 bit), tras los cuales el sniffer escuchando este flujo podrá descifrar toda la comunicación. A partir del momento en que la clave es transmitida, ya no es necesario "pre-descifrar" el relleno pervertido antes de inyectarlo al paquete, es posible usar rellenos de cualquier tamaño si uno quiere añadir incluso más información.
El uso de este canal cubierto es ¡absolutamente indetectable! (se debe tener cuidado al cifrar cada elemento del mensaje como se explicó previamente, para que la entropía del bloque no revele la estratagema). Indetectable porque el relleno es aleatorio, lo que elimina cualquier posibilidad de pruebas de validación. El Relleno Aleatorio nunca debería utilizarse en los productos de criptografía, nunca.
Lo que hace a este canal incluso más peligroso que otros en el protocolo es lo inducido por mensajes como SSH_MSG_IGNORE que es utilizable sin tener conocimiento de la clave cifrada.
Para evitar los perversos efectos del relleno aleatorio, uno simplemente debe definir en el protocolo el uso del relleno determinístico: normalmente llamado "self describing padding -- relleno autodescriptivo", lo que significa que el bit de offset n contiene n. El relleno aleatorio existe en SSH v2, es una elección, así que tenlo presente...
Para terminar, simplemente diré que si critico el canal cubierto, es porque me gustaría que un producto como SSH, que dice ser altamente seguro, realmente ofreciera un máximo de seguridad. Ahora eres capaz de imaginar que existen múltiples oportunidades potenciales de manipulación en los productos comerciales: solo los productos de código abierto pueden ofrecer una solución a un requisito indispensable, la posibilidad de revisar el código (incluso aunque dichas revisiones sean necesarias).
|
Contactar con el equipo de LinuFocus
© Bernard Perrot, FDL LinuxFocus.org |
Información sobre la traducción:
|
2003-04-07, generated by lfparser version 2.34