Archivo de la categoría ‘Internet’

Seguridad: Encriptación y Autentificación. Capítulo Segundo -> Cifrado de Datos

ATENCION: Los ejemplos que se van a mostrar y “tutoriales” tan solo tienen carácter educativo. En ningún aspecto comparto filosofías de invasión a la intimidad, ataques contra un sistema informático o cuestiones similares. En la medida que sea posible siempre se usarán ejemplos y formas que puedan ser usados por cualquier persona, de forma que pueda verificar los contenidos escritos. No obstante, por motivos más que obvios, materiales como contraseñas, nombres de usuarios o de hosts, serán omitidos o modificado en las capturas de pantallas realizadas (o las lineas escritas). Es decir, los ejemplos serán completamente reales, los datos mostrados a vosotros necesarios para poder pertrechar estos ejemplos no siempre lo serán (Sí lo serán los resultados). Para que esto conste de forma clara, todo material sensible modificado o falso estará resaltado en ROJO. Por motivos de seguridad, todo el material que sea expuesto aquí (exceptuando software propietario o libre, citaciones expresas o código de terceros) tanto texto, imágenes y código son propiedad del autor y está completamente prohibido su reproducción completa o parcial en otros lugares, espero que se comprenda.

 

Cifrado de datos

Este no es un término nuevo, y desde tiempos inmemorables es algo que se ha ido haciendo de un modo u otro. Y es que seamos honestos… no nos suele gustar la idea de que puedan invadir nuestra intimidad o interceptar cartas, mensajes, ideas… que van hacia otra persona. Evidentemente esto toma una importancia mayúscula cuando esta información es sensible o de suma importancia. Quzás el primer gran ejemplo de criptografía en el ámbito de las comunicaciones fue sin duda la máquina Enigma.

Para quien no lo sepa, la máquina Enigma fue un dispositivo similar a una máquina de escribir diseñada allá por los años 30, siendo famosa por ser usada por los Alemanes durante la Segunda Guerra Mundial. Era un dispositivo creado con inteligencia. Digamos que poseía tres discos con 26 posiciones cada uno. En cada una de esas posiciones se mapeaba una letra. Cada letra de cada disco a su vez se encontraba conectada con el disco vecino, y dependiendo de la posición inicial de cada uno de los discos, la letra era mapeada de disco en disco en una o en otra. Se diseñaba de tal modo que al presionar una tecla de la máquina, esta quedaba asociada con una letra mapeada del primer disco. En el primer disco la letra se mapeaba a la letra de salida del primer disco (que no correspondía a la de entrada) y en dicha salida se conectaba el segundo disco. El segundo disco tomaba de entrada la salida del primer disco e igualmente que como hacía este, internamente esa letra de entrada la mapeaba a la salida. El tercer disco hacía lo propio, tomaba la letra de salida del segundo y según su posición en dicho momento la transformaba en otra diferente a su salida. Despues de todo esto, un 4 disco (no obligatorio) hacía que existiese un camino de retorno, de forma que se pasase de nuevo por el tercer disco, despues por el segundo y después por el primero. La salida se conectaba a una bombilla que indicaba la letra codificada. Para evitar separaciones de palabra, todo el mensaje era enviado sin espacios.

Posiblemente fue la primera máquina seria para cifrar comunicaciones. Hay que decir que, según dicen, gracias a que la alianza fue capaz de desencriptar la mayoría de las comunicaciones de los alemanes (gracias a que pudieron romper en gran medida el sistema de Enigma) la guerra duró dos años menos de lo que podría haberse alargado. Un buen ejemplo sin duda alguna de criptología.

 

Para nosotros es cosa del pasado. Vivimos en un mundo digital y un mundo en el que las comunicaciones juegan un papel a día de hoy imprescindible. Por lo tanto es de sentido común que existan sistemas que podamos considerar seguros tanto para almacenar datos de forma protegida como para ser capaces de crear canales seguros de comunicación entre dos puntos cualquieras del mundo. Precisamente porque las comunicaciones se han convertido en algo imprescindible y de uso constante, no podemos hacer oídos sordos y pensar erróneamente que nuestros datos no son de la importancia de nadie. Dado que los canales de los que hacemos uso son públicos, nuestra información, nuestros datos están expuestos a todos. Puede que a nadie le importe que otros puedan saber en un momento dado en que blog escribe, que vean las fotos que tienen guardadas o las recetas archivadas. Pero seguro que a nadie le gustaría que humeen en su correo, en sus cuentas bancarias, en todo aquello que pueda ser de índole personal. Lo que pasa es que se presupone que todo es seguro y que no existirá nunca una intervención externa… y esto no es así. Como vimos con el Spoofing o como veremos en otros artícuos como el Sniffing, la intención rara vez encaja con la realidad.

Por todo ello vamos a introducirnos un poquito en los sistemas reales de protección que podemos encontrar a día de hoy. Y digo reales porque posíblemente gracias tan solo al cifrado de datos es posible garantizar una intimidad a la cual tiene derecho todas las personas. No vamos a estudiar la máquina enigma de ningún modo, vamos a ver los dos sistemas de cifrado que disponemos en la actualidad, cada uno con sus pros y sus contras, claro está:

  • Cifrado Simétrico
  • Cifrado Asimétrico

 

Cifrado Simétrico

Un cifrado simétrico no es más que algún sistema por el cual se encripta un contenido aplicándole una clave (o key, del ingles llave) y se desencripta usando la misma clave. Podemos pensar de un modo más específico en una contraseña, pero esta no es más que una particularidad de un cifrado simétrico. Por ejemplo, la máquina enigma era un dispositivo de cifrado simétrico, en el que la key era la posición inicial de los discos y el cableado interno que mapeaba las teclas a los discos. Se usaba por tanto la misma disposición si se deseaba recuperar el mensaje original. En la era digital, nuestras key suelen ser lo que comunmente llamamos “contraseñas”, aunque no todas las contraseñas son para cifrar. Así por ejemplo llamamos contraseña a la cadena de caracteres que debemos de teclear para poder encriptar un documento, pero también llamamos contraseña a la cadena de caracteres que debemos de teclear para acceder a nuestro correo, y no se usa en modo alguno para cifrar nada, solo como método de control de acceso. En cualquier caso, esta key (no usaremos el termino “contraseña”) en los cifrados simétricos sería la misma para encriptar un dato que para desencriptarlo.

Como vimos en su momento con los Hash, podríamos suponer que con el cifrado simétrico lo que sucede es algo similar. A un dato de entrada se le aplica una función que depende de una key para producir una salida. Pero a diferencia de los hash, la encriptación no es un camino único, es decir, la salida puede convertirse bit a bit exactamente igual a la entrada cuando el mensaje se desencripta. Esto implica que la función que sea aplicada a la entrada no será sino una serie de modificaciones que se realizarán a los datos de entrada para ocultarlos. Esas modificaciones dependerán íntegramente de una key.

Según el sistema usado por el sistema de cifrado, se puede clasificar dos tipos de cifrados simétricos: Cifrado de bloques y cifrado de flujo. Pese a que pueda ser más o menos complicada la matemáticas detrás de cada algoritmo de cifrado, no lo es tanto comprender su funcionamiento.

 

Primero veamos el cifrado simétrico de flujo. El cifrado de flujo se pensó idealmente para aquellas tareas en las que se desea cifrar algo que se está generando en tiempo real. Es decir, en un principio pensado para las comunicaciones. Esto tiene su lógica, si deseamos encriptar un archivo de 20MB en disco por ejemplo, conocemos a priori no solo el tamaño completo del archivo, sino también cada uno de sus byte. En cambio cuando los datos a transmitir son en tiempo real (por ejemplo) el modelo anterior no vale, tan solo podemos ir codificando pequeños fragmentos de un todo, fragmentos tan pequeños como bytes o incluso bits. Es decir, cada byte (por ejemplo) que se genera, se encripta y se envía. El fragmento enviado por tanto tiene significado propio, puesto que aunque pertenece a un todo, el mismo byte (en este caso) se desencripta directamente en el destino.

Pese a la complicación que esto pueda parecer, es relativamente simple en concepto. La idea es poder cifrar unidades mínimas de contenido sin que estas dependan de nada más. Pero esto crea un problema… Si la misma key fuese usada para todos los bytes, sin siquiera conocer la key sería muy facil atacar un cifrado en flujo, dado que las unidades codificadas son muy pequeñas, sería fácil encontrar mensajes o partes de estos, patrones… Para evitar esto lo que se hace con los cifrados de flujos es generar también un flujo constante de keys. Esto suena raro… el algoritmo de cifrado simétrico de flujo aplica una serie de operaciones matemáticas “seguras” para generar a su salida un flujo constante de bits, no predecibles claro está, que a su vez son los que son usados para cifrar a su vez el flujo de datos. Vamos a ver un ejemplo sencillo de esto aplicando posiblemente uno de los cifrados más básicos que existe, el cifrado XOR. XOR es una operación lógica que dice lo siguiente:

style=”text-align: justify;”>Si A = B => A XOR B = 0. Es decir, se puede expresar como A XOR A = 0
style=”text-align: justify;”>Si A != B => A XOR B = 1. Es decir, se puede expresar como A XOR 0 = A

Al igual que con los hash, imaginemos una función tal que F (key) = Kflujo

Si tenemos lo anterior en cuenta, ahora imaginemos dos flujos de datos constantes de bits:

Datos para Enviar Mensaje XOR Key Datos Enviados
Mensaje Original: 10100111 0 1011001
Kflujo: 11001011 1 1100100
Mensaje Final: 10100111 1 0111101

Es decir, el flujo constante de datos a enviar se combina mediante una operación XOR con un flujo de datos constantes también generado por una Key inicial gracias a un algoritmo dado. El receptor en nuestro ejempli tan solo tendría que generar el mismo flujo de datos desde la key original y aplicar la misma operacion XOR a los datos recibidos, de ese modo el mensaje original se reconstruiría. De este modo, a partir de un cifrado simple y lleno de problemas como pueda ser un cifrado XOR, se logra que sea consistente gracias al flujo constante de bits derivados de la key original.

No obstante, por regla general los cifrados en flujo son mucho menos robustos que los cifrados en bloques, y estos a su vez pueden actuar como cifrados en flujos, lo que poco a poco deja a los cifrados simétricos de flujo en desuso. No obstante, a día de hoy continúan siendo una fuerte columna vertebral de las comunicaciones, siendo su buque insignia el cifrado RC4. Aunque es un cifrado que ya no podríamos considerar seguro dado a los ataques pertrechados hacia él con relativo éxito, continúa siendo un cifrado extremadamente simple de implementar y de procesar, lo que lo hace ideal para tareas en las que la seguridad a lo mejor no es crucial, pero si importante. Por ejemplo, RC4 es el cifrado que usan las redes WIFI que usan WEP, el algoritmo de cifrado es RC4, y como todos sabemos WEP es un sistema a día de hoy completamente roto. Otros ejemplos de RC4 fue su uso (cada vez menos habitual) en certificados digitales (ya veremos esto más adelante). Y posiblemente los amantes de las redes Torrent podrán ver en muchos de sus clientes la opción de cifrar todo mediante RC4. Como vemos, aunque no nos otorga un grado de seguridad completo, para muchas tareas es bastante útil. En la actualidad existen otros cifrados de flujos más seguros que RC4, como por ejemplo las alternativas eStream. Personalmente no creo que vuelvan a ponerse de moda los cifrados en flujos, y que se continuará con la tendencia de los cifrados en bloque.

 

El cifrado simétrico en bloques difiere en concepto del cifrado en flujo. En este caso no se pretende a priori cifrar bit a bit un contenido, sino aplicar a un bloque de un tamaño preestablecido una serie de transformaciones (evidentemente reversibles) para dar como resultado una salida encriptada de dicho bloque. La pregunta podría estar entonces, que si dicho bloque es pequeño y el cifrado de flujos actúa sobre unidades “grandes”, ambos conceptos podrían ser iguales. Y esto es cierto.

En el caso del cifrado en flujo lo importante es la forma en la que se generará el flujo de keys y el sistema que se realizará para “combinar” los dos flujos. Aquí el sistema es mucho más complejo y sólido normalmente. Normalmente un mensaje que se quiere cifrar es dividido en bloques (de ahí su nombre) de tamaños de 64-256 bits cada uno. Lo ideal por tanto es siempre encriptar un contenido que sea cientos de veces dicho número, con lo que se tendrían cientos de bloques independientes. Cada bloque suele funcionar del mismo modo, las mismas operaciones que se aplican a uno se aplican a otro. No obstante, al igual que sucediese con los cifrados de flujo, lo normal es que la key original tan solo sea key del primer bloque, siendo la key del resto de ellos una key derivada ya no solo de esta, sino del contenido encriptado, lo cual hace ya de por sí complicada su “búsqueda”. La diferencia por lo tanto entre los diferentes cifrados de bloques radicará en esas transformaciones realizadas dentro de los bloques para obtener el resultado.

Normalmente, a estas transformaciones se les denominan “Etapas”, y no es extraño ver cifrados de bloques con varias de ellas. Por ejemplo el Cifrado AES consta de entre 10 a 14 etapas, dependiendo de la longitud de su Key. Al final de todas las etapas de cada bloque, se genera el mensaje cifrado, que en contraposición con el cifrado de flujo, aquí normalmente cada bloque cifrado es dependiente de todo su bloque, no existe una correspondencia bit cifrado – bit descifrado.

Pese a que cada algoritmo es diferente, los cifrados de bloques igualmente tienen diferente modos de operación. Cada uno de ellos no difieren por el tipo de transformaciones aplicadas, sino más bien por las interacciones entre sus bloques. Así por ejemplo, el sistema más sencillo de cifrado por bloques sería aplicar a cada bloque una función matemática tipo Fbloque(Key) = Bloque_Cifrado. Es decir, a cada bloque se le aplicaría siempre la misma key de forma independiente. Este esquema se contempla, y se llama sin ir máss lejos ECB.

Un paso más allá sería algo similar a lo que se ha visto con el cifrado de flujos. En este caso cada bloque no es independiente. En el modo CBC el bloque cifrado se combina mediante una operación lógica XOR con el bloque aun sin cifrar del siguiente bloque, y el resultado será el bloque que, ahora sí, se pasará a cifrar. De este modo simple, se logra una dependencia completa de cada uno de los bloques, haciendo inviable muchos ataques criptográficos.

Aunque existen otros sistemas de funcionamiento de los cifrados de bloques, la mayoría aplican el concepto explicado para CBC (Cifrado de bloques en cadena) pero en diferentes partes. Por ejemplo, se podría realizar la operación XOR en vez de entre el bloque cifrado y el bloque siguiente sin cifrar entre el bloque sin cifrar y el bloque cifrado de un mismo bloque y realizar a continuación otra XOR con el bloque sin cifrar siguiente, y a esto se le llamaría PCBC.

 

Estos modos de funcionamiento que pueden parecer no tener importancia, la tienen y mucha. Un test bastante conocido para comprobar la resistencia de un sistema de cifrado frente a la posible repetición de patrones, es la codificación de una imagen. Una imagen suele tener patrones que se repiten constantemente, es decir, en una imagen suelen existir zonas uniformes que pueden tener el mismo contenido. Luego una imagen es un ejemplo perfecto para atacar a un cifrado. ¿Como se realiza esto? Una imagen no son más que puntos distribuidos uniformemente sobre toda una superficie, cada cual con un color. Si quisiésemos almacenar una imagen en nuestro sistema, el método más simple sería simplemente tomar cada punto de la imagen de forma consecutiva e ir añadiéndolo a un archivo binarios simplemente especificando su color. Esto se comprende mucho mejor con un ejemplo. Pensar en que tenemos una imagen de 5 x 5 pixeles, cada uno de los pixeles está codificado en RGB con 1 byte para cada canal, es decir, que cada punto se representaría en una matriz de (5×3)x5 en la cual cada elemento constituye un byte (un valor entre 0 y 255) . Esta podría ser nuestra imagen expresada como una matriz de puntos:

128 045 135 236 002 237 112 222 012 087 158 255 000 055 099
128 045 135 236 002 237 112 222 012 087 158 255 000 055 099
128 045 135 236 002 237 112 222 012 087 158 255 000 055 099
128 045 135 236 002 237 112 222 012 087 158 255 000 055 099
128 045 135 236 002 237 112 222 012 087 158 255 000 055 099

En un archivo binario esto se almacenaría simplemente un valor tras otro. Para visionar dicha matriz de puntos tan solo tendríamos que conocer esta distribución y aplicarla a la pantalla de nuestro monitor. Sabemos que es una imagen de 5×5 con 3 canales de color, con lo que el PC tan solo debería de tomar los valores de 3 en 3. Cada 3 valores obtendrá el color de cada pixel, y su ubicación dentro de la matriz corresponderá a la ubicación del pixel en la pantalla. Este sistema no obstante no puede aplicarse a los algoritmos de imágenes actuales como JPG, PNG, TIFF… ya que estos de un modo u otro aplican compresión a las imágenes (ya sea con pérdida o sin ella), y no se podría comprobar lo que queremos explicar. Podríamos llamar a esto una imagen RAW, el problema de llamarlo así sería la confusión que ocasionaría con las imágenes RAW de las cámaras de fotos.

Visto esto, veamos la aplicación real. Primero partiremos de una Imagen RAW Fuente creada para tal ejemplo a la que he llamado egocéntricamente “Theliel”, “Alma Oscura” era muy largo para este propósito:

Evidentemente la imagen mostrada aquí no es una imagen RAW (Entendiendo RAW no como imagen de las cámaras de fotos), es una conversión a png para que el navegador pueda mostrarla. ¿Pero que es lo que sucede cuando la codificamos con un algoritmo como AES-256 (el cual veremos más adelante)? Para ello se ha realizado dos simples conversiones, una usando el método ECB y otra usando el método CBC:

La primera pertenece a la codificación ECB, mientras que la segunda imagen corresponde a la codificación CBC. Ambas imágenes hablan por si mismas. Si se accede a las versiones grandes, se puede comprobar aun mejor que incluso cuando se está codificando con AES-256 (un cifrado muy fuerte), cuando se realiza en ECB la imagen puede ser adivinada, incluso el texto es completamente legible. La imagen no es del todo clara, pero se puede apreciar perfectamente el contorno de la manzana de Apple. Esto nos plantea lo que a mi parecer es uno de los grandes problemas de la seguridad, y es que el problema no radica ya en encontrar sistemas que sean seguros, sino en el uso que se den de ellos. Que exista el método ECB no implica que sea una buena opción usarlo. El resultado de un cifrado en ECB de cada bloque es el mismo si el bloque a encriptar no varía. En una imagen, no es raro encontrar estos patrones, y dado que podemos representar de una forma gráfica esta encriptación, obtenemos un resultado realmente curioso, como el que hemos mostrado. En contrapartida, al usar CBC, cada bloque tenga o no tenga la misma información, será codificado de forma diferente, dado que la codificación de cada bloque depende del anterior. El resultado es una nube de píxeles de colores sin sentido alguno, quedando la imagen real completamente oculta.

Los cifrados de bloques según lo explicado, no obstante deja algunas incógnitas como que sucede cuando el contenido a cifrar no corresponde a un tamaño múltiplo del tamaño de bloque o que sucede con aquellos bloques que requieren de un bloque anterior (o posterior) y no lo poseen dado que son el primero o el último.

Respecto al primer problema, el tamaño de bloque, se acude a una técnica mas que conocida por la mayoría de los programadores, el Padding. Es decir… rellenar. Si los bloques son por tanto de 64bits y el último bloque tan solo tiene 32, los 32 bits restantes se rellenarían. Esto hace a su vez aparecer un problema añadido… la salida tendrá un tamaño siempre mayor que la entrada, dado que será necesario añadir tantos bits como sea el caso para poder completar el bloque. Y el segundo problema que aparece es con que datos rellenar ese Padding, lo que produce a su vez que sea complicado esclarecer el tamaño REAL del mensaje original. Para esto existen diferentes técnicas más o menos elaboradas, pero decir al menos que rellenarlo todo con simples carácteres “null” (nullo) no sería recomendado.

Respecto al segundo problema, lo normal es que exista una entrada adicional a la Key y al contenido a cifrar en el sistema, que se denomina como vector de inicialización (IV). No obstante, dado que estos vectores no pertenecen al algoritmo dado y normalmente no es dado tampoco como dato de entrada, lo normal es que la propia implementación del algoritmo lo establezca. Otra solución sería no usarlo o suponer que de no expresarlo, el vector de inicialización será una cadena de ceros.

No han sido pocos los cifrados de bloques que han existido y existen. Muchos de ellos buscando siempre ser el mejor en cuanto a seguridad se refiere, otros por ser los más rápidos, otros por ser mejores en otros fines… y se llegó al absurdo de que existían un sin fin de cifrados de bloques que eran usados. Todo ello por supuesto sin contar con el secretismo. Antes se pensaba que cuanto más secreto fuese un cifrado, más invulnerable era. Esto parecía lógico, si nadie sabe como se implementa o como funciona, lograr desencriptarlo sería complicado. El problema no obstante es que un millón de cabezas piensan más y mejor que unas cuantas cabezas de ingenieros que en su día crearon dicho algoritmo.

Así, posiblemente el primer cifrado por bloques que llegó a convertirse en un estándar y publicado como tal fue DES (Estandar de encriptación de datos). DES contaba con una key de 56bits, bloques de 64 bits y un total de 16 rondas. Al margen de lo seguro o no que pudiese ser, hoy por hoy sería impensable un sistema de cifrado con key de 56bits. En el peor de los casos por simple fuerza bruta serían necesarias 256 comprobaciones, y con el hardware actual sería un valor fácilmente alcanzable. En 1998 se creó un hardware “barato” que fue capaz de obtener una key DES por fuerza bruta en tan solo 56 horas, aunque un año más adelante tan solo necesitó 22 horas. Esto hizo replantearse seriamente el uso de DES. Después de esto, se comenzó con el uso del sucesor de DES, llamado Triple DES, publicado en 1998 y que básicamente era igual a DES, pero usaba un conjunto de 3 Key DES de 56 bits cada una. En algunos esquemas estas Keys eran independientes, en otros eran keys derivadas. Y aun que a día de hoy se puede considerar Triple DES como seguro, la realidad es que en 2001 fue publicado oficialmente AES. Al igual que se hiciese con los Hash SHA, el período de estandarización de AES fue de 5 años. 5 años en los que compitieron los mejores algoritmos de cifrado de la época, algunos de ellos conocidos dentro del mundo de la criptografía: RC6, Serpernt, Blowfish… y por supuesto el ganador: Rijndael, que pasaría a ser llamado AES (Estandar avanzado de encriptación). AES se estandarizó con 3 longitudes de key diferente, así existe a día de hoy AES-128 AES-192 y AES-256, con un tamaño de bloque de 128 bits. No obstante, el algoritmo original permitía bloques de diferente tamaños y keys.

AES a día de hoy es completamente seguro. Tal es así, que el gobierno de EEUU aceptó el uso de AES-256 para su uso en su material clasificado como “Alto secreto” y AES-128 AES-192 para su material clasificado como “Secreto”. Es decir… actualmente y posiblemente por muchos muchos años, AES permanecerá como cifrado simétrico estandar y seguro.

El como funciona AES en realidad no es tan complejo si comprendemos el funcionamiento de los cifrados de bloques. Lo único que habría que conocer son las transformaciones que se realizan en los boques, esas 10-14 etapas que se llevan a acabo en cada bloque. En primer lugar lo que AES realiza es generar una subkey de bloque derivada de la key original e interpreta la hilera de bits del bloque (128 bits) como una matriz de 4×4 bytes (1 Byte son 8 bits, 4x4x8 = 128 bits). Una vez se ha creado la estructura básica del bloque, se aplica el cifrado XOR a la matriz entre esta y la subkey de bloque generada. Una vez realizada esta operación, se realizan una series de operaciones en la matriz, como desplazamiento de columnas, mezclado y otras operaciones no lineales. Para acabar se realiza de nuevo una operación XOR con la subkey que corresponda (diferente a la key de la primera XOR). La matriz resultado se envía como bloque cifrado en una sucesión de bytes.

Como vimos en el ejemplo anterior, AES-256 en realidad sí que es extremadamente seguro, pero es necesario siempre un buen uso de dichos cifrados. Para terminar un pequeño ejemplo de un esquema de codificación simétrica, mostrando muchos de los conceptos aquí tratados:


CrypTool 2 Beta


En el esquema se puede observar como existen tres elementos principales de entrada: El archivo a codificar llamado “Original”, la Key usada llamada “Key” y un generador aleatorio de IVs. Los bloques en azul claro corresponderían a los algoritmos de cifrado, en este caso se ha usado AES-256 ECB y CBC y DES ECB. Por último los archivos de salida generados de los procesos aplicados. Se observa no obstante que para los módulos AES no se ha usado una entrada IVs. Lo que sucede es que el vector de inicialización en este caso sería 0x0000000000000000 (8 bytes). DES por el contrario requiere que se incluya, por ello se ha usado un generador aleatorio de IVs, que no es más que un generador aleatorio de valores de 8 bytes en este caso, dado qeu DES requiere un IV de 8 bytes, es decir, del tamaño de cada bloque (64 bits). Cabe destacar que para la desencriptación del archivo cifrado DES sería necesario suministrar exactamente el mismo IVs, de lo contrario no sería posible recuperar el archivo original. Para esto, siguiendo el esquema, sería tan siple como incluir en la entrada del supuesto módilo de desencriptación DES otra salida del mismo generador de IVs.

El cifrado simétrico es seguro cuando se usa un algoritmo y sistema de cifrado correcto.

 

 

Cifrado Asimétrico

El cifrado simétrico es seguro, es cierto… pero estará siempre enfrentado a una serie de ataques que antes o después es posible que sean rotos. Y su principal desventaja no es esa… es la key. El cifrado asimétrico apareció como alternativa a ello. Pero vamos a ver primero la necesidad del cifrado asimétrico, sería absurdo crear un sistema que no tenga una utilidad.

Hemos dicho que el cifrado simétrico tiene dos problemas. El primero de ellos es que está basado en algoritmos de dos sentidos, es decir, prácticamente (por no decir todas) todas las transformaciones que sufre el bloque por las diferentes etapas son funciones invertibles que a través de la misma key se puede reconstruir el mensaje (dato) original. Esto implica que la fortaleza del algoritmo simétrico recaiga tan solo en las transformaciones algebraica que se realizan sobre el bloque. De ahí que prácticamente todos los cifrados simétricos que se han estudiado antes o después se descubren diferentes ataques a sus diferentes etapas. Por ejemplo, para AES existen ataques exitosos en versiones reducidas de este, es decir, AES con menos etapas. Si AES-128 posee 10 etapas, a lo mejor se ha logrado ataques que pueden considerarse una roptura (es decir, que son computacionalmente posibles) para versiones de 6 o 7 etapas tan solo. La idea de estos ataques es ir logrando cada vez más romper cada etapa, de modo que al ir añadiendo una etapa más, el coeste computacional pueda considerarse factible. Si se llega a obtener un ataque a AES-128 en el que el coste computacional obtenido sea de 280 (por ejemplo) se considerará una roptura, frente a 2128 posibilidades iniciales.

El segundo problema al que se enfrenta el cifrado simétrico es la Key. La key es necesaria tanto para cifrar un mensaje como para desencriptarlo. Esto implica que tanto origen como destino tengan que compartir dicha Key. Esto a simple vista puede carecer de importancia, pero esto quiere decir que si queremos realmente una seguridad decente, en el mejor de los casos tendríamos que tener una key diferente de comunicación con cada uno de los usuarios con los que deseamos entablar una comunicación segura, dado que no usaríamos nunca la misma key con otros usuarios, de ser así otros usuarios podrían leer los mensajes que eran destinados para otros. Esto provoca la necesidad de múltiples keys para cada usuario, lo cual es engorroso e inseguro, dado que la comodidad podría implicar usar la misma key en todas las comunicaciones y esto supondría un problema de seguridad.

 

El cifrado simétrico resuelve estas dos cuestiones. La primera de ella haciendo uso de lo que podríamos llamar “Matemática Imposible”. En el cifrado simétrico se logra un algoritmo de cifrado de un único sentido, el cual no es computacionalmente viable el invertirlo. Podemos decir así que existen en realidad dos algoritmos diferentes dentro de un esquema de cifrado asimétrico, un algoritmo que encripta y otro que desencripta. Y al contrario que sucede con las transformaciones o la álgebra aplicada a un algoritmo simétrico, en la criptografía asimétrica esta función suele ser mucho más simple, lo cual no implica que sea más rápida, todo lo contrario. Así por ejemplo el cifrado AES requiere de 10 etapas mínimas para completar el cifrado de un bloque, mientras que el el cifrado RSA esto se limita a una “simple” función, aunque lo que no es simple es la teoría y el cálculo de dicha función. Estas funciones se basan en la premisa de que es imposible invertirlas, así por ejemplo tenemos el problema matemático de la factorización (usado en RSA) y el del logaritmo discreto (usado en ElGamal). Vamos a basarnos por simplicidad y fácil compresión en RSA. Posiblemente hasta los niños más pequeños aprenden a temprana edad que es la factorización de un número. Factorizar un número no es más que encontrar sus factores, es decir, los diferentes números que lo dividen, es decir, aquellos números que al dividirlo dan como resto cero:

Factorización de 20: 1,2,4,5,10 ya que 20 mod 10 = 0 20 mod 5 = 0….

Todos sabemos factorizar un número, el problema radica en dicho método. El problema reside en que la única forma real de obtener los diferentes factores de un número (así como saber si dicho núnero es por ejemplo primo) radica en ir dividiendo dicho número por cada uno de los números desde el 2 (el 1 es factor de todos los números) hasta n-1, siendo n el número a factorizar. Si disponemos de un número relativamente pequeño como el 101, podemos simplemente ir dividiendo este por 2, por 3, por 4… hasta llegar al 99. En realidad a la hora de encontrar los factores no es necesario llegar a dicho número, tan solo es necesario realizar Raiz (n) operaciones. Es decir, en el caso que el número a factorizar fuese 101, en realidad tan solo sería necesario ir probando Raiz (n) = 10 aprox, es decir, después de 10 operaciones podríamos conocer si realmente 101 es primo: 101/2, 101/3, 101/4… 101/10. Esto podría parecer no tener complicación alguna, 10 operaciones podríamos hacerlas incluso a mano. ¿Pero que sucede cuando el número a factorizar es infinitamente mayor? Podríamos pensar que un PC actual podría manejarlo en segundos, pero esto no es así. Existen diferentes algoritmos que intentan dar una opción viable a la factorización sin necesidad de usar divisiones una a una, el problema es que estos algoritmos no son fiables al 100% ni mucho menos, produciendo lo que se conocen como falsos números primos. Aun así, cuando se manejan los números tan ingentes que pronto veremos, ni haciendo uso de estos algoritmos sería posible. Vemos por tanto en este caso, que la matemática detrás de la factorización es más que conocida, es sencilla, pero es computacionalmente imposible para grandes números.

Respecto al segundo problema comentado, la key, en el cifrado asimétrico no existe una sola key, sino dos. Una key se denomina como clave pública y la otra como clave privada. El concepto es simple. Cada una de las claves son complementarias y pueden ser usadas tanto en el algoritmo de encriptado como en el de desencriptado, es decir, lo que encripta una clave lo desencripta la otra. No hay que pensar en clave pública como clave para desencriptar, sino clave que se distribuye a todo aquél con el que deseamos entablar un canal seguro. A diferencia que el cifrado simétrico en el que es necesario una key única para cada canal de comunicación, aquí será la clave pública la que será usada para todos. Este concepto choca al principio, una clave que se da a conocer a todos. Por otro lado la clave privada será el mayor secreto para su dueño, y es aquí donde reside la vulnerabilidad desde mi punto de vista del cifrado asimétrico. Visto esto, es lógico asumir que el par de claves (privada y pública) deben de estar relacionadas de modo alguno, pero sin que pueda suponer un riesto el conocimiento de dicha clave pública.

Estas dos características hacen que el cifrado asimétrico sea a día de hoy posiblemente el sistema más seguro en cuanto a encriptación de datos, y ello puede verse diariamente. Todas las comunicaciones cifradas a día de hoy que requieren de una privacidad importante, están basadas de un modo u otro en cifrado de clave pública (o cifrado asimétrico). No obstante no todo son ventajas. El cifrado asimétrico para empezar requiere de una capacidad de computación muy superior a la del cifrado simétrico para realizar la encriptación o desencriptación, llegando a ser cientos de veces más lento. Por otro lado se requieren por regla general keys de una longitud muy superior a lo que es habitual encontrar en el cifrado simétrico. Por ejemplo AES-256 (Key de 256 bits) frente a RSA, que puede usar Keys de entre 1024-4096 bits. Aunque una Key de 4096 bits (512 Bytes) sea un tamaño irrisorio para las comunicaciones, nadie sería capaz de recordar jamás una clave de 512 caracteres. En contrapartida, con AES-256 (32 Bytes) por un lado no sería complicado recordar una frase de 32 caracteres, pero además no es necesario, dado que generalmente las subkeys usadas son generadas apartir de nuestra “clave” introducida. Pero en el cifrado asimétrico esto no funciona así, no existen keys derivadas, una para encriptar todo el mensaje, una para desencriptar todo el mensaje.

Este problema de keys grandes se une al echo de la necesidad de que una Key pública sea conocida. Si deseamos que alguien encripte un mensaje hacia nosotros, este mensaje deberá de cifrarlo usando nusetra key pública, luego dicho usuario deberá tener acceso a nuestra key pública. Del mismo modo si queremos responder a dicho mensaje, tendremos que o usar la clave publica de dicho usuario para encriptar la contestación o encriptar la contestación con nuestra clave privada, ya que el receptor dispondrá de nuestra clave pública para desencriptarlo o su clave privada. Para que esto pueda ser posible, hace ya mucho tiempo que se establecieron bases de datos de claves públicas, de modo que cualquier persona pued acceder a ellos de forma simple y conocer la clave pública de cualquier persona.

 

Posiblemente los dos algoritmos de cifrado asimétrico más conocidos sean como hemos dicho RSA y ElGamal. Cada uno de ellos se basa en una imposibilidad matemática y por comodidad vamos a explicar como funciona RSA a grandes rasgos.

RSA como hemos dicho se basa en la imposibilidad matemática de factorizar un número grande. El proceso no es muy complejo. Lo primero es generar las claves que serán usadas, tanto la privada como la pública:

  1. Tomar dos números primos, llamados ‘p’ y ‘q’, los cuales por seguridad se requiere que ambos tengan una longitud de bits similar, para garantizar en caso de un posible ataque el “peor de los casos posibles”, y por otro lado que puedan escaparse a los algoritmos conocidos de búsqueda de primos. Estos dos números es normal encontrarlos de al menos 512 bits de longitud, es decir, un número con más de 154 cifras.
  2. Se calcula n = p x q, y acto segido la función Phi de Eulerm definida como Phi (p x q) = (p-1)(q-1). La función Phi de Euler calcula el número de coprimos que existen a un número dado. dos números son coprimos si no tienen ningún factor en común salvo el 1. Es decir, aunque el 10 no es un número primo, el 14 es coprimo de 15, dado que tan solo comparten el factor común uno. Dado que tanto p como q son números primos (ta solo divisibles por 1 y por ellos mismos) poseerán cada uno un número p-1 y q-1 de coprimos cada uno.
  3. Se escoge un número ‘e’ que se encuentre entre en el intervalo 1 < e < Phi(p x q), de modo que e y Phi sean coprimos entre ellos. Si ‘e’ a su vez es primo mejor.
  4. Se calcula ‘d’ en la siguiente función: d x e = 1 (MOD Phi (pxq)). de = 1 MOD Phi(pq) es quizás el principal problema de comprensión en RSA. Esta función recibe el nombre de multiplicación modular inversa, y se calcula de forma simple gracias al método extendido de Euclides. En realidad es tan solo matemáticas aplicadas. NOTA: Los “Iguales” que son especificados en estas igualdades en las que implican operaciones modulares, no son en realidad “Iguales”, sino “Congruentes”, es decir… equivalentes. Escribir “d x e = 1 (MOD Phi (pxq))” siendo ese “Igual” el símblo de congruencia, significa que 1 = dxe MOD Phi, siendo ese Igual un Igual de los de toda la vida.

Después de estos 4 pasos, la clave privada y la clave pública estarán ya creadas. La clave privada corresponderá entonces a la tupla Clave_privada (n, d), mientras que la clave pública a la tupla Clave_pública (n, e). Una vez obtenidas sendas claves tan solo es necesario aplicar la función de encriptación o desencriptación. Por cuestiones de Padding y seguridad, el mensaje es convertido a un número entero ‘m’, menor a ‘n’:

me = Cifrado MOD n -> Se obtiene así un valor en Cifrado

Cifradod = m MOD n -> El valor Cifrado será desencriptado por medio de dicha función y se obtendrá m, es decir el mensaje original. Tan solo es necesario deshacer el padding.

Como se pueden ver, en realidad las funciones de encriptado y desencriptado son sencillas. Si quisiésemos llevar esto a un ejemplo real a pequeña escala (con números pequeños):

a) p = 101, q = 103 -> Ambos números son primos, de longitud similar (aunque números muy pequeños).

b) n = p x q = 101 x 103 => n = 10403. Phy (10403) = (101 – 1) (103 – 1) => Phi = 10200

c) 1 < e < Phi => 1 < e < 10200 => e = 13. 13 a su vez es primo y coprimo de 10200. Esto puede comprobarse de forma sencilla gracias al algoritmo de Euclides.

d) d x e = 1 (MOD Phi (p x q)) => d x 13 = 1 MOD 10200. Esta ecuación se expresa del mismo modo como: d-1 = e MOD Phi. Si se aplica el método extendido de Euclides se puede obtener de forma sencilla la identidad de Bezout. El método de euclides no es más en realidad que ir dividiendo dividendo entre divisor. Una vez se realiza la operación, el divisor pasa a ser dividendo y el resto divisor y se realiza otra iteración, hasta que se obtiene un resto de 1. A cada iteración se le calcula sus dos coeficientes para generar así la igualdad de Bezout. En nuestro caso para la iteración 5 (en la cual el resto es 1) del método extendido de euclides estos son 5 y -3923. calcular estos coeficientes se obtienen por sustitución de las iteraciones anteriores. En la iteración 3 se obtienen los coeficientes sustituyendo en esta la igualdad de bezout obtenida en la iteración una y dos. Las iteraciones una y dos a su vez se conocen de antemano:

restoi= Combi = Comb (i-2) + Comb (i-1)

Ronda Divndo. Div. Cociente Resto Sustitución Combinación Coef. 1 Coef. 2
1 10200 13 10200 10200=10200*1+13*0 1 0
2 10200 13 13 13=10200*0+13*1 0 1
3 10200 13 784 8=10200-13*784 8=(10200*1+13*0)-(10200*0+13*1)* -784 8=10200*1+13* -784 1 -784
4 13 8 1 5=13-8*1 5=(10200*0+13*1)-(10200*1+13* -784)*1 5=10200*-1+13* 785 -1 785
5 8 5 1 3=8-5*1 3=(10200*1+13* -784)-(10200*-1+13*785)*1 3=10200*2+13* -1569 2 -1565
6 5 3 1 2=5-3*1 2=(10200*-1+13* 785)-(10200*2+13* -1569)*1 2=10200*-3+13*2354 -3 2354
7 3 2 1 1=3-2*1 1=(10200*2+13* -1569)-(10200*-3+13*2354)*1 1=10200*5+13* -3923 5 -3923
8 2 1 2 0=2-1*2 0=(10200*-3+13*2354)-(10200*5+13* -3923)*2 0=10200*-13+13*10200 -13

10200


Pese a la aparente complejidad, si se presta atención al procedimiento realizado rápidamente se comprende como se ha realizado. Una vez obtenido los dos coeficientes, tan solo nos quedaría que d = Phi + Coef. 2 (Resto 1) => d= 10200 – 3923 = > d = 6277. Si deseamos verificar esto: d x e = 1 MOD (Phi(pxq)) => 6277 * 13 = 1 MOD 10200 => 81601 MOD 10200 = 1. Es decir, se cumple.

e) Con esto tendríamos la claves privadas y públicas calculadas:

Clave Privada (n->10403, d->6277), Clave Pública (n->10403,e->13)

Cabe destacar que todo este proceso de 4 fases es tan solo llevado acabo una sola vez, y estas claves serán las que sean usadas durante meses o años sin ningún tipo de problemas. Una vez se tienen estas dos claves, el resto tan solo es aplicar la función de encriptación o la función de desencriptación. Continuando con el ejemplo imaginemos que quisiésemos encriptar la palabra “Casas”, y que estamos usando un sistema simple de translación de dichos valores a ASCII en hexadecimal. Imaginar también que se tiene un Padding que inserta en el mensaje un valor de “0x01” cada dos caracteres:

Mensaje Original: C -> 0x43 a -> 0x61 s -> 0x73 a -> 0x61 s -> 0x73
Mensaje Con Padding: 43 61 01 73 61 01 73. Es decir, cada dos bytes se incrusta un 01.
Tamaño de la palabra: 2 Bytes. Es decir, se especifica la cantidad de Bytes que se van a tomar para realizar la codificación, en este caso por ejemplo 2. Es decir, se divide el mensaje con el padding incorporado en grupos de 2 bytes, si el número es impar (como en nuestro caso) se añade un byte más de padding al final para rellenar

Codificación 1- >4361, Codificación 2 -> 0173 Codificación 3 -> 6101 Codificación 4 -> 7300

me = Cifrado MOD n ->Se cifrará usando la clave pública. En caso de que se quisiese cifrar con la clave privada, en vez de e se usaría d.

436113 = Cifrado MOD 10403 => Cifrado = 436113 MOD 10403 = 7905
017313 = Cifrado MOD 10403 => Cifrado = 017313 MOD 10403 = 6398
610113 = Cifrado MOD 10403 => Cifrado = 610113 MOD 10403 = 3597
730013 = Cifrado MOD 10403 => Cifrado = 730013 MOD 10403 = 3217

En mensaje cifrado por tanto correspondería a la cadena hexadecimal: “79 05 63 98 35 97 32 17“, algunos de esos valores tendrían representación en ASCII y otros no. El proceso de desencriptación sería similar:

Cifradod = m MOD n

79056277 = m MOD 10403 => m = 79056277 MOD 10403 = 4361
63986277 = m MOD 10403 => m = 63986277 MOD 10403 = 0173
35976277 = m MOD 10403 => m = 35976277 MOD 10403 = 6101
32176277 = m MOD 10403 => m = 32176277 MOD 10403 = 7300

Para poder calcular el módulo a tales cifras exponenciales no servirá una calculadora normal, es necesario recurrir a técnicas concretas para el cálculo de módulos a exponenciales. Un buen punto de partida para poder realizar esto sería: AQUI

Como se puede observar, los resultados obtenidos son exactamente los mismos que los iniciales, la cadena desencriptada correspondería a “43 61 01 73 61 01 73 00”, eliminando el Padding nos quedaría “43 61 73 61 73” que se traduciría en ASCII de nuevo como “Casa”.

Según el esquema propuesto se puede ver la necesidad del Padding. El Padding en RSA toma una importancia aun mayor, dado que no solo sirve para añadir al final bytes que puedan faltar para rellenar, sino que es importante incluir ciertos bits o bytes (de forma reversible) en el mensaje original, de este modo RSA se hace resistente a ataques conocidos como “textos específicos”, aunque las vulnerabilidades serán tratados en el último capitulo de este artículo. El Padding debe de ser conocido por todos, no debe de ser un secreto.

Como se puede comprobar, RSA (o los algoritmos de clave pública en general) no son en realidad complejos por sus funciones, sino por la carga matemática que hay detrás de ellos. Las funciones en RSA para cifrar son muy simples, 4 variables de las cuales se conocen siempre 3 y dos operaciones, una exponencial y otra modular. La seguridad en cambio radica en que es virtualmente imposible obtener a partir de la clave pública la clave privada. Como hemos visto, la clave privada corresponde a la tupla n y d. Mientras que n es también un valor dado por la clave pública, d es calculado desde la clave privada a la hora de generar las claves. El cálculo de ‘d’ se podría intentar, pero como hemos visto anteriormente, d depende de Phi (p x q) y para calcular Phi (p x q) es necesario conocer ‘p’ y ‘q’. Aquí es donde radica el problema de la factorización. Sabemos que n = p x q y es un dato conocido, pero no conocemos el valor de ‘p’ y el valor de ‘q’ necesario para poder calcular Phi y posteriormente ‘d’. Para poder obtener ‘p’ y ‘q’ sería necesaria la factorización de ‘n’, y esto como hemos dicho no es viable. Es computacionalmente sencillo obtener dos primos con un número de bits muy grande. Es computacionalmente sencillo multiplicar dichos primos entre ellos. Y es computacionalmente imposible revertir el proceso y obtener los factores de dicho producto, es un camino solo de ida, si perdiésemos ‘q’ y ‘p’ sería imposible volver a encontrarlos.

Para aquellos que les pueda interesar RSA, recuerdo bien el programa DisMat, una herramienta para aprendizaje sobre RSA y otras cuestiones igualmente interesantes.

 

RSA no es el único sistema de clave asimétrica que existe. En la otra cara de la moneda tenemos ElGamal, que está basado en algunas asunciones similares pero en principios diferentes. No voy a detallar el funcionamiento de ElGamal por dos razones. La primera porque honestamente se escapa a los conocimientos matemáticos del redactor (es decir, a mi) y no sería ético buscar información sobre ello y plasmarla aquí sin comprenderla. Y por otro lado, aunque ElGamal es un sistema libre (RSA está patentado), su popularidad es relativa, siendo RSA inmensamente más usado y popular. De todos modos ElGamal si podemos decir que aplica otro principio de la “matemática imposible”, llamado como logaritmo discreto. Lo gracioso es que esto lo hemos visto a menos de pasada dentro de RSA. El problema reside en esta ecuación:

a = bx MOD n => x = log discretob (a)

Siendo a, b y n números conocidos y X la incógnita. El problema es poder calcular X. En RSA nos tenemos que enfrentar a esta ecuación, pero en nuestro caso no tenemos que calcular X, tan solo a. En ElGamal, poder obtener la clave privada implicaría resolver dicha ecuación, y esta es imposible de resolver computacionalmente, es decir… en un tiempo razonable, de nada sirve que pueda ser resuelto con un ordenador funcionando durante miles de años.

 

Los algoritmos de cifrado asimétrico como RSA son extremadamente seguros. El echo de que sea “lentos” comparados a los sistemas de cifrado simétrico hace que normalmente se opte por sistemas híbridos de los que serán tratados en los próximos capítulos. Dado que el potencial de computación es limitado estos sistemas suelen estar a salvo de cualquier posible ataque contra el propio sistema (no implica que no sean vulnerables a otros ataques), pero todos sabemos que la capacidad de cálculo de los dispositivos actuales se incrementa exponencialmente cada año que pasa. Esto significa que cada día que pasa se está un poco más cerca de alcanzar el reto computacional que plantean tanto los cifrados simétricos como AES-256 a cifrados asimétricos como RSA-1024. La ventaja de estos segundos, es que están diseñado para trabajar con longitudes muy superiores, mientras que no sucede lo mismo con los cifrados simétricos. Es probable que dentro de X años, AES-128 sea considerado inseguro, o incluso su sistema sea roto, como en su día lo fue RC4. En cambio encontrar una roptura en sistemas como RSA es harto más complicado.

Seguridad: Encriptación y Autentificación. Capítulo Primero -> Hash

ATENCION: Los ejemplos que se van a mostrar y “tutoriales” tan solo tienen carácter educativo. En ningún aspecto comparto filosofías de invasión a la intimidad, ataques contra un sistema informático o cuestiones similares. En la medida que sea posible siempre se usarán ejemplos y formas que puedan ser usados por cualquier persona, de forma que pueda verificar los contenidos escritos. No obstante, por motivos más que obvios, materiales como contraseñas, nombres de usuarios o de hosts, serán omitidos o modificado en las capturas de pantallas realizadas (o las lineas escritas). Es decir, los ejemplos serán completamente reales, los datos mostrados a vosotros necesarios para poder pertrechar estos ejemplos no siempre lo serán (Sí lo serán los resultados). Para que esto conste de forma clara, todo material sensible modificado o falso estará resaltado en ROJO. Por motivos de seguridad, todo el material que sea expuesto aquí (exceptuando software propietario o libre, citaciones expresas o código de terceros) tanto texto, imágenes y código son propiedad del autor y está completamente prohibido su reproducción completa o parcial en otros lugares, espero que se comprenda.

 


Hash

A diferencia del Spoofing, si hablamos de encriptación o autentificación se debe de establecer un orden sobre lo que vamos a ir viendo. Esto se debe a que un elemento suele requerir de otro, y este otro de otro… si no se explica adecuadamente cada uno de los elementos, será imposible comprender los que dependan den estos. Y el primero de estos elementos es el hash.

Un hash podemos definirlo como el resultado de una función matemática aplicada a una entrada arbitraria de datos, de forma que el resultado es (idealmente) asociado únicamente a la entrada dada y siempre obteniendo un resultado de longitud finita y concreta para el mismo hash. Es decir, idealmente para los hash criptográficos sería imposible volver a obtener el mismo resultado con otros datos diferentes. La idea es poder convertir la cantidad de datos que sea en un “resultado” de longitud fija (fijada por el propio hash). Veamos un ejemplo muy sencillo de esto. Imaginar uan función hash que realiza lo siguiente sobre números enteros:

Hash = numero1 + numero2 + numero3…. MODULO 100

En dicho ejemplo el hash se calcularía sumando cada numero de entrada dado y se le realizaría la operación Módulo 100. La operación módulo devuelve simplemente el resto de la división, y dado que el divisor es 100, el resto será siempre un número entre 0 y 99:


n1 = 500 n2 = 100 -> Hash = (500+100) MOD 100 = 600 MOD 100 = 0 Hash = 0 (600/100 = 6 y resto 0)

n1 = 1250 n2 = 25 n3 = 5460 Hash = (1250+25+5460) MOD 100 = 6735 MOD 100 = 35 Hash = 35 (6735/100 = 67 y resto 35)

Evidentemente esta función hash sería un tanto absurda desde un punto de vista criptográfico, dado que sería relativamente muy facil obtener el mismo resultado con dos entradas de datos diferentes. Pero sirve para dejar ver más o menos de lo que estamos hablando. En este caso tan solo existen 100 posible resultados, pero se puede observar que si modificásemos cualquier número este podría repercutir en un resultado completamente diferente. Las funciones hash hacen más o menos esto, aunque no con una precisión de 100 posibles valores y de una forma mucho más eficiente, pero la idea es la misma. Pero no solo es útil pensar en criptografía, una función Hash puede tener un valor muy importante simplemente en la detección de errores por ejemplo.

¿Para que sirve esto? Tiene una gran utilidad en muchísimos campos. Podemos decir que existen tres tipos de Hash: Hash checksums, Hash CRC y Hash criptográficos.


CheckSum

Sería el ejemplo más básico de Hash. El concepto apareció de la necesidad de verificar de algún modo la integridad de la transferencia de los datos. Es decir, si estos se habían transmitido de forma alguna de forma errónea. ¿Pero como podemos verificar esto? Podemos tratar los datos de entrada de tal forma que nos de un resultado, de modo que si el resultado es diferente en el destino, los datos son erroneos. Generalmente un CheckSum es una operación matemática basada en sumas. El ejemplo expuesto anteriormente sería un posible ejemplo de checksum. El ejemplo de checksum más simple es el bit de paridad. Imaginar que sea cual sea el bloque de datos de entrada, se le computa la paridad al dato, y esta se le añade al dato final. El checksums en sí mismo es tan solo un bit, un cero o un uno que corresponde a la paridad del dato inicial. Cuando los datos son recibidos por el destino, el destino calcula de nuevo la paridad del bloque y la compara con la paridad recibida. Si coincide los datos son válidos. Evidentemente este checksum tan solo previene contra 1 posible cambio de valor en uno de los bits transmitidos. Vamos a verlo con un ejemplo:

Se desea transmitir la cadena “Casa” desde A hasta B. Imaginar que cada carácter es acompañado con un bit de paridad. Un carácter tiene un valor entre 0 y 255 según la tabla ASCII, es decir, un carácter ocupa 1Byte de datos (8 bits). El carácter “C” equivale al código ASCII x43 (43 en hexadecimal), lo que en binario equivale a “01000011”:

C -> 01000011 -> Se aplica Paridad Par por ejemplo (Hay número par de “unos”? si es asi el resultado es cero, de lo contrario es uno) -> 3 Unos, es impar, bit de paridad par = 1

C -> 01000011 + bit de paridad -> Datos transmitidos: 010000111

De este modo, el destino tan solo tiene que tomar los primeros 8 bits y realizar la misma operación. Si el resultado coincide no hay error o no se ha podido detectar. Si no coincide se ha producido un error y los datos no puede tomarse como válidos. En este caso caso, tan solo se podría detectar con un bit un número impar de errores: 1, 3, 5… dado que si se produce un número par de errores el bit de paridad no cambiaría.


Evidentemente existen Checksums más eficientes, aunque todo depende del uso que se le haga. En cambio todos los días tratamos con este tipo de sistemas, y no hay que profundizar siquiera en la informática. En la mayoría de datos personales que puedan ser sensibles, suele existir un carácter o caracteres de control que verifican que los datos introducidos son válidos. Por ejemplo la letra de nuestro DNI no es más que un checksum, que se obtiene aplicando un módulo 23 al número de la división. Al resultado (entre 0 y 22), se le asigna una letra ya espeificada. Por ejemplo, el Cero es la letra T, el tres es la letra A… de tal forma que si damos o introducimos nuestro DNI de forma incorrecta, es posible verificarlo simplemente comprobando la letra proporcionada y ver si coincide con la que debería de ser. A este ejemplo se le suman los carácter de control de los números de cuenta corriente, de otros datos del DNI, número de la seguridad social… es una forma simple y efectiva de detectar con prontitud cualquier error en los datos tomados.

Otro uso increíblemente extendido es en la verificación de datos en sí mismos, no solo en la transferencia de estos. Así por ejemplo, si se quiere disponer de algún tipo de archivo que pueda tener datos relativamente sensibles como bios, firmwares, datos personales… lo normal es ir aplicando checksums a determinadas partes del archivo incrustando este mismo en las diferentes partes del archivo. De este modo, el software a medida que va procesando el archivo puede ir verificando cada bloque para asegurarse de que el archivo es confiable. Pensar en una bios que se quiere actualizar y por cualquier motivo existe un error en uno solo de sus bits. Es suficiente para que el PC no arranque. Para evitar esto, se distribuye por toda la bios checksums que van verificando bloques menores,

Su uso no obstante se ha ido reduciendo con la aparición de los Hash CRC, los cuales suelen realizar operaciones similares pero de una forma mucho más efectiva. No obstante para pequeños bloques de datos o comprobaciones sencillas suele ser más fácil y barato de implementar Checksums. Entre los Checksums más habituales encontramos Sum8, Sum16, Sum32 o Sum64.


CRC

Se traduce como comprobación de redundancia cíclica. Su objetivo y uso es muy similar al del checksum, de tal modo que no es raro ver lugares en los cuales el nombre de CRC no es más que un tipo de checksum. La necesidad de la verificación de los datos es algo de suma importancia, siendo quizás su máximo exponente la firma digital, de la cual ya hablaremos de ella. Pero no solo la detección de errores es necesaria, a veces es necesaria también la corrección de estos. Aunque un checksum puede usarse para esto, es más normal ver este tipo de correctores como CRC. Aun así, los sistemas de corrección de errores suelen ser costosos en cuanto a rendimiento, precio, implementación… tanto que normalmente no compensa, y es mucho más eficiente simplemente un buen sistema de detección, y si la detección es erronea simplemente se retransmiten de nuevo los datos. Si bien los checksums pueden ser una herramienta muy extendida dentro de los propios archivos, los CRC suelen ser usado de forma mucho más extensa en la transmisión de datos, aplicado normalmente a bloques de datos de un tamaño mayor.

El peor escenario que puede darse en una transmisión de datos o en un error en un archivo, es que este no pueda detectarse, haciendo que los datos sean enviados o procesados como legítimos. Y es esto lo que se debe de evitar a cualquier precio. Por ello, los CRC son usados intensamente en la transmisión de datos sobre internet, telefonía… y por supuesto en la integridad de los datos en un disco duro, CD, pendrive y otros dispositivos. Cuando hablo aquí de integridad no me estoy refiriendo a sistemas de checksums que puedan estar implementados en la misma estructura del archivo, sino sistemas de ingreidad que poseen los propios dispositivos. Gracias a la integración hardware y la simplicidad de como opera un CRC (la mayoría de ellos), la gran mayoría de nuestro hardware implementa funciones CRC en él mismo, sin necesidad de un software. Es decir… todo el proceso es transparente a nosotros.

El funcionamiento de un CRC es simple. A un bloque de entrada se le añade primero los bits correspondiente al CRC, y el nuevo bloque se divide por un polinomio preestablecido. El resto de dicha división binaria será el CRC. Dicho CRC se añade al bloque original y se retransmite. El destino tomará el bloque y lo dividirá por el polinomio generador (que será el mismo que usó el emisor). Si el resto es cero, no hay error de transmisión, o al menos no hay error detectable. La eficiencia radica por lo cual en el polinomio generador usado y evidentemente en el número de bits usados para el CRC. El caso más simple de CRC sería el bit de paridad, que correspondería a un bit de CRC tan solo, y el polinomio generador sería X + 1, el cual se traduciría como “11” como divisor del mensaje de entrada. Un polinomio generador tal como X5+X4+X+3 se traduciría por lo tanto como “110011” y se tendría un CRC de 6 bits.

Aun en los CRC-32, no se puede considerar CRC un hash seguro, no está pensado como resultado único de una posible entrada ni como sistema de ocultación o cifrado de datos, sino como un sistema robusto de detección de errores, y francamente, hace su trabajo a la perfección. Gracias a este tipo de funciones hash, a día de hoy disponemos de medios de comunicación fiables y con una gran tolerancia a fallos. Que no apreciemos este tipo de tecnologías, no implica que las estemos usando constantemente. Para hacernos una idea de la eficiencia de los CRC, un CRC-16 tienes el siguiente índice de detección:

  • Detección del 100% de errores simples (errores que afectan tan solo a un bit)
  • Detección del 100% de errores dobles de bits adyacentes (Si dos bits consecutivos son erróneos)
  • Detección del 100% de los errores para datos de hasta 16 bits.
  • Detección del 100% de todos los errores de dos bits que no estén separados uno del otro exactamente a 216-1 bits
  • Para el resto de posibles errores, se establece tan solo una no detección en un fallo de cada 216

Es decir, un cRC-16 sería capaz de detectar aproximadamente el 99.995% de todos los errores. ¿Esto es mucho o es poco? Esto equivale a que cada 20.000 errores, uno no se detecta. Teniendo en cuenta las comunicaciones ultrarápidas de hoy en día, la cantidad de información que es manejada en segundos es simplemente impresionante, por lo cual podemos afirmar que de cuando en cuando efectamente aparecerán errores no detectados. Esto se subsana también gracias a la fiabilidad cada vez mayor de las propias redes, con menos ruido, con mejores equipos…

Los CRC más comunes son CRC8, CRC16, CRC32… aunque si se desea ver una lista de ellos con sus polinomios generadores tan solo hay que acudir a la Wikipedia, por ejemplo.


Criptografía

En realidad son los Hash que nos van a interesar a nosotros. Este tipo de hash se usan ya no solo como detectores de errores (que pueden valer para ello también). Este tipo de Hash, al igual que los que hemos visto, es u procedimiento determinista que devolverá un resultado de una longitud fija. Pero a diferencia de los CRC o checksums en los que su objetivo principal es la detección de errores, la función de un hash criptográfico va mucho más allá:

  • La imposibilidad de poder encontrar una cadena (un bloque de datos…) cuyo resultado sea un hash dado.
  • La imposibilidad de modificación de la cadena inicial, sin modificar el hash.
  • La imposibilidad de encontrar una segunda cadena que verifique un hash de otra cadena.
  • Un hash que sea computacionalmente eficiente y facil de implementar.

Hay que comprender que con imposibilidad no podemos asegurar que sea imposible, sino que el coste computacional para ello sería tan ingente que de ninguna forma sería factible. Esto evidentemente no es más que la teoría, en la práctica todo no es tan simple.

A diferencia de los CRC o los checksums que pueden comprenderse sin muchas nociones de matemáticas y parten de unos conceptos simples, los hash criptográficos son bastante más complicado de comprender (las matemáticas escondidas detrás de ellos). Cada algoritmo hash tiene sus propios fundamentos, basados en premisas diferentes, siempre intentando cumplir cada una de las premisas dadas. No obstante podemos citar los Hash criptográficos más usados a día de hoy, como pueden ser: MD4, MD5, RIPEMD, SHA-1, SHA-256, SHA-512. Por supuesto existen muchos otros, aunque menos usados. Posiblemente a muchos algunas de esos nombres les sea conocido.

Al cumplir las premisas citadas, los Hash criptográficos suelen ser usados de forma intensiva en los siguientes campos:

  • Comprobaciones de archivos
  • Firmas digitales
  • Tablas Hash
  • Integridad de un mensaje/contenido


Dado que un Hash puede ser usado para detectar errores en el envío y/o recepción de los datos, un Hash criptográfico puede ejercer función de Comprobador de archivos. Mientras que CRC o checksum suelen aplicarse normalmente a porciones de código, tramas en las comunicaciones, pequeños detectores… este tipo de hash en realidad no se diseñan como correctores de errores o para que el contenido sea reenviado si no es correcto. Este tipo de Hash se suelen aplicar sobre un archivo completo (o conjunto de ellos). Para estos Hash, no importa lo grande o pequeño que sea el dato a verificar (pensado especialmente para grandes cantidades de datos en comparación con CRC o checksum claro está).

Comprender su función en este caso es simple. Al contenido original se le apluca un Hash criptográfico el cual se adjunta al software/archivo original. Cuando el receptor lo descarga, tiene acceso a él… solo tiene que calcular el mismo el mismo Hash y comprobarlo con el Hash que ha sido descargado desde la fuenta original. La idea es que sl el hash es el mismo, tenemos la certeza de que el archivo no se ha corrompido por el envío y la recepción ha sido satisfactoria. Por un principio similar, se puede verificar la integridad y veracidad de dicho archivo, que no ha sido modificado por nadie, que es legítimo. Podemos afirmar esto dada las propiedades ya vistas de este tipo de Hash: La imposibilidad de poder encontrar o crear otro archivo que pudiese coincidir con el hash del archivo original, y por otro lado no sería posible modificar el contenido del archivo sin alterar el hash que se calcularía en el destino.

Ver esto es muy fácil con algunos ejemplos. Tan solo tenemos que buscar un software que sea distribuido por razones de seguridad con su hash. En este caso vamos a usar por ejemplo la imagen de Windows 7 x64 Ultimate ENG. Imaginad que no te quieres molestar en ir a la tienda y encuentras un vendedor supuestamente autorizado que te permite descargar una copia de la imagen de Windows 7 (la misma que he expuesto ahi). Pero claro… quieres asegurarte de que la imagen sea legítima, y no sea una imagen modificada a la que se le haya puesto una activación o algún crack para poder instalarla. Solución? Conocer el Hash de la imagen legítima. Me pongo en contacto con Microsoft o investigo un poco para conocer el Hash de la imagen original y lo que obtengo es lo siguiente:

Windows 7 Ultimate x64 ENG: 7600.16385.090713-1255_x64fre_client_en-us_Retail_Ultimate-GRMCULXFRER_EN_DVD.ISO
MD5: F43D22E4FB07BF617D573ACD8785C028
SHA-1: 326327CC2FF9F05379F5058C41BE6BC5E004BAA7

Lo único que se debe de hacer en este caso es verificar si los valores que yo obtengo al calcular el hash son esos o difieren. En teoría con el cálculo de uno de ellos es suficiente. Para hacer esto se puede usar por ejemplo la utilidad md5sum sha1sum:

E:\Windows 7 Ultimate Final (EN-DE-JP-AR)>md5sum 7600.16385.090713-1255_x64fre_client_en-us_Retail_Ultimate-GRMCULXFRER_EN_DVD.iso
f43d22e4fb07bf617d573acd8785c028 *7600.16385.090713-1255_x64fre_client_en-us_Retail_Ultimate-GRMCULXFRER_EN_DVD.iso

E:\Windows 7 Ultimate Final (EN-DE-JP-AR)>sha1sum 7600.16385.090713-1255_x64fre_client_en-us_Retail_Ultimate-GRMCULXFRER_EN_DVD.iso
326327cc2ff9f05379f5058c41be6bc5e004baa7 *7600.16385.090713-1255_x64fre_client_en-us_Retail_Ultimate-GRMCULXFRER_EN_DVD.iso

Si dicha imagen hubiese sufrido cualquier tipo de modificación el resultado sería muy diferente. Por ejemplo, si a la imagen le modifico simplemente el primer bit (que es un “cero”, y lo establezco a “uno” con un editor hexadecimal) y le recalculo el hash MD5, esto es lo que obtengo:

4420bc0022a2ca8a361111b7a4d24ea7

Es decir, modificando tan solo un bit, el hash es completamente diferente. Por los mismos principios sería en la práctica imposible modificar aleatoriamente (o a conciencia) los bits de forma que pudiese obtener el mismo hash. Y he dicho en la práctica por una razón concreta que ahora veremos.

Vamos a suponer el caso concreto del Hash MD5. El Hash MD5 es un hash de 128 bits, lo que significa que cualquier contenido al que se le aplique este hash, se obtendrá una salida de 128 bits, una cadena de 32 caracteres hexadecimales. Es decir, sin entender siquiera de paradojas o estadística, podríamos afirmar que podríamos obtener un máximo de 2128 posibles hash. Esto es un número un tanto ingente, tanto que posiblemente una mente no es capaz de cuantificar, hablamos de 3.4 * 1038 es decir… 34 con 37 ceros a su derecha. Pero aun cuando este número es mentalmente imposible de imaginar, si es posible de imaginar que en el peor de los casos, cada ese número de hash calculados estos se volverán a repetir, lo cual implica evidentemente que sería teóricamente posible encontrar dos archivos exactamente con el mismo hash. Esta afirmación en realidad no rompe los esquemas vistos, dado que no se “rompe” la veracidad al decir que es improbable modificar un archivo para obtener un hash concreto o encontrar ese segundo archivo que verifique dicho hash. Aunque teóricamente esto es posible, aun cuando solo fuese de forma estadística.

Este es por tanto uno de los principales problemas de los hash criptográficos, y a esto se le llama colisión. Al margen de lo bueno o malo que sea el Hash, estadísticamente es posible encontrar dos hash iguales. En este caso concreto visto, aunque es posible teóricamente, en la práctica si el Hash está bien diseñado sería imprácticable. Cuanto tiempo necesitaría un PC en ser capaz de encontrar una colisión? Pues haciendo números muy por encima… 15 * 1010 años en el supuesto de que toda la población mundial tenga un procesador de 4 núcleos trabajando al mismo tiempo en la misma tarea 24 horas al día. Es decir… en el peor de los casos sería virtualmente imposible.

El problema es que esta lógica no es así. Cuando se habla de una colisión en un hash hay que recordar la llamada “Paradoja del cumpleaños”. Cabe señalar de nuevo que es muy diferente encontrar un contenido que verifique un hash concreto a encontrar dos contenidos disferentes que posean un mismo hash. Lo segundo es una colisión. Es cierto que para el primer caso la probabilidad sería la ya citada, pero no para el segundo caso, y aquí aparece lo que puede parecer increible: La paradoja del cumpleaños establece que en una habitación con 23 personas, existe un 50% de probabilidad de que dos personas cumplan años el mismo día, y si fuesen 60 personas la probabilidad sería del 99%. No hay truco, simplemente se busca una coincidencia entre cualquiera de las 23 personas, no una coincidencia concreta dentro de las 22 restantes. Teniendo esto en cuenta, MD5 posee tan solo 232 posibilidades de encontrar una colisión. Es decir, 4294967296 hash calculados de 4294967296 archivos aleatorios, estadísticamente debería de existir alguna colisión, es decir, dos archivos diferentes que poseen el mismo hash. Y es evidente que este número si que es comprensible y relativamente bajo, dado que un PC normal podría generar colisiones de hash MD5 con relativa facilidad, y esto comenzaría a invalidar los puntos en los que se asienta un Hash criptográfico. Es por esto que MD5 ha dejado de considerarse un Hash seguro, y es solo cuestión de tiempo que quede en desuso, a favor de otros Hash más seguros.

En teoría cualquier Hash debería de presentar posibilidad de Colisión, aunque es evidente que si esta probabilidad es computacionalmente imposible, podemos afirmar que no existe colisión (aunque teóricamente exista). Para tener presente esto, pensar que al Hash MD4 es posible encontrarle colisiones con tan solo en 256 hash.

A raiz de las Colisiones, aparecieron las primeras herramientas que han empezado a romper del todo el Hash MD5. A día de hoy existen herramientas capaces de generar dos programas diferentes que satisfagan el mismo Hash MD5, con lo que se rompe la seguridad de MD5 para la verificación de integridad y comprobación de un contenido. Es evidente que esto tiene matices. A día de hoy continua siendo imposible generar un contenido nuevo que satisfaga un hash buscado (lo cual rompería de forma definitiva el Hash). Pero en cambio si es posible producir dos archivos o dos contenidos que satisface el mismo hash. Esto quedó de manifiesto por el doctor Xiaoyun Wang, el cual incluso liberó el código de una aplicación que es capaz de realizar esto (En la cabecera de este artículo se puede encontrar)

SHA-1 es el segundo Hash más usado a día de hoy. A diferencia de MD5 (aunque basado en sus mismos principios) es un hash de 160 bits, al cual se le ha podido establecer un índice de colisiones de 252 en el mejor de los casos. En dicho caso el cálculo de una colisión sería relativamente práctica de llevar a acabo, quizás un año o dos años en poder lograr encontrar dos contenidos que compartan el mismo hash. No obstante se le continúa considerando seguro.

SHA-2 (conocidos como SHA256 y SHA-512) funcionan de forma muy similar a SHA-1, anque en este caso producen salidas de 256 y 512 bits respectivamente. En ambos casos no se conocen colisiones posibles.

Ante todo esto y dado que podemos asumir que tanto MD5 o SHA-1 son algo así como estándares, ya está en marcha el nuevo “concurso” que será seleccionado como sucesor de SHA-1/SHA-2 y que posiblemente será el próximo estandar en Hash dentro de un par de años. Actualmente se ha comenzado la segunda ronda, y a final de este año debería de quedar todo más o menos finalizado. La idea es encontrar un Hash más seguro y que sea muy eficiente su cálculo ,es decir… la velocidad con la que se pueda calcular el hash a un contenido. Se puede acceder a una lista de todos los candidatos de la segunda ronda en la web oficial del NIST (Instituto nacional de estándares y tecnología)

 

El último uso que deberíamos explicar son las Tablas Hash. Antes de entrar en detalle sobre este tipo de prácticas sería más correcto hablar antes de la Sal o Salt (en inglés). Hasta ahora hemos visto funciones de los Hash criptográficos para comprobar la integridad de los archivos, pero ¿que sucede si queremos usar un Hash como una especie de “encriptador” de contenido? Esto podría no tener mucho sentido dado que cualquier persona puede calcular un hash MD5 por ejemplo a cualquier entrada… pero en cambio no es posible partir del hash para obtener el contenido. Esto adquiere mucha más relevancia cuando se usan un hash para proteger detrás de él un contenido pequeño como un nombre de usuario o una contraseña, y es aquí donde aparece el término y la idea de Salt. Salt es un apéndice que se añade a una cadena de entrada para generar un Hash no intuituvo

Dentro de la web, las cookies y otros contenidos que puedan ser sensibles de cara al exterior como nombres y contraseñas puede ser sometido a un hash criptográfico para esconder su “significado” original. Esto nos dará como resultado una salida “única”, con lo que se podría usar dicha salida como contraseña y nombre del usuario de cara a un servidor, en vez del texto plano. Esto incrementa de forma exponencial la seguridad de cualquier base de datos o sistema de control de acceso. Pero como hemos dicho la utilidad de esto podría ser relativa. Vamos a ver esto con 3 ejemplos que ilustrarán la eficacia o no eficacia de un Hash para estos procesos, así como la implicación de Salt:

Imaginemos que hemos robado un archivo que guarda las credenciales de acceso a una importante base de datos. Imaginemos que dichas credenciales pueden ser almacenadas en dicho archivo como texto plano, MD5 y MD5+Salt. Si abrimos ese documento encontraríamos esto para cada una de las opciones:

1º. Nombre: Theliel Contraseña: perico

2º. Nombre: 5A04B2D961488CDA31CD065F259783BE Contraseña: DFE483413E24A5B1506389D36EBFD05C

3º. Nombre: 217B11413677EE9D4806967515D66607 Contraseña: 8E50E5A474DDAF3BC370F87DD97EC7F0

En el primer caso, es evidente que si está configurado como texto plano, las credenciales serán tomadas de forma directa y rápidamente podremos acceder a la base de datos.

En el segundo caso no obstante n oparece que sea posible descifrar absolutamente nada… ¿pero que pasaría si hacemos uso de la inteligencia? Podemos intuir que es un hash, y si buscamos información del sistema podemos incluso conocer que se trata de un Hash MD5. No podemos revertir el MD5 (a priori), pero en cambio si podemos presuponer el nombre de usuario y ver si hay una coincidencia con el hash que tenemos. Dado que el atacante es listo, comenzaría por cotejar en un diccionario que ya tiene el hash. Su diccionario no es más que una lista precalculada con quizás millones de posibles nombres de usuarios a los que ya se les ha calculado el hash correspondiente. Si el hash se encuentra en su diccionario, obtendrá de forma automática le nombre de usuario. Esto mismo se puede aplicar a la contraseña. Que usuarios se probarán primero? Admin, admin, theliel, Theliel… y en este caso, el diccionario encontraría que dicho hash corresponde a la palabra “Theliel”. En caso de la contraseña es exactamente igual, si la palabra o frase empleada en la contraseña existe en su diccionario, obtendrá directamente la contraseña buscada. Es por ello que siempre es importante tener una contraseña alfanumérica de una longitud decente.

En el tercer caso la cosa es más complicada. El atacante agotaría todos sus diccionarios y no lograría encontrar el hash deseado. ¿Por qué? Porque lo que no sabe el atacante es que el programa que codificó el hash usó una Salt, un trozo de datos que simplemente añadió al final del usuario y la contraseña. Así si el usuario escribió el nombre de usuario: “Theliel”, el servidor jamás lo tomó como tal, sino que automáticamente le añadió el Salt “TATA” (en este caso). Es decir, de cara al servidor cualquier dato introducido es concatenado con “TATA”. Así, el servidor no calcularía el hash de “Theliel” o de “perico” (la contraseña), sino de “ThelielTATA” y “pericoTATA”. dicha modificación es seguro que no aparecerá en su diccionario. La única opción del atacante es conocer la Salt usada por dicho servidor, y crear así un programa que automatice el proceso, recalculando todos los hash de su diccionario con la Salt aplicada y así con suerte obtener algún resultado. Esto lo trataremos mejor cuando se vean las diferentes técnicas para romper la seguridad.

Pero volvamos a las tablas Hash. Hemos explicado que la Salt o la importancia que puede tener un hash para “esconder” unos datos, pero ¿qué es una tabla hash? Dado que el índice de colisiones es relativamente alto, podemos presuponer que no será posible dar la casualidad de tener a dos nombres de usuarios que compartan el mismo hash. Si esto es cierto, para un servidor es mucho más seguro no guardar jamas en sus bases de datos el usuario o la contraseña como tal, solo sus Hash. Al introducir los datos el usuario, son sus hash los que alcanzan el servidor y este simplemente tiene que cotejar dicho hash (el usuario) en su base de datos para comprobar si existe una coincidencia. Si existe tal coincidencia verificar el hash de la contraseña con el hash de contraseña ya almacenado. De este modo nuestros datos de sesión no serían jamás enviados como tales. Pero la utilidad de las tablas de hash radica no en la seguridad (que por supuesto también lo es) sino su eficiencia.

Hemos dicho que el servidor debería de verificar si el hash de nombre de usuario existe en su base de datos. ¿Pero como hace esto? Si nuestra base de datos posee 100 registros, en el peor de los casos la base de datos debería de hacer 100 comprobaciones, para acabar en el último registro que sería el que coincidiese con el hash del usuario introducido. Pero aun, si el usuario introducido no se encontrase en la propia base de datos, esta la habría recorrido entera buscando una coincidencia. Este proceso sería muy costoso para los servidores. Ahora bien, partimos de la premisa que el índice de colisión de un hash MD5 es relativamente alta, 4 mil millones aproximadamente. Podríamos calcularle simplemente el módulo a dicho Hash (en función del número de índices que tengamos en la base de datos), el resultado sería un número de 1 a X, siendo X el número de entradas posibles en nuestra base de datos. Es decir, pongamos que nuestra base de datos tiene 100 registros insertados y tiene una capacidad máxima de 997 (por ser un número primo). Es decir, se aplicaría la operación módulo 997 a cada hash de entrada. Esto convertiría todos los hash de entrada en un número que iría desde el 0 al 996. Este número sí podría ser usado como índice, luego el acceso al registro en la base de datos sería inmediato. Por razones de precisión, usar un número de 128 bits no es aconsejable, lo normal es acotar este número a una resolución de 64bits, tomando por ello los 64 bits primeros del hash o los 64 bits últimos de este. En el ejemplo anterior, al Hash “Theliel” se le aplicaría módulo 997, y el resultado sería: 5A04B2D961488CDA31CD065F259783BE -> 5A04B2D961488CDA MOD 997 = 763. Es decir, que el nombre de usuario Theliel sería convertido al índice 763 en la base de datos. De este modo, al introducir “Theliel” en el navegador, se calcularía el Hash, en el servidor se truncaría y daría como resultado un índice. Con este índice el acceso a la base de datos sería directo, “Acceso a elemento 763”. Asociado a dicho índice se podría encontrar por ejemplo el hash de la contraseña y se procedería a realizar una simple comparación, si los dos hash coinciden se obtiene el acceso.

Esto evidentemente multiplica exponencialmente la posibilidad de una colisión, dado que el espacio disponible ahora es de tan solo 997 elementos. Como hemos dicho la posibilidad de colisión dependerá en gran medida de la ocupación del espacio disponible. Por la paradoja del cumpleaños no obstante, se daría el caso que con unos 35-40 elementos introducidos la probabilidad de una colisión sería de un 50%!!. Para evitar esto se acude a tablas muco mucho mayores en relación al indice esperado de ocupación que se tendrá. Es decir, se sacrifica espacio en post de velocidad. En la Wikipedia aparece un ejemplo parejo, en el que se dice que con 2500 elementos introducidos en una tabla de un millón de elementos, la probabilidad de colisión ascendería al 95%. Que hacer en caso de colisión? Primero evitarlas, ya sean con grandes tablas o con crecimiento dinámico de estas. Por otro lado asumir que es posible que exista una colisión, y diseñar el sistema de forma que ante una colisión sea necesaria una segunda búsqueda en los registros afectados para determinar el destino final.

Seguridad: Spoofing. Índice (Actualizado)

Bienvenidos al tema de Hoy: Spoofing, el arte del engaño.

 

Spoofing es un término genérico que puede ser aplicado a un buen número de cuestiones en la red. Todos ellos comparten la misma premisa, por tanto podemos definir el Spoof o la técnica de Spoofing a la falsificación de unos datos, modificándolos de algún modo para obtener por ello un beneficio.

Lo que vamos a intentar hacer aquí es explicar los diferentes ataques de Spoofing que podemos encontrar a día de hoy, intentando mostrar ejemplos de uso real y por tanto como podemos evitarlos:

Herramientas Utilizadas/Material necesario: (No todo es necesario, dependiendo de la plataforma a usar, de cada Spoofing y de lo que a cada cual le sea más cómodo)

  • Windows 7 x64 Ultimate -> OS principal (General)
  • Debian Squeeze x64 -> OS secundario (General)
  • Firefox 3.7a2pre
  • Thunderbird 3.2a1
  • Servidores Whois RIPE, ARIN, APNIC, LACNIC, afriNIC -> También útil usar la linea de comando “Whois” (IP Spoofing)
  • Servidor Proxy anónimo con soporte SSL -> Cientos en Internet (IP Spoofing)
  • NMAP -> Escaner de puertos (IP Spoofing, MAC Spoofing)
  • Winpcap -> Librerías para Windows para capturar frames (IP Spoofing, MAC Spoofing, Header Spoofing)
  • Wireshark ->Sniffer (IP Spoofing, MAC Spoofing, Header Spoofing)
  • Cuenta de Correos Gmail (IP Spoofing, eMail Spoofing)
  • Cuenta de Correos Live/Hotmail (eMail Spoofing)
  • AirCrack Suite (Linux) (MAC Spoofing)
  • Servidor Web con soporte PHP o hosting con iguales características (Web Spoofing)
  • Cliente FTP: WinSCP, FileZilla… (Web Spoofing)
  • Web Spider: HtTrack, wget… (Web Soofing)
  • Apache, PHP (Web Spoofing)
  • NoScript, Cookie Monster, Firebug-> Extensiones para Firefox (Web Spoofing)
  • User-Agent Switcher, Firebug-> Extensión para Firefox (Header Spoofing)
  • Paros Proxy (Header Spoofing)
  • Ncat (incluido en NMAP) ó NetCat, Telnet… (eMail Spoofer)
  • OpenSSL (eMail Spoofer)
  • hMailServer (eMail Spoofer)
  • Dig (eMail Spoofer)

 

Sobre SMS Spoofing, he decidido posponerlo conjuntamente con la versión PDF. Continuaré con la publicación de artículos, y posiblemente sea al final cuando revise todo el material, lo compacte, lo ordene… y lo lance todo como dios manda.

Seguridad: Spoofing. Capítulo Quinto -> eMail Spoofing

ATENCION: Los ejemplos que se van a mostrar y “tutoriales” tan solo tienen carácter educativo. En ningún aspecto comparto filosofías de invasión a la intimidad, ataques contra un sistema informático o cuestiones similares. En la medida que sea posible siempre se usarán ejemplos y formas que puedan ser usados por cualquier persona, de forma que pueda verificar los contenidos escritos. No obstante, por motivos más que obvios, materiales como contraseñas, nombres de usuarios o de hosts, serán omitidos o modificado en las capturas de pantallas realizadas (o las lineas escritas). Es decir, los ejemplos serán completamente reales, los datos mostrados para poder pertrechar estos ejemplos  a vosotros, no siempre lo serán (Sí lo serán los resultados). Para que esto conste de forma clara, todo material sensible modificado o falso estará resaltado en ROJO. Por motivos de seguridad, todo el material que sea expuesto aquí (exceptuando software propietario o libre, citaciones expresas o código de terceros) tanto texto, imágenes y código son propiedad del autor y está completamente prohibido su reproducción completa o parcial en otros lugares, espero que se comprenda.

 

eMail Spoofing

Casi con toda seguridad, conjuntamente con Web Spoofing, es el Spoofing más usado y/o peligroso que podemos encontrarnos estos días. Por otro lado es el Spoofing posiblemente que más personas identifican y tratan con él, aun cuando quizás no sepan que se llame así. Y es que a día de hoy, quien no ha recibido un correo electrónico que parecía venir de él mismo o de cualquier otro usuario, sin que evidentemente fuese dicho usuario quien lo había enviado. Aquí no se debe de confundir eMail Spoofing con virus que usan nuestras cuentas para reenviarse a nusetros contactos. Un virus en nusetro PC que se expande por correo electrónico usando nuestras propias herramientas, no es Spoofing.

¿eMail Spoofing? La técnica de modificar (generalmente) el remitente de un correo electrónico, con el fin de aparentar se un correo electrónico genuino. Esto evidentemente es una suplantación de identidad en toda regla, y es algo completamente ilegal. Para hacerse una idea, clonar una web (Phising) con el objetivo de engañar a alguien para que introduzca unos datos es ilegal porque casi con toda seguridad no tiene derechos de autor para usar el contenido de la web original. Pero nadie puede denunciarte porque una persona sea “estúpida” e introduzca unos datos en una web. En cambio, falsear un correo de forma que el remitente sea suplantado es ilegal. Al menos en españa, es ilegal la suplantación de identidad. Evidentemente el daño que puede causar este tipo de Spoofing es ingente en todos los ámbitos.

Esto crea por ende un debate moral sobre si este tipo de artículos deberían de ser escritos o no. La razón es evidente… de cada 10 personas que puedan leer este artículo, casi con toda seguridad más de la mitad no les importaría poner en práctica lo que aquí se pueda explicar para hacer uso de dichos conocemientos/formas. Similarmente al Phishing, eMail Spoofing es un problema más que real. En la medida que pueda intentaré llevar un compromiso entre lo que es informar y lo que pueda ser dar pautas exactas de como un lector malintencionado podría hacer cosas que no deberían de hacer. Aunque evidentemente no soy el padre ni la madre de nadie. Eso sí… estas prácticas son completamente ilegales y son delito penal. Más vale no jugar con este tipo de técnicas.

Ahora que hablamos de eMail Spoofing, deberíamos de hacer aparecer el término SCAM. En realidad, lo que hemos llamado Phishing anteriormente (a crear una web fraudulenta) lo más correcto es llamarlo SCAM, y llamar Phishing a la suplantación de identidad, generalmente debida al eMail Spoofing. He usado anteriormente Phishing para referirme a la web falsa puesto que el matiz de SCAM es la realización de un Phishing con fines fraudulentos. En mi caso no podría decirse que es un SCAM, dado que tan solo tiene fines didácticos. De cualquier forma ambos términos se suelen cruzar indistintamente, aunque personalmente para mi, la suplantación de identidad por eMail sería realmente el Phishing y el SCAM el Web Spoofing cuando se desea engañar a los usuarios para robar su información. De todos modos visto esto, aquí no voy a hablar de Phishing para no confundir a los lectores, solamente de eMail Spoofing, pero lo explico porque al final de todo hablaremos de Phishing.

Como hemos dicho en otra ocasión, el problema de estos sistemas y/o ataques no reside en que Internet sea más o menos segura, sino en la intención de cada persona. Si diseñas una tecnología basada en la censura y en el recorte de libertades tendrás posiblemente un sistema mucho más seguro… pero que llega a infinitamente menos personas, erradicas la libertad. Internet por ahora (y espero que siempre) es un lugar libre, de tal forma que todo el que quier puede formar parte y construye esa Internet, sin pasar por gobiernos ni leyes absurdas. Esto implica que la mayoría de todos los protocolos en Internet son en su mayoría simples y pensados para ser usados por cualquiera, no están pensados para restringir las libertades, y eso produce que siempre existirán personas que quieran aplicar la tecnología para fines nada éticos o siquiera legales.

Antes de entrar en detalles, hay que comprender como se puede enviar un correo electrónico a Internet. Aunque para muchos un eMail no es más que un texto escrito en el ordenador y enviado a través de nuestro navegador gracias a los portales de Gmail o Live, los correos electrónicos son mucho más que todo ello. SMTP es el responsable de los correos electrónicos, es el protocolo que hace posible este envío de información. La mejor forma de comprender el sistema de eMail, es asimilarlo siempre al correo postal ordinario. Cuando enviamos una carta a un destinatario necesitamos conocer antes que cualquier otra cosa la dirección de dicha persona, su nombre y apellidos, código postal… y del mismo modo escribir un remitente (si queremos) en el sobre. Pues el eMail es exactamente igual, vamos a ver como podrían ser las equivalencias:

 

Correo Ordinario ————————————————–> Correo Electrónico

Destinatario: Nombre y Apellidos ——————————> Destinatario: Nombre y Apellidos (Por ejemplo: Theliel Smith)

Dirección: Calle y Número/bloque —————————–> Dirección: UserID y Realm (Por ejemplo: eMailSpoofing@Theliel.es, eMailSpoofing es el UserID y @Theliel.es el Realm)

Código Postal ——————————————————-> Registro MX en las bases de datos DNS (Por ejemplo: smtp.europe.secureserver.net)

 

Remitente: Nombre y Apellidos ———————————> Remitente: Nombre y Apellidos (Por ejemplo: Sandra Smith)

Dirección Remitente ———————————————–> Dirección: UserID y Realm (Por ejemplo:Sandra@live.com, Sandra es el UserID y @live.com el Realm)

Código Postal Remitente ——————————————> Servidor SMTP (Por ejemplo: smtp.live.com)

 

En realidad como se puede apreciar es simplemente llamar a cada cosa de forma diferente y comprender el esquema básico de esto. Cuando se comprende, se comprende igualmente los fallos de seguridad que podría tener el esquema, pero como digo, no se planeó que fuera un sistema rígido y restrictivo, sino abierto. Esta imagen tomada de la Wiki nos muestra más o menos el proceso:

Anque la jerga pueda ser complicada, es igual que si fuera un correo ordinario. Digamos que Alice quiere enviar un correo ordinario a Bob. Para ello rellena los datos en la carta y la tira al buzón. El cartero la lleva a la oficina postal de su localidad, es decir, la oficina que corresponde al código postal del remitente, que en un correo electrónico correspondería a su servidor SMTP. Una vez en la oficina, esa carta debe de ser procesada para saber su destino. Se comprueban los datos del destino (es decir de Bob), para conocer el destino del código postal escrito en la carta (o la entrada MX en caso de un correo electrónico). El ordenador devuelve al operario la oficina a la que deben de enviar dicha carta, es decir… la dirección de la oficina de correos que se encarga de dicho código postal. En el caso de un corro electrónico el ordenador que procesa dicha información se llama servidor DNS. Una vez que el operario de la oficina postal tiene los datos de a qué oficina enviar la carta (no a que dirección del usuario final) llama al transportista y envía todas las cartas para dicha oficina. En Madrid llegan todas las cartas destinadas a dicha oficina (paso 4 del gráfico). En dicha oficina se verifican las direcciones físicas de los destinatarios para comprobar que no hay errores y el cartero las repartirá de forma correcta. En el caso de un correo electrónico vemos que es exactamente lo mismo, los datos llegan al servidor que gestiona el servicio de correo electrónico del destino, este procesa el correo y lo entrega en la bandeja de entrada de su usuario.

No perdamos de vista el objetivo de esta parte, eMail Spoofing. En el esquema que acabamos de explicar y pensando en la suplantación, ¿Como podríamos modificar el remitente en una carta ordinaria? Es facil, tan solo escribiendo unos datos falsos en el remite de la carta. Con el eMail pasa exactamente lo mismo. ¿Pero entonces es así de simple? Sí y no, como de costumbre.

  • En primer lugar prácticamente ningun programa nos permitiría modificar el remitente del eMail.
  • En segundo lugar en los servidores SMTP existne medidas de seguridad para evitar el SPAM. Siguiendo con la misma analogía, imaginar que yo he puesto de remitente a Julia Robert con residencia en estados unidos. Cuando la carta la recoge el cartero imaginar que mira el remitente y ve algo así. El operario podría automáticamente romper la carta, puesto es imposible que el haya podido recoger una carta del buzón con tal dirección en su oficina postal. Es decir, un método de desechar esos correos fraudulentos sería automáticamente bloquear cualquier remitente que no pertenezca su nombre y apellidos, dirección y código postal de la oficina que recoge la carta. Esta medida es usada casi en el 100% de los proveedores de correo electrónico, de modo que con dicha protección, sería imposible pretender enviar un correo fraudulento usando un servidor SMTP concreto el cual no reconoce el remitente como legítimo.
  • En tercer lugar, la oficina podría ser aun más lista, y simplemente solicitar el carnet de identidad de cada persona que desea enviar una carta. Una vez se presenta el carnet de Identidad, es la misma oficina quien graba el remitente en la carta. Este otro sistema es también ampliamente usado con los correos electrónicos (evidentemente en similitud, no literalmente)

Es decir, aunque el protocolo inicial es simple, a raiz de sus más que normales carencias se han construido filtros y sistemas de seguridad para evitar el uso de la suplantación de identidad. Con todo esto se podría pensar que entonces no es posible realizar un eMail Spoofing, y todos sabemos que no es cierto. ¿Con todas estas medidas es posible realizar eMail Spoofing? Si, y existen 3 formas (que ahora mismo pueda pensar yo). Todas ellas tienen sus pros y sus contras. Antes de entrar en ellas vamos a explicar un poco que es un servidor SMTP relay.

Originalmente, no se contemplaba como hemos dicho problemas de suplantaciones de identidad ni cuestiones similares, y existian los llamados Servidores Relay abiertos. Dado que cualquier persona puede crear un servidor de correos, este servidor de correos se puede configurar como hemos dicho como se desee. Estamos acostumbrados a ver que nuestros servidores SMTP de gmail o de Live requieren de un nombre de usuario o una contraseña. Pero si se desease, podríamos crear un servidor de eMail que no requiriese autentificación de ningún tipo, y simplemente especificásemos remitente y destino (el que quisiésemos). Años atrás, estos relays abiertos eran muy comunes, el problema que tenía por tanto era que cualquier persona podía enviar correos desde estos servidores para crear cantidades ingentes de SPAM. Ante este problema, casi todos los proveedores de eMail actuaron bloqueando en listas negras los correos que proviniesen de ciertos servidores Relay abiertos. Esta fue la primera medida que se comenzó a tomar, y tal es el efecto que a día de hoy no estoy seguro de que quede algún servidor SMTP relay abierto.

Sin embargo, la posibilidad de poder modificar el destinatario de un correo no solo es negativo, muchas veces es una función necesaria. Imaginar por ejemplo cuando tenemos la propiedad de dos cuentas de correos diferentes y preferimos usar un solo servidor SMTP para ambas. Por ejemplo esto lo permite realizar gmail previa verificación de dirección de correo. Otro ejemplo clásico es alguna suscripción a algún servicio, y este servicio envía correos electrónicos directamente a nuestro nombre para que el destinatario pueda siquiere incluso con “responder” alcanzar nuestra dirección. Aun así, existen multitud de ocasiones en las que es deseable poder modificar los remitentes. Ante esta necesidad comenzaron a aparecer los servidores Relay cerrados.

A diferencia de los Relay Abiertos, los Relays cerrados son actualmente los servicios de correo electrónico que con más frecuencia nos son ofrecidos. Muchos quizás no comprendan la diferencia entre un servidor SMTP Relay y no Relay. Cuando usamos el término de Relay, nos referimos a un servidor SMTP que acepta conexiones teóricamente de cualquier usuario. Si pensamos por ejemplo en el servidor SMTP de Gmail: smtp.gmail.com, no deja de ser un servidor Relay, puesto que el mismo servidor SMTP es el que usan todos prácticamente. Lo que sucede es que es un Relay cerrado, con ciertas restricciones. Pero igualmente podemos encontrar servidores SMTP puros, dedicados. El ejemplo más clásico de estos servidores son algunos servidores de correos empresariales o particulares. Normalmente cualquier persona que posea un dominio o un servicio de hosting, puede crear su propio servidor SMTP sin necesidad de un servidor Relay (aunque se puede configurar como tal)

A día de hoy como se ha dicho, la mayoría de los servidores SMTP son relay, y cada uno implementa las medidas que cree necesarias. Por ejemplo, un servidor SMTP relay de una empresa lo normal es que permita el relay local-> local local -> Internet y bloque por defecto cualquier intento de acceso tipo Internet -> Internet Internet -> Local. Es decir, permite a los usuarios dentro de la propia red empresarial a enviar correos, pero dicho servidor relay está bloqueado externamente. Otro ejemplo sería gMail. Gmail permite el acceso local -> local local -> Internet Internet -> Local e Internet -> Internet. Pongo el ejemplo de Gmail a conciencia… si permite todo tipo de usos… ¿no debería de ser un servidor Relay abierto? No. Desde la época de los relay abiertos, muchos proveedores decidieron otra medida, rechazar todos aquellos correos que no realicen proceso de autentificación en su servidor de correos SMTP. Para el servidor destino es facil comprobar esto, tan solo tiene que realizar una conexión a nuestro servidor y comprobar si se requiere o no. La mayoría de los proveedores no permiten circular por sus redes correos que no han sido autentificados, o añadidos a una “lista blanca”. ¿Y que es la autentificación? Ni más ni menos las credenciales que necesitamos para poder enviar o recibir correos. Existen aun muchos servidores SMTP relay los cuales no es necesario realizar una autentificación, pero tienen filtros que impiden el relay de sus servicios Internet – > Internet Internet -> Local. Aunque todo esto suene un poco complicado, todo cobrará sentido más adelante con los ejemplos.

Veamos ahora sí las tres formas que podemos encontrar de eMail Spoofing:

 

Servidor de Email propio:

Como hemos dicho Internet es libre. Tu puedes agradecer a Gmail su servicio gratuito de Internet, pero también te sometes a sus políticas de Spam, a sus restricciones, a sus filtros… a fin de cuentas gMail es tu oficina de correo postal. Pero si internet es libre… ¿puedo construir un servidor de correos yo mismo? Sí. Es decir, es como si pudieses crear tu propia oficina postal. Al ser tu servidor, tu eliges las normas. Internet la construimos todos, el protocolo SMTP es estandar y cualquiera puede usarlo. Por tanto podríamos crear un servidor SMTP en casa y arreglarlo todo de tal forma que prácticamaente podríamos enviar correos desde el remiente que quisiésemos. ¿Por qué? Ya lo hemos dicho, nosotros decimos las normas que queremos. Ojo!! esto no quiere decir que los correos sean completamente anónimos ni mucho más lejos.

Vamos a expandir esto un poco más. Si hemos comprendido el esquema de funcionamiento de un eMail, para crear nuestro propio servidor lo que hay que hacer sería primero crear nusetra “oficina”. Lo segundo para que nuestra oficina sea localizable tener en las bases de datos mundiales nuestro código postal registrado, en nuestro caso, tener registrado nuestro MX en los servidores de DNS. Y nada más.

En realidad no es necesario tener un registro MX si no deseamos recibir correo, el problema de este sistema es que por razones de seguridad y propensión a usar SPAM con estos sistemas muy simples de crear, la mayoría de los servidores destino no permiten correo procedente de aquellos clientes que no posean un registro MX o que procedan de IPs que sean estáticas. Por lo demás todo es muy simple. Tan solo sería cuestión de usar cualquier software servidor de correos, configurarlo y listo. No voy a explicar a hacer esto paso a paso, en este caso tan solo vamos a ver los resultados, pros y contras. En mi caso he usado hMailServer, un servidor de correo gratuito.

Para este primer ejemplo de eMail Spoofing se ha usado el servidor eMail citado. En cada una de las pruebas siempre se han enviado dos copias de los correos con remitentes falsos, una a gmail y otra a live (hotmail). En una de las pruebas se optó por usar una dirección falsa de Hotmail y en el otro caso una dirección falsa de gmail. El tercer test se optó por una dirección prueba test.com.

Los resultados son interesantes, y demuestran puntos a favor y en contra de cada proveedor (gmail y hotmail) a la hora de manejar posibles suplantaciones de identidad. Evidentemente tanto la cuenta de correo theliel@gmail.com y theliel@hotmail.com, no me pertenecen.

 

Prueba 1: Remitente theliel@hotmail.com, destino mis cuentas de gmail y live:

Gmail en este caso si permitió el acceso del correo y este alcanzó la bandeja de entrada.

Hotmail permitió la recepción pero fue filtrado una vez más como Spam -> Ver notas después de las pruebas


Prueba 2: Remitente theliel@gmail.com, destino mis cuentas de gmail y live:

Gmail no permitió siquiera la entrada del correo, dado que verificó que el remitente theliel@gmail.com tan solo podía enviar correos usando el servidor SMTP de gmail, y no uno externo. El correo no llegó a abandonar mi gestor de correos.

Hotmail permitió la recepción del correo, pero en este caso llegó como Spam -> Ver notas después de las pruebas

 

Prueba 3: Remitente theliel@test.com, destino mis cuentas de gmail y live:

Gmail filtró el primer correo como Spam, pero sucesivos correos del mismo destino alcanzaron la bandeja de entrada

Hotmail lo volvió a filtrar como Spam -> Ver notas al final de las pruebas.


Live Spam



Gmail Inbox


En principio se podría pensar que Live tiene un filtrado de Spam mejor que Google. Pero esto esto tiene muchas lecturas. Efectivamente Gmail rechazó de pleno un supuesto correo de gmail (theliel@gmail.com) simplemente presuponiendo que un correo de ellos tiene que provenir de ellos. Pero fracasó en las otras dos pruebas, dando por buenos los correos con los remitentes falsos. Por otro lado Live los categorizó todos como Spam.

Cada proveedor tiene sus propias políticas de que es mejor filtrar o que no. Por ejemplo, es evidente que el correo Theliel@hotmail.com era un remitente suplantado, pero Gmail prefirió no establecerlo a priori como Spam, lo que causa que en ese aspecto debemos de suspender a Gmail. Pero por otro lado bloqueó completamente Theliel@gmail.com. Live por su parte prefirió no bloquear completamente el correo que provenía supuestamente desde sus propios servidores “Theliel@hotmail.com”, lo cual es un punto negativo para Live. No obstante fue capaz de filtrar los otros dos correos falsos.

La política por defecto de Gmail es “Ante la duda, lo permito”. La política de Hotmail es “Ante la duda lo bloqueo”. Esto no solo es una cuestión de políticas por desgracia… sino de dinero. Microsoft con Live presupone que no puedes o no debes de tener un servidor de eMail en tu casa a menos que seas una empresa. En realidad a Microsoft no le importa el remitente del correo, no los detecta como Spam por ello. Si detecta que posees una IP dinámica ellos presuponen que eres un Spammer. Por otro lado, puedes pagar a Microsoft un dinero para que categoricen tu dominio como verificado, para que no sea filtrado como Spam. Esto parece injusto, ya que si Internet es libre, cualquiera podemos querer tener un servidor de Email sin dar cuentas a nadie, y no por ello somos unos Spammers. Google presupone inocencia, y mientras no tenga más datos sobre el origen de dichos correos no lo categoriza como Spam y lo permite, eso sí… bloquea los correos que no proceden de sus servidores y que es de ellos… cosa más que normal.

A todo esto hay que sumarle un gran problema de seguridad respecto al Spam que tiene Live. Quitando alguna que otra dirección, siempre se pasará a la bandeja de entrada (y no se considerará Spam) correos de direcciones que ya se han recibido. Es decir, supongamos que en realidad Theliel@hotmail.com ó Theliel@gmail.com fuese la dirección de un amigo mío y en mi cuenta live ya tuviese algún correo de ellos, ninguno de los dos correos sería filtrado como Spam. Esto es un peligro. Esto es posible pq Live presupone que los correos no marcados como Spam, son remitentes seguros.

En realidad no podemos ni debemos darle un tirón de orejas a ninguno. Cada cual implementa las políticas que creen más acertadas para filtrar la mayor cantidad de Spam posible y no filtrar los correos que crean que son legítimos. Pero como en todo, no hay un sistema que sea realmente mejor que otro.

Este sistema de eMail Spoofing se ha podido ver cuales son sus principales deficiencias. Si bien es algo sencillo y rápido de pertrechar, es muy fácil que cualquier proveedor de servicios pueda detectarnos. Por supuesto, y aunque no haya sido comentado, detectar un usuario este tipo de ataques de eMail Spoofing es muy simple, tan solo tendríamos que acudir a la cabecera del correo entrante:

Delivered-To: xxxxxxx@gmail.com
Received: by 10.103.197.9 with SMTP id z9cs22623mup;
        Sun, 7 Feb 2010 10:54:05 -0800 (PST)
Received: by 10.103.85.4 with SMTP id n4mr3722461mul.128.1265568845523;
        Sun, 07 Feb 2010 10:54:05 -0800 (PST)
Return-Path: 
Received: from localhost (30.Red-79-158-250.staticIP.rima-tde.net [79.158.250.30])
        by mx.google.com with SMTP id u26si17461538mug.45.2010.02.07.10.54.05;
        Sun, 07 Feb 2010 10:54:05 -0800 (PST)
Received-SPF: softfail (google.com: domain of transitioning Theliel@hotmail.com does not designate 79.158.250.30 as permitted sender) client-ip=79.158.250.30;
From: Theliel 
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; es-ES; rv:1.9.1.7) Gecko/20100111 Lightning/1.0b2pre Thunderbird/3.0.1
MIME-Version: 1.0
Subject: Test
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Prueba 1

Se puede apreciar perfectamente la IP origen de dicho correo, así como la resolución inversa de ella, que se aprecia claramente como proviene de telefónica. Por otro lado se puede ver el registro de Google sobre si es SPAM o no lo es. Si leemos lo que nos dice, es un aviso. El host citado no está designado como un emisor permitido.

 

Servidor Relay SMTP Sin Autentificación

La segunda opción y posiblemente la más usada a la hora de realizar eMail Spoofing, reside en los servidores Relay. Hemos dicho que prácticamente todos los servidores Relay tienen fuertes medidas de protección para evitar el Spam o la suplantación de identidad. Como hemos dicho a día de hoy continua siendo necesario el papel de los servidores Relay en los cuales NO EXISTE autentificación previa. Lo que sucede es que estos servidores están disponibles normalmente tan solo a grupos de clientes que pagan por usar dichos servicios como servicios de email o de hosting, y normalmente con un número determinado de correos diarios permitidos. Por otro lado, generalmente no se permite su uso externo. El concepto de local o internet se debe de comprender. Si por ejemplo posemos un hosting que nos permite usar su servidor Relay e intentamos hacer uso de él desde nuestro propio equipo, pronto se dará cuenta cualquiera que la conexión es denegada, puesto que nuestro proveedor tan solo permite el uso del Relay en local. ¿Que implica esto? Que no podemos directamente hacer uso de dicho servidor, pero dado que en dicho servidor podemos tener herramientas como SSH, PHP… podemos crear formularios o accesos remotos para poder usar dichos recursos. La idea es claramente poder crear contenido web que nos permita la creación de formularios y otros que llamen a nuestro servidor relay. Dado que el formulario se encuentra en nuestro servidor web, podrá utilizar el servidor Relay de nuestro proveedor.

Esto tiene una ventaja y un inconveniente. Al ser un servidor “abierto” (que no requiere de autentificación) podemos enviar cualquier correo que deseemos en nombre de quien sea sin preocupación alguna, y casi con toda seguridad el correo será entregado y no filtrado como Spam. ¿El problema? Es necesario crear un formulario web para ello o usar SSH para conexión remota o algún sistema similar. Para evitar este tipo de prácticas abusivas de Spam, normalmente existe como he dicho un número finito de correos que pueden ser enviados al día.

Tanto esta sección como la siguiente, realizaremos conexiones directas en terminal para mostrar los ejemplos, esto nos hará comprender de una forma mucho más clara como funciona SMTP y el potencial que tiene. Veamos ahora el uso y conexión de un servidor SMTP Relay sin autentificación. Cualquier respuesta por parte del servidor va antecedida con un código númerico. El resto de texto corre a cargo por el cliente, es decir… tecleado a mano. Recordar que en rojo se resaltará siempre datos modificados por cuestiones de seguridad.

theliel@Anarchy:~$ ncat -C smtp.relay.com 25
220 smtp.relay.relay.com ESMTP
EHLO TEST
250-smtp.relay.relay.com
250-PIPELINING
250 8BITMIME
Mail from:
553 sorry, your mail was administratively denied. (#5.7.1)
mail from: 250 ok
rcpt to: 553 sorry, relaying denied from your location [79.158.250.30] (#5.7.1)
quit
221 smtp.relay.relay.com Goodbye.

Como se puede observar, este servidor relay en concreto tiene una lista negra de hosts que no se pueden especificar como remitentes (a priori). Cualquier intento de crear un remitente gmail, live, hotmail… devolverá el error mostrado. No obstante en principio, cualquier otro host no tan “famoso” es completamente aceptable. Aun así esto no implica nada, ya veremos que el secreto último del Spoofing no se encuentra en la orden “mail from” del protocolo SMTP. Como se puede observar el servidor no solicita ningún tipo de autentificación (vendría listada como se verá más adelante). Por último podemos ver la protección de dicho servidor de no permitir conexiones externas. La IP mostrada es mi IP de telefónica en este momento, y el servidor la rechaza por ser una dirección externa a él. Es decir, para poder usar este servidor relay es necesario usarlo dentro de la misma infraestructura. ¿Como podemos realizar esto? Ya lo hemos dicho, o por medio de PHP y un formulario web por ejemplo, o quizás podamos realizar un telnet al servidor desde dentro del propio servidor mediante una conexión SSH:

-bash-3.2$ telnet smtp.relay.com 25
Trying xxx.xxx.xxx.xxx
Connected to smtp.relay.com (xxx.xxx.xxx.xxx).
Escape character is ‘^]’.
220 smtp.relay.relay.com ESMTP
EHLO TEST
250-smtp.relay.relay.com
250-PIPELINING
250-SIZE 30457280
250 8BITMIME
mail from: 250 ok
rcpt to: <xxx@gmail.com>
250 ok
data
354 go ahead punk, make my day
From: Theliel To: Theliel <xxx@gmail.com>
Subject: Test

Prueba relay
.
250 ok 1265487183 qp 5150 by smtp.relay.relay.com
data
503 MAIL first (#5.5.1)
quit
221 smtp.relay.relay.com Goodbye.
Connection closed by foreign host.

En esta ocasión, el servidor no devuelve un error dado que se está ejecutando en local. El servidor está protegido para que no se acepten identidades (mail from) desde Gmail, pero en cambio, en el mismo cuerpo del mensaje si es posible especificar el remitente con “From”, en el cual si es posible especificar gmail, live o la dirección que se desee. El correo mostrado es entregado a la perfección a la bandeja de entrada de mi cuenta gMail. En este punto hay que recordar algo que se comentó anteriormente. Muchos servidores no aceptan el paso de correos por sus servidores si este no está autentificado. En este caso estamos enviando un correo sin autentificación, lo cual quiere decir que existirán servidores que no permitan la recepción desde este tipo de servidores… este es el ejemplo de live. En realidad es un problema y una falta de respeto por parte de Microsoft, dado que esto es posible usarse con fines legítimos. Por el contrario si pagas a microsoft podrías hacer que el servidor se añadiese a una lista blanca que permitiese su uso sin necesidad de autentificación.

Hay que tener en cuenta que este tipo Spoofing es altamente anónimos. Sí, nuestra IP quedará registrada en el servidor relay, pero ¿qué sucedería si realizáramos la conexión SSH mediante un servidor proxy?

La búsqueda de servidores Relay “abiertos” es algo muy interesante. Permite a los atacantes un alto índice de Spam sin apenas molestarse lo más mínimo aprovechándose de las infraestructuras de terceros. Por otro lado, si se tuneliza el tráfico mediante un servidor proxy, esto brinda un anonimato increíblemente alto. Aquí somos personas de bien, y dado que todo esto tan solo tiene fines didácticos no me importa no tunelizar el tráfico por un proxy. Lo que estábamos comentando es la búsqueda de servidores Relay “abiertos”. ¿Pero como hacerlo? Ya hemos dicho que para que un servidor pueda ser alcanzado, debe de tener un registro MX asociado a él en los servidores de DNS. Estos registros MX nos están diciendo directamente el servidor SMTP “al descubierto” que tienen. Gracias a herramientas como DIG, podemos consultar estos registros e intentar encontrar un relay abierto en dicho servidor:

C:\Users\Theliel>dig gmail.com MX

; <<>> DiG 9.7.0rc2 <<>> gmail.com MX
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 85
;; flags: qr rd ra; QUERY: 1, ANSWER: 5, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;gmail.com. IN MX

;; ANSWER SECTION:
gmail.com. 3008 IN MX 5 gmail-smtp-in.l.google.com.
gmail.com. 3008 IN MX 20 alt2.gmail-smtp-in.l.google.com.
gmail.com. 3008 IN MX 30 alt3.gmail-smtp-in.l.google.com.
gmail.com. 3008 IN MX 10 alt1.gmail-smtp-in.l.google.com.
gmail.com. 3008 IN MX 40 alt4.gmail-smtp-in.l.google.com.

Un buen punto de partida sería comenzar por el servidor SMTP con una preferencia menor (supuestamente el primero a usarse). A continuación comprobar si se puede hacer algo con dicho servidor:

C:\Users\Theliel>ncat -C gmail-smtp-in.l.google.com 25
220 mx.google.com ESMTP 31si565032vws.79
EHLO TEST
250-mx.google.com at your service, [79.158.250.30]
250-SIZE 35651584
250-8BITMIME
250-ENHANCEDSTATUSCODES
250 PIPELINING

Bingo!! El servidor no responde con ninguna línea de que necesite autentificación, luego a priori podríamos pensar que hemos encontrado un buen objetivo. Si profundizamos un poco más:

250 PIPELINING
mail from: 250 2.1.0 OK 31si565032vws.79
rcpt to: 550-5.1.1 The email account that you tried to reach does not exist. Please try
550-5.1.1 double-checking the recipient’s email address for typos or
550-5.1.1 unnecessary spaces. Learn more at
550 5.1.1 http://mail.google.com/support/bin/answer.py?answer=6596 31si565032vws.79
rcpt to: 250 2.1.5 OK 31si565032vws.79

Con lo que nos muestra, ya podemos hacernos una idea de lo que está pasando. Efectivamente es un servidor relay abierto, pero tan solo permite conexiones local -> local internet -> local. Es decir, podemos falsear como deseemos con él nuestra identidad, pero el destinatario tan solo puede ser un correo “gmail”, es decir, una dirección local. Si llegamos a enviar el correo a nusetra cuenta de gmail, efectivamente el correo es recivido por nuestra bandeja de entrada, dependiendo de la IP desde donde lo hagamos, será filtrado como Spam o no.

Lo importante en este caso no es si el correo se filtra como SPAM o llega, lo importante es ver como con dos simples pasos es posible “apropiarse” de un servidor relay. No es malo, solamente sucede que todo puede ser usado para fines buenos o fines malos. Por último veamos que sucede si hacemos lo mismo con live:

C:\Users\Theliel>ncat -C mx1.hotmail.com 25
220 bay0-mc3-f33.Bay0.hotmail.com Sending unsolicited commercial or bulk e-mail to Microsoft’s computer network is prohibited. Other restrictions are
found at http://privacy.msn.com/Anti-spam/. Violations will result in use of equipment located in California and other states. Mon, 8 Feb 2010 04:18:2
6 -0800
EHLO
250-bay0-mc3-f33.Bay0.hotmail.com (3.10.0.73) Hello [79.158.250.30]
250-SIZE 29696000
250-PIPELINING
250-8bitmime
250-BINARYMIME
250-CHUNKING
250-AUTH LOGIN
250-AUTH=LOGIN
250 OK

En este caso el servidor con el que hemos dado requiere autentificación, luego tan solo podríamos usarlo en caso de tener unos credenciales válidos. Aun así, se podría comprobar su seguridad, pero por ahora estamos buscando servidores sin autentificación, y en este caso es un palo de ciego (pero si no se intenta, no se puede saber). En teoría, cuando se solicita autentificación se dice… pero que suceed si intentamos forzar aun así?:

mail from:
250 test@hotmail.com….Sender OK
rcpt to:
250 test@live.com
data
354 Start mail input; end with .
From: Theliel
To: Theliel
Subject: TEST

Prueba 10
.
250 mail from IP 79.158.250.30 soft failed sender ID check. Please ensure this IP is authorized to send mail on behalf of [hotmail.com]

Bueno… se ha intentado. Efectivamente contra todo pronóstico, el servidor no nos ha expulsado por no estar autentificado, pero aun así los servidores de MS no permiten usar dicho relay si no se tiene una IP autorizada para ello… y evidentemente la mía no lo es.

Prácticamente cualquier registro MX que veamos puede ser susceptible a ser utilizado por un atacante, el problema es que normalmente tendrán alguna política de restricción. Otras veces podemos comprobar que existen diferentes registros MX. Que un registro MX nos lleve a un servidor SMTP más protegido, no implica que otro pueda no pueda llevarnos a un servidor menos desprotegido. Estos servidores no es que sean todos inseguros, lo que sucede como ya dijimos en su momento, es que siempre se presupone un uso debido de las tecnologías actuales. Aunque aquí pueda mostrar los riesgos que pueden existir, siempre defenderé un Internet limpia y libre. La mejor forma de evitar estos ataques es el conocimiento, por parte de los administradores de sistemas y por parte de los usuarios que pueden ver comprometida su seguridad.

 

Servidor SMTP Con Autentificación

El uso de servidores de correo propios tiene el problema de que casi todo el contenido será marcado como Spam. El uso de servidores Relay sin autentificación tiene el problema de que muchos proveedores filtran dichos correos. Lo ideal por lo tanto sería poder contar con servidores Relay los cuales podamos acceder con autentificación y que no estén filtrados por nadie. El problema de este tipo de servicios es que si te autentificas en un sistema, es mucho menos anónimo, por no decir que estos servidores puedan implementar grandes medidas de seguridad para evitar el Spoofing.

Lo primero que podríamos intentar es realizar lo que se hizo con anterioridad pero usando nuestra cuenta de gmail. El arte del “hacking” es presuponer que en algún momento los programadores metieron la pata, y esa metedura de pata se usa para lograr los fines. Un atacante esta premisa la conoce bien. Podemos presuponer que gmail es completamente invulnerable y no intentarlo, o tener la esperanza de hacer saltar por los aires la seguridad de ellos, buscando un olvido de los programadores. Vamos a presuponer que no conocemos en absoluto el sistema de correos de gmail ni de live, y queremos simplemente investigar un poco. En este caso lo más probable es que una búsqueda por registros MX no nos devuelva nada interesante, y dado que estamos buscando servidores SMTP con autentificación, vamos a tener que usar o partir de algún servidor del cual tengamos unas credenciales.

Primero vamos a ver como se comporta gmail. Necesitamos por lo cual los datos de acceso al servidor SMTP de gmail para ello:

Servidor: smtp.gmail.com, Puertos 25, 465, 587. En teoría, sabemos que el puerto por defecto es 25 y es el puerto por defecto también de STARTTLS. Por otro lado sabemos que normalmente 465 se usa para SMTP sobre TLS, y 587 suele ser usado para lo mismo. Visto esto, lo normal sería intentar acceder por puerto 25 para evitar TLS:

C:\Users\Theliel>ncat -C smtp.gmail.com 25
220 mx.google.com ESMTP 16sm3074639ewy.6
EHLO TEST
250-mx.google.com at your service, [79.158.250.30]
250-SIZE 35651584
250-8BITMIME
250-STARTTLS
250-ENHANCEDSTATUSCODES
250 PIPELINING
mail from:
530 5.7.0 Must issue a STARTTLS command first. 16sm3074639ewy.6

Lo cual nos está indicando claramente que por ese puerto tan solo podremos acceder mediante STARTTLS (un sistema similar a TLS… por así decirlo). Vemamos que obtenemos por los otros dos puertos:

C:\Users\Theliel>ncat -C smtp.gmail.com 465

C:\Users\Theliel>ncat -C smtp.gmail.com 587
220 mx.google.com ESMTP 24sm11618069eyx.6
EHLO TEST
250-mx.google.com at your service, [79.158.250.30]
250-SIZE 35651584
250-8BITMIME
250-STARTTLS
250-ENHANCEDSTATUSCODES
250 PIPELINING
mail from:
530 5.7.0 Must issue a STARTTLS command first. 24sm11618069eyx.6
quit
221 2.0.0 closing connection 24sm11618069eyx.6

En el primer caso se queda esperando… esto es normal. Mientras que STARTTLS inicia una sesión encriptada dentro de la propia sesión ya establecida, TLS/SSL desde el momento de la conexión se realiza una sesión encriptada. Por tanto se queda esperando a recibir los certificados e iniciar el proceso de encriptación del canal. En el segundo caso podemos compronar que el puerto 587 se está usando igualmente para STARTTLS.

Por tanto vamos a intentar conectar al servidor SMTP mediante STARTTLS y mediante TLS. Una vez establecido el canal seguro, deberíamos de poder hablar con el servidor SMTP como hemos estado haciendo anteriormente:

theliel@Anarchy:~$ openssl s_client -starttls smtp -crlf -connect smtp.gmail.com:25
CONNECTED(00000003)
[ELIMINADO POR ACORTAR]
Start Time: 1265640813
Timeout : 300 (sec)
Verify return code: 21 (unable to verify the first certificate)

250 PIPELINING
EHLO TEST
250-mx.google.com at your service, [79.158.250.30]
250-SIZE 35651584
250-8BITMIME
250-AUTH LOGIN PLAIN
250-ENHANCEDSTATUSCODES
250 PIPELINING
AUTH LOGIN
334 VXNlcm5hbWU6 <- Significa “Usuario”, codificado en base64 -> $echo “dGVzdEBnbWFpbC5jb20=” | openssl enc -base64 -d
dGVzdEBnbWFpbC5jb20= <- Significa “test@gmail.com” condificado en base 64 -> $echo -n “test@gmail.com” | openssl enc -base64
334 UGFzc3dvcmQ6
Y29udHJhc2XDsWFwcnVlYmE=
235 2.7.0 Accepted
mail from:
250 2.1.0 OK 26sm6346727fks.37
rcpt to:
250 2.1.5 OK 26sm6346727fks.37
data
354 Go ahead 26sm6346727fks.37
From: Theliel
To: Theliel <test@live.com>
Subject: Test

Prueba 1
.
250 2.0.0 OK 1265640966 26sm6346727fks.37
quit
221 2.0.0 closing connection 26sm6346727fks.37

Es necesario usar OpenSSL para poder iniciar la sesión y continuar con STARTTLS. En este caso Gmail acepta cualquier origen especificado en “mail from”. Esto podría ser un paraíso para los Spammers. Y es que aunque todo el proceso parezca que funciona perfectamente bien, cuando acudimos a la bandeja de entrada vemos que los servidores de Gmail han modificado el remitente, de forma que coincida con los datos de la autentificación. Es decir, da igual que se especifique en “mail from” ó “from”, gmail usará nuestra verdadera identidad. Luego mediante este servidor no es posible realizar un Spoofing. He optado por la autentificación “LOGIN”, la cual nos muestra por pantalla que introduzcamos el usuario y la contraseña. Tanto las peticiones como las respuestas se deben de hacer en base64

Podemos intentarlo por el puerto 465 y usando TLS:

C:\Users\Theliel>ncat -C –ssl smtp.gmail.com 465
220 mx.google.com ESMTP 23sm11723882eya.3
EHLO TEST
250-mx.google.com at your service, [79.158.250.30]
250-SIZE 35651584
250-8BITMIME
250-AUTH LOGIN PLAIN
250-ENHANCEDSTATUSCODES
250 PIPELINING
AUTH PLAIN
334
AHRlc3RAZ21haWwuY29tAGNvbnRyYXNlw7FhcHJ1ZWJh
235 2.7.0 Accepted
mail from:
250 2.1.0 OK 23sm11723882eya.3
rcpt to: <test@live.com>
250 2.1.5 OK 23sm11723882eya.3
data
354 Go ahead 23sm11723882eya.3
from: Theliel
to: Theliel <test@live.com>
subject: Test

Prueba 2
.
250 2.0.0 OK 1265642518 23sm11723882eya.3
quit
221 2.0.0 closing connection 23sm11723882eya.3

Como podemos comprobar, obtenemos exactamente lo mismo. Aun así me ha servido el ejemplo para mostrar en este caso la conexión mediante SSL (se puede usar si se prefiere openSSL) y como en esta ocasión hemos preferido usar autentificación “PLAIN”. En este caso, se debe de introducir las credenciales en base 64 pero con un formato específico. La mejor forma de llevar a cabo esto es quizás utilizar algún lenguaje de scripting para que nos haga la labor más simple. Se podría componer pasando a base64 primero por un lado el ID, despues la arroba, despues el realm, despues la contraseña… es más comodo hacer lo siguiente en Perl:

“perl -MMIME::Base64 -e ‘print encode_base64(“\000test\@gmail.com\000contraseñaprueba”)'”

Nos quedaría otro método de autentificación por ver, que sería CRAM-MD5, el más seguro. De todos modos dado que que gmail solo permite mediante la creación de una sesión encriptada, no importa usar CRAM-MD5, el cual suele usarse cuando no es posible una comuncación cifrada.

En esta ocasión ninguna de las pruebas realizadas ha tenido ningún tipo de éxito, pero tan solo hemos probado con Gmail. Esto mismo podríamos hacerlo con cualquier servidor SMTP al cuan tengamos acceso. Como último ejemplo vamos a ver que sucedería con Live (hotmail):

ehlo test
250-BLU0-SMTP59.blu0.hotmail.com Hello [79.158.250.30]
250-TURN
250-SIZE 35840000
250-ETRN
250-PIPELINING
250-DSN
250-ENHANCEDSTATUSCODES
250-8bitmime
250-BINARYMIME
250-CHUNKING
250-VRFY
250-AUTH LOGIN PLAIN
250 OK
auth login
334 VXNlcm5hbWU6
xxxxxxxx
334 UGFzc3dvcmQ6
xxxxxxxx
235 Authentication succeeded
mail from:
250 2.1.0 test@hotmail.com….Sender OK
rcpt to:
250 2.1.5 test@live.com
data
354 Start mail input; end with .
from: Theliel
to: Theliel
Subject: TEST

Prueba 2
.
250 2.6.0 Queued mail for delivery

Bingo!! En un principio se podría pensar que sucede exactamente lo mismo que con gmail. En cambio, si miramos la bandeja de entrada ahora si que nos topamos con una interesante noticia… el mensaje llega correctamente a la bandeja de entrada y con el remitente completamente suplantado!! Vemos aquí un grabe agujero de seguridad por parte de MS, dado que cualquier usuario con una cuenta live unos cuantos conceptos podría suplantar cualquier identidad que quisiese y sin que el correo sea considerado SPAM. Evidentemente no es oro todo lo que reluce y si se mira un poco más a fondo uno comprobaría el origen REAL del correo. Pero en principio pasaría completamente por real.

Como hemos visto, es raro encontrar un sistema que sea completamente confiable y segudo. Cuanto más experimentas y pruebas, te das cuenta que prácticamente los fallos en la seguridad están a la orden del día. Muchos de dichos problemas son más que sabidos, pero quizás se necesitan tal y como están por otros motivos.

 

Hemos visto como un atacante podría crear un servidor de correo. Hemos visto como un atacante podría buscar y utilizar servidores relay. Hemos visto como podemos incluso usar nuestros propios servicios de correo para estos fines. Es decir, por desgracia es muy fácil a día de hoy suplantar una identidad. Esto sumado al Web Spoofing o URL Spoofing, es un arma terrible para los Spammers, Hackers… y toda la prole.

En la creación de esta parte, Email Spoofing, además de los datos suministrados, casi todos los servidores que he puesto a prueba con fines de redacción, antes o después mostraban una vulnerabilidad, un acceso, algo que podría mejorarse considerablemente.

Por tanto… ¿como podemos defendernos ante esta más que visible amenaza? Teniendo los ojos abiertos. No hay una norma… quizás la única es desconfiar, y cuando algo nos hace sospechar acudir a las cabeceras de los correos para ver la verdadera procedencia de este. En el mejor de los casos nos podrá decir el correo original, en el peor de los casos tendremos que conformarmos con la IP del remitente real. El peor escenario? que estén usando contra nosotros un servidor SMTP relay al cual se haya accedido mediante proxy, en cuyo casi no tendríamos prácticamente nada.

Es evidente que no se puede sospechar del 100% de los correos, pero si tener presente que en cualquier momento un correo de nuestra paraje, amigo, familiar… puede que no sea realmente de ellos. Por supuesto hay que tener en cuenta, que las personas no se dedican a esto para molestar, y que el 90% de este uso es con fines de SPAM, a fin de cuentas, tal y como comencé al inicio… ¿Quien no ha recibido alguna vez un correo falso?

Seguridad: Spoofing. Capítulo Cuarto -> Header Spoofing

ATENCION: Los ejemplos que se van a mostrar y “tutoriales” tan solo tienen carácter educativo. En ningún aspecto comparto filosofías de invasión a la intimidad, ataques contra un sistema informático o cuestiones similares. En la medida que sea posible siempre se usarán ejemplos y formas que puedan ser usados por cualquier persona, de forma que pueda verificar los contenidos escritos. No obstante, por motivos más que obvios, materiales como contraseñas, nombres de usuarios o de hosts, serán omitidos o modificado en las capturas de pantallas realizadas (o las lineas escritas). Es decir, los ejemplos serán completamente reales, los datos mostrados a vosotros necesarios para poder pertrechar estos ejemplos no siempre lo serán (Sí lo serán los resultados). Para que esto conste de forma clara, todo material sensible modificado o falso estará resaltado en ROJO. Por motivos de seguridad, todo el material que sea expuesto aquí (exceptuando software propietario o libre, citaciones expresas o código de terceros) tanto texto, imágenes y código son propiedad del autor y está completamente prohibido su reproducción completa o parcial en otros lugares, espero que se comprenda.

 

Header Spoofing

En un principio, cuando puse en mente esta serie de artículos, tenía pensado hablar tan solo de Referred Spoofing, pero por extender un poco más esto y que se comprenda mejor, vamos a expandirlo a todo el Header.

En realidad no estoy seguro si el término Header Spoofing existe o no. Ya sabemos que es el Spoofing y ha quedado más o menos claro. Pero que es ¿Header? Header (o Cabecera) pueden ser muchas cosas (Perdonarme y permitirme muchas veces los términos anglosajones, soy un férrimo defensor de nuestra lengua castellana y comprendo que para la mayoría de toda esta jerga existen términos castellanos para ellos. No obstante la costumbre de trabajar con ellos siempre en ingles te crea el hábito).

Una cabecera en una carta sirve para especificar por ejemplo la fecha. En informática un header suele ser lo mismo, una serie de datos que preceden a otros. Nosotros nos vamos a centrar en el header de una web, pero como digo el ámbito es muy grande. Más adelante, en eMail Spoofing por ejemplo veremos el header de un correo.

Cuando accedes desde el navegador a cualquier web, se ponen en marcha una serie de procesos que son completamente transparente para el usuario. Primero peticiones DNS y después el request (o petición) de la web al servidor. Este recuest explicado en simple sería algo así como enviar por ejemplo a google un mensaje que diga: “Quiero acceder a tu buscador”, y google con un response (contestación) contestaría algo así como: “Este es mi buscador…..” y la web se visualizaría. En cada petición que se envía hacia un servidor web, así como en cada respuesta de estos a nuestro PC, existe una cabecera con una serie de datos muy interesantes. Estos datos son preconfigurados por nuestro navegador (en caso de los request) en función de las opciones propias del navegador o de la web que estamos en ese momento visitando. Por su parte, los headers de los response de los servidores están igualmente preconfigurado por los servidores de ellos en función de su configuración o de nuestros propios request.

El secretismo en todo esto está en que a efectos prácticos para el usuario, estos headers no los verá jamás, en cambio, sin darse cuenta, la visualización de una web puede ser completamente diferente, así como otro millar de cosas tan solo por esa cabecera. Luego… que sucedería si modificamos nosotros a voluntad esa cabecera? Si modificamos los request, podemos producir un comportamiento interesante por parte del servidor objetivo. Del miso modo si modificamos el header de un response, estaremos modificando el comportamiento de nuestro propio navegador ante un request. ¿Que utilidad tiene esto?:

  • Acceso a webs sin autorización
  • Acceso a webs alternativas
  • Búsqueda de exploits en Webs
  • Cheats para juegos online
  • Etc…

 

¿Que aspecto tienen? Eso ya lo sabemos… en estas páginas por ejemplo se han publicado headers. Pero vamos a ser más concretos. Vamos a ver cual sería el header de una petición desde mi navegador Firefox a www.google.es:

GET / HTTP/1.1
Host: www.google.es
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.3a1pre) Gecko/20100203 Minefield/3.7a1pre
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: es-es,es;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://www.google.es/ig?hl=es
Cookie: PREF=ID=XXXXXX
Cache-Control: max-age=0

Cada una de las etiquetas mostradas (Host, User-Agent, Accept…) tiene su propia utilidad y es igualmente importante. Y todas ellas son establecidas por el navegador que estemos usando. Si realizamos exactamente la misma petición, pero desde Internet Explorer esto es lo que tendríamos:

GET / HTTP/1.1
Accept: */*
Accept-Language: es-ES
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0)
Accept-Encoding: gzip, deflate
Host: www.google.es
Connection: Keep-Alive
Cookie: PREF=ID=XXXXXX

Todas estas etiquetas de la cabecera de request, serán procesadas y/o ignoradas por el servidor destino, y este responderá con uno u otros datos de una u otra forma en correspondencia a estas cabeceras. Hay que decir que aunque estas cabeceras sean especificadas por el navegador, no quiere decir que sean inmutables. Las propias webs que se reciben, formularios que se rellenan… dan instrucciones también al navegador de como deben de solicitar dichos request. Es decir, es un círculo vicioso. El navegador es el primero en establecer una cabecera, y el servidor responde con una web. En dicha web, dependiendo de donde pulsemos o las acciones que llevemos a cabo, nuestro request incluirá información de estado de esta web y el servidor destino responderá del modo acordado a esa petición.

Por otro lado, también tenemos las cabeceras que son enviadas por parte del servidor a nuestro navegador. Su importancia suele ser menor, dado que lo que logran es modificar el comportamiento de nuestro navegador, algo que suele importar menos. No obstante también puede tener su utilidad como veremos más adelante. Vamos a ver los response de las peticiones anteriores:

HTTP/1.1 304 Not Modified
Content-Type: text/html
Date: Fri, 05 Feb 2010 15:40:46 GMT
Set-Cookie: IGTP=LI=1:LM=XXXXXXXXXX; expires=Sun, 05-Feb-2012 15:40:46 GMT; path=/ig; domain=www.google.es
Expires: Fri, 05 Feb 2010 15:40:46 GMT
Cache-Control: private, must-revalidate, max-age=0
Last-Modified: Fri, 05 Feb 2010 15:40:46 GMT
ETag: XXXXXXXXXXXXXXXXX
Server: igfe
X-XSS-Protection: 0

Algunas de las cabeceras son ellas mismas descriptivas y no hay que entrar mucho en detalle para comprender que significan o que función realizan, pero no por ello no dejan de ser importantes. Vamos a ver algunas de ellas:

 

-Etiquetas de Metodos y Etiqueta Host

Es la primera etiqueta que aparece, y es la única que podríamos decir que no es una etiqueta. No especifica ninguna cualidad del navegador, sino más bien como se han de obtener los datos, la URI de acceso y la versión del protocolo al que se está accediendo. Mi intención no es dar un repaso completo de cada una de las etiquetas de los headers, para eso tan solo tenemos que acudir a las especificaciones del protocolo. Por tanto vamos a centrarnos tan solo en lo que pueda ser más significativo, los métodos GET y POST. Aunque no sea una definición correcta, podemos decir que GET lo usará el navegador para obtener datos desde un servidor y POST cuando nuestra petición incluye datos que puedan ser significativos para el servidor, por ejemplo los formularios rellenos, credenciales de acceso…

En los dos ejemplos anteriores, la URI es “/”, es decir, se está obteniendo (GET) la ubicación raiz “/” del host especificado en la etiqueta “host”, en este caso “www.google.es”. No obstante la URI podría haber sido algo así como “/es” por ejemplo, para especificar el contenido dentro de “www.google” a recibir. Con esto hemos dicho también el significado de la etiqueta “Host”. Especifica el servidor al cual se desea realizar el acceso. La respuesta de la etiqueta Host por parte de response, podría venir dada pro la etiqueta Server, que especifica el servidor usado. En este caso “igfe” un servidor (software) propio de Google.

En el caso de los response, no aparecerá POST ni GET (entre otros), sino la respuesta a estos. Para ello, se especifica del mismo modo la versión HTTP que usará el servidor y un código que especificará información sobre el site que se ha solicitado. En el ejemplo anterior se contesta con un código 304 -> Not Modified. Es decir, en este caso implicaría que el contenido ha sido encontrado pero no ha sido modificado desde la ultima petición de este, posiblemente porque se ha realizado un refresh de la misma web. Como digo, podemos acudir a las especificaciones HTTP para conocer esto en detalle.

 

-Etiqueta User-Agent

Posiblemente una de las primeras etiquetas Spoofeadas en la historia. El User-Agent es un string, un identificador del navegador que estamos usando. Es una etiqueta fundamental, es la única forma que tiene el servidor de conocer el navegador que estamos usando. Esto es evidente tiene una importancia mayúsculas. ¿Por qué? Es obvio, cada navegador es diferente y usa tecnologías diferentes. Gracias a los User-Agent puedes especificar por ejemplo que tipo de contenido quieres para unos o para otros, puedes simplemente filtrar todas las peticiones de clientes específicos. Es decir, sin que lo sepamos, muchos contenidos que vemos en cada momento está dependiendo exclusivamente de dicho User-Agent. En los dos ejemplos, evidentemente cada User-Agent es completamente diferente.

Normalmente el User-Agent no solo brinda información de la versión del navegador o de su layout, sino incluso del OS que se está usando. En el primer caso, tenemos desde la versión de Firefox, la compilación, la versión del kernel NT (6.1 = Windows 7), incluso el lenguaje de Firefox. En el caso de IE los datos son similares, pero evidentemente referentes a IE.

 

-Etiquetas Accept y Accept Language

La primera especifica los tipos de archivos que aceptará, y si hay más de un tipo especificado, la preferencia de un tipo de contenido respecto a otro. La segunda el lenguaje aceptado, e igualmente que con Accept, si se especifica más de uno cada uno tiene una preferencia diferente. Normalmente esta última etiqueta la podemos nosotros modificar seleccionando otro idioma en las opciones de configuración del navegador. Ojo!! no tiene nada que ver el idioma del navegador, sino el lenguaje solicitado por el navegador. Si el servidor dispone de diferenciación de idiomas nos dirigirá al nusetro, sino, nos devolverá el idioma por defecto que tenga configurado el servidor.

La contestación por parte del servidor en su response de Accept, vendrá dada por la etiqueta Content-Type que especifica precisamente el tipo de contenido que será transferido.

-Etiquetas Accept-Encoding y Accept-Charset

La primera es importante, especifica el tipo de compresión soportada por nuestro navegador. Nuestro navegador envía al servidor una serie de parámetros (las etiquetas) y según estos el servidor podrá seleccionar que web mostrar. Si el servidor está usando compresión y nuestro cliente la soporta, el servidor enviará la información comprimida, ahorrando ancho de banda.

La segunda etiqueta simplemente especifica el conjunto de caracteres que se usará

 

-Etiqueta Cookie

Antes de comenzar… ¿que es una Cookie además de una galleta? Es un pequeño archivo de texto que almacena normalmente unos cuantos datos que son reutilizados después por las webs. Es la única forma que tiene una web de guardar datos en el PC del usuario. Estas Cookies son las que se encargan por ejemplo (normalmente) de mantener una sesión abierta en aquellos sitios que requieren una autentificación, o guardar un pequeño registro sobre algo. Pero por dichos motivos son también un objetivo muy importante. Si una Cookie se usa para que podamos acceder por gmail (por ejemplo), si esa cookie se traspasase a otro usuario, es posible que ese otro usuario pudiese acceder a la misma cuenta de correos que el otro, sin necesidad de conocer las credenciales (usuario y contraseña). Es decir, una cookie puede ser una llave a cualquier sitio que sea necesario autentificarse. Por esta razón, dichas cookies suelen tener una caducidad, así tenemos cookies de sesion (que son eliminadas cuando salimos del navegador) o cookies que son permanentes (o se borran). Por desgracia estas Cookies son usadas demasiado asiduamente para espiarnos o guardar un seguimiento nuestro. Dado que la cookie es accedida también por el servidor, se puede usar para contabilizar las veces que se accede a tal página, realizar seguimientos de las personas… en fin… todo tiene siempre un lado negativo.

Por lo tanto, es otra etiqueta de gran importancia. El navegador especificará la cookie de dicho lugar. Si en dicho momento aun no tiene ninguna cookie almacenada, creará una con el objeto de que pueda ser usada por el servidor si así la requiere. La importancia de poder modificarlas es por tanto muy grande. Las cookies, mientras que suelen estar almacenadas en nuestro PC en archivos, estas no se transmiten como archivos, sino en la cabecera, dentro de la etiqueta Cookie. Es decir, esta etiqueta lo que especifica es el contenido de dicho archivo. Modificar esta etiqueta por tanto implica modificar los datos que contiene la cookie. Evidentemente por motivos de seguridad, estos datos suelen ser ilegibles a simple vista, usando Hashes o algun otro sistema para que la información de estas cookies no sea visible de forma simple (o sea imposible).

 

-Etiqueta Referer

Esta etiqueta es fundamental en muchos aspectos. Lo que realiza esta etiqueta es especificar la web desde la que estamos accediendo a la nueva página. Su uso es claro. El servidor puede actuar de una forma u otra dependiendo de cual era el origen. Un ejemplo muy sencillo a esto es cuando accedemos desde Google images a cualquier imagen y el servidos nos devuelve un error diciendo que la imagen no puede mostrarse porque no se permite su “enlazamiento” desde otro lado. ¿Como sabe el servidor que estamos accediendo desde google? gracias a esta etiqueta.

En cambio, posiblemente el uso más extendido de Spoofing de esta etiqueta sea el del acceso sin autorización a sitios de pago, generalmente páginas pornográficas. Estos sites, suelen permitir con la misma inscripción a un site concreto navegar por otros sites que no son de su propiedad. ¿Pero como sabe ese otro site si el usuario puede o no puede acceder? O ese otro site tiene acceso a la misma base de datos para poder reconocer usuario/contraseña, o simplemente permite el acceso siempre y cuando la etiqueta referer provenga de un site pactado. Es decir, modificando a voluntad una etiqueta referer, es posible acceder a muchos sitios pornográficos de pagos, dado que dichos servidores cotejarán dicha etiqueta por si proviene el usuario de un site con acceso dicho contenido.

 

-Etiqueta Cache-Control

Esta etiqueta la encontramos de forma predominante los response por parte del servidor. En teoría es una orden de como el navegador debe de manejar el caché para dicha página. El caché de un navegador guarda en disco ciertos contenidos de una web para poder acceder a ella más adelante de forma más rápida y eficiente. Pero es evidente que todo el contenido no siembre es bueno cachearlo. Si se cachea y usa el contenido de la caché en vez del deservidor siempre se corre el riesgo de que los datos que estemos visualizando no sean correctos. Un buen manejo del caché podría ser por ejemplo marcar el contenido estático como puedan ser imágenes, scripts… con una duración mayor al que pueda tener por ejemplo un html dinámico con contenido de texto que está casi continuamente cambiando.

Si controlamos el valor de este campo, podríamos obligar a nuestro navegador que cachease el contenido o que no lo hiciese, ambos casos pueden ser útiles en momentos concretos.

 

Aquí tan solo vamos a dar unas pautas de como modificar estas etiquetas. En teoría se puede modificar cualquier cabecera, lo que no quiere decir que pueda ser útil. Por ejemplo, la utilidad de modificar la etiqueta “Accept Language” sería un poco absurdo, dado que puede ser modificada a voluntad en el mismo navegador. Por cuestiones evidentes no puedo poner un ejemplo de Referer Spoofing de una web adulta, pero puedo poner otros ejemplos que pueden extrapolarse a cualquier uso real. Recordar que Spoofing es engañar, modificar… y eso es lo que pretendemos. Vamos a ver ejemplos de Referer Spoofing, Cookie Spoofing y User-Agent Spoofing. Las herramientas que podamos usar para estas prácticas pueden ser más o menos las mismas siempre. Ya que lo que vamos a realizar es modificar estos headers, necesitaremos algo que nos permita interceptar estos datos, y básicamente vamos a encontrar dos formas: La primera con alguna herramienta del mismo navegador web (Bienvenido sea Firefox). La segunda por medio de un Proxy que nos permita modificación “al vuelo”. Para ello vamos a usar algunas extensioens de firefox y como Proxy por ejemplo Paros.

 

User-Agent Spoofing:

Vamos a ver un ejemplo simple de como afecta en el navegador este User-Agent. Lo bueno para muchos es que para aquellas prácticas que están relativamente expandidas existen utilidades para realiza dicha tarea de forma simple. Por ejemplo tenemos herramientas en Firefox que nos permiten especificar directamente que User-Agent queremos usar.Vamos a hacerlo de las dos maneras. Para ello vamos a ver que ocurre cuando llamamos a “www.google.es” con el User-Agent por defecto de mi navegador y que ocurre si invocamos la misma página con el User-Agent del iPhone 3.1.3:

Mi User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.3a1pre) Gecko/20100205 Minefield/3.7a1pre

iPhone 3.0 User-Agent: Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_0 like Mac OS X; en-us) AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0 Mobile/7A341 Safari/528.16

 

Trabajando solo con Firefox (Firebug+User-Agent Switcher):

Ventana de Firebug -> Net -> HTML -> Headers

Configuración User-Agent Switcher

En las dos primeras imágenes podemos comprobar perfectamente como sería una petición básica a www.google.com y como se configuraría un User-Agent dentro de User-Agent Switcher. Firebug es sin duda una herramienta potentísima que puede hacer las delicias de muchos, es una de esas herramientas que cuanto más usas, más aprecias, capaz de hacernos la vida mucho más fácil a los programadores/diseñadores webs.

Google para iPhone y nuevo User-Agent

Al establecer el nuevo User-Agent, el servidor www.google.es considera que la petición se está realizando desde un iPhone, y lo resuelve enviando la web específica para dicho dispositivo. Es tan solo un ejemplo de la importancia de este simple identificativo.

Pero al igual que hemos realizado esto con herramientas de andar por casa (a fin de cuenta una extensión en firefox no deja de ser una extensión), la mejor forma de realizar esto (puesto que no solo nos va a servir para este caso concreto) es la utilización de un servidor proxy que nos intercepte todas las peticiones realizadas:

Paros Proxy, examinando una cabecera
Paros Proxy, modificando una cabecera

Paros Proxy es un software gratuito, sin la complejidad de tener que instalar un servidor proxy completo. Como se muestra en la primera imagen tan solo captura las peticiones que se van realizando, y al finalizar la carga es tan simple como examinar las cabeceras. Una vez localizado el objetivo, es tan facil como poner un “cepo” (trap) a los request, de este modo antes de que sea enviado nuestro request, podremos modificarlo a voluntad.

Aunque no se muestra el resultado final, el efecto es exactamente el mismo que el mostrado anteriormente, salvo que queda de manifiesto el potencial de una herramienta así, dado que con ella podremos modificar no solo el User-Agent, sino lo que deseemos, tanto de los request como de los responses.

 

Referer Spoofing

Ya hemos explicado lo que es, y en User-Agent Spoofing se han dado pautas de como podría realizarse cualquier Header Spoofing. Mi objetivo original era explicar un poco por encima tan solo el Referer Spoofing, y al final será el menos especificado.

En realidad la imaginación es el límite.Cuanto más es usada una etiqueta, más beneficioso podría ser poder controlarla. En este caso hemos dicho que Referer Spoofing se suele controlar para conocer la web de procedencia que nos ha originado en dicho lugar. Mi idea originar era poner una web adulta de ejemplo, pero por cuestiones de edad y de privacidad he decidido no hacerlo. Podría mostrar tan solo imágenes de las propias cabeceras… pero entonces no lograría el objetivo de ver un antes o un después, como hemos realizado con el User-Agent.

Otros ejemplos notables del control de esta etiqueta es para filtrar contenido. Esto es muy usado en blogs y otros sites que no desean que su contenido pueda ser enlazado desde el exterior, mostrando una imagen “falsa” (o mejor expresado, diferente de la esperada) en caso de que sea enlazada con una referencia href. A fin de cuenta, cuando se enlazan imágenes u otros tipo de contenido de forma directa, el ancho de banda corre a cargo de la web original. Por parte de los servidores esto se evita con filtrados en el servidor web, y para evitarlo basta con modificar la etiqueta referer.

 

Cookie Spoofing

Esta etiqueta siempre será objetivo de incesantes ataques. Tal es así que prácticamente todas las cookies actualmente tienen algún tipo de encriptación o modificación para que no se pueda apreciar de forma clara que es lo que realiza.

No obstante, muchas veces este “cifrado” puede ser reversible o se puede inferir por el contenido. Otras veces no importa siquiera el contenido de dicha Cookie, y modificándolo a gusto se pueden obtener resultados igualmente satisfactorios.

Un ejemplo aplicado de esto fue usado por ejemplo en mi Artículo sobre Hammerfest, el cual por cierto tengo que rehacer. ¿Por qué fue necesario Cookie Spoofing para dicho artículo? Hammerfest es un juego Online que tan solo permite 3 cuentas máximas asociadas a un mismo PC. Si intentas crear una cuenta para jugar por encima de dicho número, el servidor te lo impedirá. Para poder hacer esto, el servidor tiene algunas opciones. Una podría ser verificando la IP, pero dado que la mayoría de las IPs son dinámicas, no serviría de mucho. La otra opción es por Cookies. El navegador cada vez que intenta acceder envía su cookie al site. El site coteja el ID de dicha cookie (por así decirlo) en su base de datos. Si ya tiene asociada a ella 3 usuarios no permite más. Aunque se elimine la cookie del navegador no ocurre nada, puesto que nada más conectarse el navegador especificará la cookie que usará (aunque esté vacía), la cual tiene el mismo ID, la cual será cotejada. ¿pero que sucede si cambiamos el ID de la cookie? El servidor pensaría que estamos desde otra máquina, almacenaría la nueva ID y nos daría acceso a otras 3 cuentas más para ser creadas.

En el ejemplo puesto, no es necesario siquiera conocer que tipo de ID está usando el servidor, con modificarlo por un valor arbitrario tendremos suficiente.

La importancia del Spoof de cookies tiene mayor importancia cuando conocemos la cookie de sesión de otro usuario, dado que si usamos sus datos para modificar la nuestra, podremos tener acceso a su sesión. Se puede pensar que es complicado conocer la cookie de otro usuario… pero no es complicado en realidad. Formas de obtener estos datos podrían ser mediante Snifers o XSS. En su momento veremos esto, pero por ahora vamos a verificar que puedo iniciar sesión en Internet Explorer en mi cuenta de Gmail sin pasar por el nombre de usuario y contraseña. Esto se puede hacer en dos fases. La primera “espiando la Cookie de Firefox y dirección una vez la cuenta está abierta, y en la segunda parte simplemente usar dicha cookie en IE. Recordar que la cookie en el PC no deja de ser un archivo, pero se especifica directamente en forma de datos en la misma etiqueta Cookie:

Cookie de Sesión y URL gMail

Evidentemente por motivos de seguridad he emborronado los datos propios. Aquí lo importante tan solo es la URL completa y la Cookie. Imaginar ahora que accedemos a IE, pegamos la URL que tenemos en gMail e interceptamos la Cookie enviada por IE y la modificamos por la que obtenemos en Firefox

Inserción Cookie en IE

Aunque pueda verse un error de certificado, esto no es importante. Dado que Gmail usa HTTPS, cualquier modificación en medio (como la realizada al cambiar la cookie) invalida el certificado. Pero si lo aceptamos, vemos como de forma mágica podemos acceder a gMail sin pasar por el nombre de usuario o contraseñas, ya que estos están embutidos de algún modo en la propia Cookie. Es cierto que quizás no seamos capaces de comprender el Hash usado por Google para proteger dicha información, pero no importa, simplemente copiando y pegando tenemos un resultado impecable.

Pensar no solo en las cookies de sesión. Pensar en que pasaría con aquellas cookies que usamos de forma persistentes. Es decir, podemos activar muchas veces las casillas de “Recordarme en cada Visita”, lo cual lo que realiza es que la Cookie usada no se invalida por cada sesión, sino que tiene a lo mejor una validez de una semana.

Sobre la modificación de Cookies que podamos inferir su contenido para especificar otro, será una cuestión que se abordará mejor cuando hablemos de Hashes.

 

Podríamos añadir muchos otros Spoofing dentro de las Cabeceras. Por ejemplo en todos los ejemplos mostrados se presupone que la utilidad es a la hora de los request, pero también puede ser útil modificar los response para producir en aplicaciones Flash por ejemplo un comportamiento completamente diferente. Por ejemplo imaginar que en un response se configuran los datos de una aplicación Flash para tener más vidas (en un juego). Modificando el response podríamos obtener más vidas.

Otra utilidad que se tiene es para modificar los datos enviados por el método POST al servidor. Con POST normalmente se especifican una serie de valores que son especificados en un formulario previamente. Pero muchas veces los valores que podemos introducir en el formulario son muy limitados en correspondencia a los que podríamos introducir directamente realizando Spoof a la cabecera. O por ejemplo pensar en formularios que dependiendo si los rellena un usuario u otro tiene más o menos campos, puesto que es posible que el sistema de procesarlos el servidor sea la misma forma. En dicho caso podríamos añadir “campos” extras con información arbitraria para obtener permisos administrativos por ejemplo u otros menesteres.

 

Volver a arriba

Sobre Mí

Alma Oscura por Theliel is licensed under a Creative Commons Reconocimiento-No comercial-Sin obras derivadas 3.0 Unported License.
Política de Privacidad.
Para otros permisos que puedan exceder el ámbito de esta licencia, contactar en blog.theliel.es/about/contactar.