Security / Seguridad

An important note

Although I am interested and work in different computer security-related projects, I am not affiliated to any kind of underground movement.
I know that there are many underground groups which have made important contributions to computer security, I don't think that attacking from the shadows to vulnerabilities is not the way to go - The correct way is, instead, to raise conciousness in users, administrators and programmers on how things should be done. To whoever can contribute in further ways, with their own research and development, please go ahead. But everything, everything in an open and public way, and respecting above all other things other people's rights.

Resumen: 

Nota importante

Si bien yo me intereso y trabajo en diferentes proyectos de seguridad en cómputo, no estoy afiliado a ningún tipo de movimiento underground.
Si bien hay muchos grupos underground que han hecho importantes contribuciones a la seguridad en cómputo, el camino a seguir en mi opinión no es el del ataque oculto a las vulnerabilidades, sino que el de conicentizar a usuarios, administradores y programadores de cómo debemos hacer las cosas. Para quien tenga la capacidad de contribuir no sólo con concientización sino que con desarrollo propio, adelante. Pero todo, todo de manera abierta, pública, y respetando por sobre de todas las cosas los derechos de los demás.

Fortalecimiento del llavero de confianza en un proyecto geográficamente distribuido

TitleFortalecimiento del llavero de confianza en un proyecto geográficamente distribuido
Publication TypeReport
Year of Publication2015
AuthorsWolf G
Refereed DesignationNon-Refereed
Prepared forIII Congreso de Seguridad de la Información ESIMECU-IPN; Congreso de Seguridad en Cómputo UNAM
CityMéxico DF, México
KeywordsDebian, identidad, Seguridad
Abstract

El establecimiento de cualquier forma de comunicación apoyada por la criptografía de llave pública entre dos entidades determinadas presupone para cualquiera de ellas confianza en la identidad de su contraparte. Esto es, si Alice desea enviar un mensaje a Bob, sea cifrándolo para asegurar la confidencialidad, firmándolo para asegurar integridad y no repudio, o cualquier otra operación/propiedad, el primer paso para Alice debe ser verificar que la llave para la cual esté cifrando pertenezca a Bob y no a un impostor, al igual que Bob debe asegurarse de que la llave firmante sea efectivamente la de Alice, y de nadie más que ella.

En un entorno donde son posibles las verificaciones fuera de banda (donde Alice y Bob se conocen y pueden emplear canales para intercambiar sus llaves sin que haya margen de duda, como podría ser un encuentro en un café) este problema queda resuelto. Sin embargo, la realidad de Internet plantea una situación claramente distinta. En una transacción en línea típica, Alice y Bob no se conocen, y ni siquiera verse en persona les aseguraría que dicha persona es el destinatario de la comunicación y no Eve, Mallory u otro de los personajes del catálogo criptográfico. La respuesta que se ha encontrado ante este planteamiento es el uso de certificados y el depósito de confianza en terceras entidades, los certificadores, lo que se conoce como infraestructura de llave pública (PKI por sus siglas en inglés).

Hay dos modelos principales para hacer esto:

Modelo jerárquico
Se designa a uno o un grupo de participantes de la red como certificadores raíces de confianza. Todos los usuarios confiarán en los certificados emitidos por éstos, o por aquellos certificadores delegados por ellos. Los certificados quedan entonces dispuestos siguiendo la estructura de una serie de árboles, con nodos raíz bien conocidos.
Modelo entre pares

Se establece que todo usuario de la red es un certificador, y se instituye la costumbre de firmar mutuamente los certificados de todas aquellas entidades en cuya identidad se tenga plena confianza. Al hacer pública la lista de certificados, todo usuario podrá trazar rutas de confianza siguiendo a los certificados que unan al Alice con el supuesto Bob. Si se puede establecer dicha ruta, y es suficientemente robusta (pueden emplearse diversas métricas para establecerlo), la identidad de Bob se toma por buena.

El primer modelo es el empleado por los navegadores Web, en el que un grupo de decenas de autoridades certificadoras definidas por los desarrolladores del navegador o del sistema operativo obtienen confianza plena. El segundo modelo impera cuando las relaciones son más bien horizontales (no de cliente-servidor, sino persona a persona), y han logrado fuerza particularmente en las comunidades de desarrollo de software libre, necesariamente al situarse éstas sobre una amplia distribución geográfica. Ambos modelos tienen sus fortalezas y debilidades.

Esta exposición abunda sobre un estudio de caso realizado en una comunidad comparativamente grande (el proyecto Debian, con cerca de 1,000 desarrolladores miembro, y con más de 20 años de existencia) relativo a la dificultad y resultados obtenidos de la adopción de políticas encaminadas a asegurar que todas las llaves reconocidas por el proyecto sean de suficiente fuerza criptográfica para asegurar la inviolabilidad de las características de seguridad que el proyecto requiere. El autor es mantenedor del llavero de confianza de Debian, y participó en la planeación, diseño e implementación del proceso que esta presentación describirá, enfrentándose a factores tanto técnicos como sociales para su consecución.

AttachmentSize
Poster presentado en el III Congreso de Seguridad de la Información (ESIMECU-IPN, oct 2015)8.77 MB
Presentación empleada para el Congreso de Seguridad en Cómputo 2015 de DGTIC/UNAM2.99 MB

Puntos débiles de prácticas comunes en desarrollos Web

TitlePuntos débiles de prácticas comunes en desarrollos Web
Publication TypeMiscellaneous
Year of Publication2015
AuthorsWolf G
Refereed DesignationNon-Refereed
Abstract

Los sistemas Web ya no se construyen a partir de piezas fundamentales o marcos "pelones", sino que parten necesariamente de combinar una gran cantidad de recursos creados por terceros — Por un lado, bibliotecas diversas para su ejecución en el lado del servidor, y por otro lado, proyectos Javascript que son enviados al cliente, apoyando no sólo a la parte estética sino, cada vez más, a la funcionalidad de la aplicación.

Ahora, si nuestros proyectos son enjambres de código de terceros, resulta fundamental tener cómo dar seguimiento a sus nuevas versiones, corregir problemas en dicho código, e incluso evitar introducir disonancia que modifique la ejecución.

En mi sesión abordaré algunas prácticas recomendadas y algunas discusiones en proceso en un proyecto de integración de software a gran escala: La distribución Debian GNU/Linux, con más de 43,000 paquetes, es una de las colecciones de software más grandes del mundo. Para lograr esta integración, ha habido un gran trabajo para adoptar (o, si es necesario, criticar y mejorar) las prácticas de las diversas comunidades de desarrollo de distintos marcos, lenguajes e ideologías.

Para mantener un enfoque hacia el mundo Web, enfocaré las temáticas a abordar en las prácticas específicas empleadas con frecuencia en proyectos basados en Ruby, PHP y JavaScript, presentando nuestras recomendaciones o, en todo caso, nuestra forma de lidiar con las carencias que éstas presentan.

(Ver: Hilo en debian-devel iniciando en <87wpwk7vgy.fsf@latte.josefsson.org>, 24/08, Fedora opens up to bundling en LWN)

Video de la presentación disponible en archive.org

URLhttp://sg.com.mx/sgvirtual/sesion/puntos-debiles-practicas-comunes-desarrollos-web
AttachmentSize
Presentación (formato PDF)13.63 MB

Desarrollo de software y criptografía

TitleDesarrollo de software y criptografía
Publication TypeMiscellaneous
Year of Publication2014
AuthorsWolf G
Refereed DesignationNon-Refereed
Abstract

Ante sucesos recientes tales como las filtraciones de documentos confidenciales de los Estados Unidos (Wikileaks, Edward Snowden) o las vulnerabilidades detectadas en mecanismos criptográficos de alto perfil (SSH de Debian/Ubuntu en 2008, Heartbleed de OpenSSL en 2014), es de especial importancia que los desarrolladores de software cobren mayor conciencia de la importancia de crear software seguro, empleando comunicaciones cifradas.

En esta presentación, buscaré exponer:

  • Aspectos básicos de operación de los mecansimos criptográficos: Cuáles son los mecanismos principales, y cuándo elegir cada uno.
  • Presentar algunos casos de software que, a pesar de emplear los mecanismos correctos, lo hace de forma incorrecta —exponiendo, a fin de cuentas, la información que intentaban proteger, confiados por una falsa seguridad.
URLhttp://sg.com.mx/sgce/2014/sessions/desarrollo-software-y-criptografia-como-proteger-los-datos-nuestras-aplicaciones
AttachmentSize
Presentación (PDF)3.14 MB
Fuentes (Org-mode → LaTeX Beamer)3.01 MB

"No al voto electrónico", Triple W, W Radio

Title"No al voto electrónico", Triple W, W Radio
Publication TypeBroadcast
Year of Publication2013
AuthorsWolf G, Ruiz O
Refereed DesignationNon-Refereed
Keywordse-vote
URLhttp://www.wradio.com.mx/escucha/programas/voto-electronico-octavio-ruiz-y-kunar-wolf-analistas-190213/20130219/programa/1789792.aspx?au=1845636
Full Text

In yet another episode where we push for the population to be aware of the perils that electronic voting represents, Octavio Ruiz (@tacvbo) and me were invited to (briefly) talk about the topic in W Radio, one of the largest radio networks in Mexico.
The interview was short-ish, but we managed to get several points accross. And, of course, one of the best ways to do so is via a radio show with tens of thousands of listeners. So, we were quite happy to be there!
Here is the audio of the segment we presented in Fernanda Tapia's radio show "Triple W", in W Radio, Mexico.

AttachmentSize
Tripe W - Entrevista: no al voto electronico9.97 MB

Herramientas de privacidad en la red

Written in...: 
2012

The internet was conceived as a network where reliability should be more important than privacy: What matters is to get the messages from their origin to their destination, even though this makes them highly traceable. Throughout the years, a large variety of schemes have been created to protect privacy, both while the packages are in transit and in form of stored documents, and at different levels.

In this talk, I present some (relatively) user-friendly programs helping users keep their communications and data more secure.

Resumen: 

Internet de inicio fue planteada como una red donde privaría la robustez sobre la privacidad: Lo importante es poder hacer que los mensajes lleguen de su emisor a su destino, a pesar de que eso los haga altamente rastreables. A lo largo de los años, se han creado una gran variedad de esquemas para proteger la privacidad de, tanto cuando se habla de paquetes en tránsito como en forma de documentos almacenados, a diferentes niveles.

En esta presentación hablo acerca de algunos programas (relativamente) amigables al usuario que ayudan a mantener las comunicaciones y los datos más seguros.

AttachmentSize
Presentation exported to PDF format669.22 KB
Source presentation in Emacs org-mode for LaTeX Beamer437.13 KB

Electronic voting: Talk delivered in Moquegua (Peru)

TitleElectronic voting: Talk delivered in Moquegua (Peru)
Publication TypeAudiovisual
Year of Publication2012
AuthorsWolf G
Date Published07/07/2012
CityMoquegua, Perú
Full Text

While we were at DebConf, all busy and in the organizing frenzy, I was supposed to deliver a talk in Moquegua, Perú, on the evening of July 7. Of course, I was unable to attend. Nevertheless, I accepted, if the talk could be delivered as a pre-recorded video with a live Q&A session afterwards. And so it was.
The talk went quite smooth, and I think I will use bits of it. Video quality is far from great, but well... it was taken using nothing but a webcam and the laptop's integrated microphone. To my surprise, sound quality –that's what matters!– works quite well.
I mostly followed the attached presentation; the video is split in three parts to make it easier to download.
And yes, it's all in Spanish. Translations are, of course, welcome :)

AttachmentSize
Presentation slides (PDF)561.5 KB
Presentation video (1/3)76.57 MB
Presentation video (2/3)55.26 MB
Presentation video (3/3)137.46 MB

El voto electrónico en 2012: ¿Cómo vamos?

Written in...: 
2012

Over and over, in different media we are told that all automatization means progress, and is surely a positive change. Many people expect us techies to be the first enthusiasts for all technifying changes — But sometimes, our task is to bring to the public's attention the reasons as to why some processes should not be automatized.

An example for this is voting. Democratic countries have as their maximum, refoundational act the periodic renovation of the ruling class through the free, secret and universal vote. There is, of course, a recognition to the importance that voting holds, as well as the trust needed in their results' processing. Electronic voting, however, puts it at risk more strongly than any other, human-based way.

In this talk, I present a short exposition on why we think this way, and will delineate the current status of electronic voting in different aspects of our country, to be able to present what we can do in the future.

Resumen: 

Una y otra vez, en diversos medios nos insisten en que toda automatización es símbolo de progreso, es algo necesariamente positivo. Mucha gente espera que nosotros, los tecnólogos, seamos los primeros entusiastas de cualquier cambio tecnificador — Pero en algunos casos, nuestra labor es llamar la atención a por qué algunos procesos no deben pasar por la automatización.

Un ejemplo de lo anterior es el del voto. Los países democráticos tienen como el acto máximo y refundacional la renovación periódica de la clase gobernante por medio del voto libre, secreto y universal. Existe, claro, el reconocimiento a la importancia de este hecho, y de la certeza que haya en el procesamiento de sus resultados. El voto electrónico, sin embargo, pone en riesgo de una manera mucho más fuerte que cualquiera otra implementada a escala humana.

Presentaré una exposición corta respecto a por qué pensamos de esa manera, y delinearé el estado actual del voto electrónico en diversos ámbitos de nuestro país, para poder evaluar con mayor certeza lo que podamos hacer a futuro.

AttachmentSize
PDF presentation426.31 KB
Sources for the presentation (Emacs Org-mode for LaTeX Beamer)148.01 KB
HTML version of the presentation30.8 KB

Urna electrónica es menos confiable que el papel

TitleUrna electrónica es menos confiable que el papel
Publication TypeBroadcast
Year of Publication2011
AuthorsWolf G
Abstract

Interview for UDG Noticias (Guadalajara), talking about how electronic voting stations are inherently insecure

URLhttp://medios.udg.mx/node/11157
AttachmentSize
The audio as transmitted (mp3)22.46 MB

Prácticas seguras de programación para sistemas Web

TitlePrácticas seguras de programación para sistemas Web
Publication TypeJournal Article
Year of Publication2009
AuthorsWolf G
Refereed DesignationRefereed
Journal TitleVentana informática
Issue21 (jul-dic 2009)
Pages91-111
Start Page91
Journal Date07/2009
Type of ArticleArtículo monográfico
ISSN0123-9678
Keywordscross-site scripting, galletas HTTP, inyecciones SQL, mapeo objeto-relacional, redefinición, resumen criptográfico, Seguridad en cómputo, sesiones HTTP, XSS
Abstract

El campo de la seguridad en cómputo muchas veces es visto como uno donde el trabajo es investigativo (búsqueda de nuevas categorías de fallos), reactivo (corrección de fallos encontrados, o incluso buscarlos proactivamente) o, en el peor de los casos, un campo donde los personajes más destacados son quienes saben abusar de los sistemas ajenos. Nada más lejano de la realidad — En la seguridad en cómputo, el rol más importante debe ser el desarrollador de sistemas, una de las piezas más importantes de la sociedad actual.

Este trabajo parte definiendo qué debemos entender por seguridad en cómputo, y por qué este concepto debe ir más allá de definiciones duras y frías, para reflejar que antes que otra cosa, el cómputo es una disciplina con la misma flexibilidad que los estudios humanísticos.

La parte medular del trabajo se centra en ejemplificar, analizando tres categorías de vulnerabilidad informática de alto perfil hoy en día (inyecciones de SQL, Cross-Site Scripting y manejo de sesiones a través de galletas HTTP), de especial relevancia para los sistemas Web desarrollados hoy en día — Y poco abordadas en específico por los principales textos con que se enseña la disciplina.

Full Text

La Evolución del rol que cumplen los sistemas en las organizaciones ha cambiado por completo -afortunadamente- el punto de vista que la mayor parte de los desarrolladores tiene con respecto a la seguridad.
Hace una o dos décadas, el tema de la seguridad en cómputo era frecuentemente evitado. Y hasta cierto punto, esto era muy justificable: ¿Intrusos? ¿Integridad? ¿Validaciones? Conceptos que hoy a todos parecen fundamentales eran vistos como distracciones teóricas que sólo entorpecían la usabilidad de los sistemas. En la década de los 80 había muy poco software diseñado para su operación en red, y mucho menos para la idea de red que tenemos hoy en día. Y si bien es cierto que la mayor parte de los ataques se origina -y siempre se ha originado- dentro del perímetro de confianza de nuestra organización, hace 20 años sencillamente había menos información sensible alojada en medios electrónicos, menos gente con el conocimiento necesario para manipularla, e incluso la manipulación tenía efectos más nocivos: Si bien hace años la infraestructura de cómputo era el soporte facilitador, la copia maestra estaba en papel - Hoy en día estamos transitando hacia la situación opuesta, en que la versión electrónica es la primaria. Hoy, una intrusión en nuestros sistemas puede poner en jaque la integridad de la información primaria.
Mantener la seguridad en los sistemas que desarrollamos implica un alto costo: Los programadores tienen que aprender a evitar errores comunes; tenemos que concientizarnos y acostumbrarnos a dedicar recursos a implementar baterías de pruebas; tienen que entrar en juego validaciones y conversiones sobre los datos que manipulamos, con costos en tiempos de procesamiento de cada solicitud... Pero, afortunadamente, ha crecido también la conciencia de la importancia de destinar a la seguridad la atención y recursos que requiere.
El problema sigue siendo, coloquialmente... /¿con qué se come?/ La seguridad en cómputo sigue siendo un campo dificil de entender, con muchas aristas ocultas. Es por esto que en este artículo abordaremos algunos temas fundamentales, que a pesar de ser bien conocidos, siguen siendo origen de un sinfín de nuevos sistemas creados con obvios agujeros.
1. ¿Qué es la seguridad en cómputo?
--------------------------------
A riesgo de que parezca perogrullada, un /sistema seguro/ no es otra cosa que un sistema /que responde como debe/, un sistema que /cubre las necesidades y requerimientos con que fue concebido/. Claro, a esta pregunta hay que verla a la luz de varios criterios para que en verdad signifique algo. Intentemos nuevamente. Un sistema seguro presenta:
Consistencia: Ante las mismas circunstancias, debe presentar el mismo comportamiento. Ante un sistema /seguro/, el tradicional remedio "¿ya intentaste reniciarlo?" no surte efecto. Si una grandísima proporción de usuarios se ha acostumbrado a que un reinicio resuelve las cosas, no es sino porque el ambiente de ejecución se ensucia con elementos que debería haber descartado - Y por tanto, podemos concluir que sistemas en cuestión son inherentemente inseguros.
Protección y separación: Los datos, instrucciones y espacio de memoria de un programa, componente o usuario no deben interferir ni permitir interferencia de otros. Las condiciones anormales ocurridas en uno de los componentes -sean accidentales o expresas- deben tener un impacto mínimo en el sistema como un conjunto.
Autenticación: El sistema debe poseer los mecanismos necesarios para asegurarse que un usuario es realmente quien dice ser.
Control de acceso: Nuestro sistema debe poder controlar con toda la granularidad necesaria los permisos de acceso a sus datos - Quién tiene acceso a qué recursos, y qué tipo de acceso tiene.
Auditoría: El sistema debe ser capaz de registrar, así como de notificar a quien sea necesario, de cualquier anomalía o evento importante.
Claro está, todos estos atributos deben ir matizados, priorizándolos al nivel /adecuado/ a nuestras necesidades. Ir demasiado lejos en uno de estos objetivos puede ser de hecho perjudicial para los fines de nuestro sistema - Por poner un ejemplo, es de todos bien conocido que el tradicional esquema de autenticación basado en usuario y contraseña es fácil de engañar; basta adivinar (o conseguir) un pedazo de información, típicamente de muy débil complejidad, para estar autenticado como determinado usuario. En México, desde hace algunos años, los bancos exigen la identificación del cliente a través de dispositivos que presenten una mucho mayor complejidad, generando cadenas de números que cambian periódicamente. Pero, obviamente, poca gente requerirá un nivel de seguridad similar a éste, o basado en parámetros biométricos, para abrir su cuenta de correo. Si bien es aceptable demandar que un usuario bancario tenga acceso al dispositivo como una medida de seguridad (lo cual es una inconveniencia, dado que muchos usuarios prefieren no cargarlo consigo constantemente - Precisamente pensando en la seguridad) es aceptable, requerir medidas similares para acceso al correo electrónico sería de inmediato criticado por todos los usuarios como excesivo y como limitante a la usabilidad.
Y otra anotación: Nos es natural aspirar a la perfección, al 100%. Sin embargo, dice el refrán que "lo perfecto es enemigo de lo bueno". Es importante que, en toda etapa de la planeación, desarrollo, implantación y tiempo de vida de un sistema recordemos que un 100% de seguridad es una utopía, un objetivo que sólo puede servir para guiar nuestro trabajo diario.
Los programas son escritos por humanos, y son también humanos quienes administran los sistemas en que corren. Hay una gran cantidad de interacciones entre los elementos de un programa y el sistema, y un cambio en cualquiera de ellos puede tener consecuencias inesperadas si no se hace con cuidado y conciencia. Constantemente aparecen nuevas categorías de errores capaces de llevar a problemas de seguridad. Parte fundamental de nuestra actuación como profesionales en nuestro campo debe ser el mantenernos al día con los últimos desarrollos y las últimas amenazas.
2. El estado actual de la seguridad en cómputo
-------------------------------------------
En un estudio publicado a inicios del 2009, SANS y MITRE (SANS/MITRE, 2009) publicaron la lista de los 25 errores de seguridad más importantes en frecuencia y relevancia. Este listado incluye muchos temas fundamentales, que deberían ser comprendidos por cualquier programador que se diga profesional. Vienen explicados con un buen nivel de detalle, detallando cómo evitar o mitigar sus efectos. Éste estudio ha contado con amplio apoyo por parte de diversos sectores tanto de la academia como de la industria.
Sin embargo, volviendo al punto con el que inicia el presente texto: En realidad, ¿el hecho de que ahora la seguridad en cómputo sea un tema que forma parte del inconsicente colectivo /realmente/ ha llevado al mejoramiento de la calidad general del código? Es muy posible que estemos ante un claro caso de falso sentido de seguridad.
Usuarios y programadores están al tanto del peligro que corren al utilizar un sistema informático. Obviamente, los programadores están (o por lo menos, deberían estar) más atentos, dado que se dedican profesionalmente al cómputo y que comprenden (o, nuevamente, deberían comprender) mucho mejor las interacciones que llevan a las principales vulnerabilidades. Sin embargo, una y otra vez nos topamos con sistemas con las mismas clases básicas de errores, de tremendos agujeros de seguridad a través de los cuales podrían pasar marchando regimientos completos.
¿Por qué sucede esto? En síntesis, podría resumirse en los siguientes factores:
• Confianza ciega en la propaganda de los proveedores. Prácticamente todos los proveedores de herramientas de desarrollo, de modelado, de verificación aseguran ser «la más segura». En el mundo del software propietario (en contraposición al Software Libre), muchos usuarios tienden a creer en la voz de los "gurúes" sin poderla verificar, dado que no pueden siquiera validar lo que éstos anuncian.
Si bien algunos modelos de programación de hoy en día /sí/ nos protegen de las más graves fallas técnicas, muchos programadores se sentirán mágicamente protegidos por la tecnología que tenga la mezcla correcta de palabras de moda, sin verdaderamente averiguar qué es lo que dichas palabras significan. No hay peor ceguera que la de quien no quiere ver, dicen — Y no hay peor profesional que el que cree en un acrónimo sin comprender su significado.
• Falta de actualización. Al estudiar acerca de los peligros relativos a la seguridad, seguimos pensando en las mayores amenazas de seguridad que fueron estudiadas y descubiertas hace décadas — Desbordamiento de pila (Wheeler, 2003), desbordamiento de enteros (Williams, 2009)... Sin embargo, pocos cursos relativos a la seguridad se han actualizado a los errores que plagan a la clase actual de aplicaciones, mayormente desarrolladas en marcos que inherentemente se protegen de estos graves errores de hace décadas.
• El «Síndrome NIH» (Not Invented Here - No Inventado Aquí (Wikipedia, 2008-2009a)) es un antipatrón de diseño definido como la tendencia a reinventar algo ya existente, basándose en la casi siempre falsa creencia de que un desarrollo llevado a cabo "en casa" resultará más adecuado, más seguro o más controlado que implementaciones ya existentes.
• Procedimientos tediosos. Muchos errores de diseño de sistemas podrían ser fácilmente paliados si los desarrolladores no tuvieran que llevar a cabo prácticas engorrosas o tediosas para evitarlos. Por poner un ejemplo, casi la totalidad de los lenguajes desarrollados en las últimas décadas liberan a sus desarrolladores del manejo (asignación, liberación) explícito de bloques de memoria. Si bien esto reduce sensiblemente la rapidez del software desarrollado y resta un poco de flexibilidad (imposibilita trabajar sobre conjuntos de datos con simple aritmética de apuntadores), evita por completo los principales problemas que plagaban al desarrollo de software en los años 80 y 90 — Como es mencionado dos párrafos atrás, los diversos tipos de desbordamiento, o errores típicamente no asociados con la seguridad, como las dobles liberaciones (MITRE, 2009-2009a) o las fugas de memoria (Erickson, 2002).
Es por esto que resulta tan importante enfatizar en explicar y enseñar respecto a las principales vulnerabilidades de que al día de hoy hay que cuidarse.
Una grandísima proporción de los sistemas desarrollados hoy en día, siguen el paradigma cliente-servidor. Y si bien hay muy diferentes maneras de implementar sistemas cliente-servidor, indudablemente la más difundida y prevalente hoy por hoy es la de los sistemas Web. Al mismo tiempo, dado medio mismo a través del cual se transporta y por el ámbito global que han adquirido muchos de éstos sistemas, que encontraremos bajo éste modelo de desarrollo la categoría más expuesta directamente a elementos hostiles — Esta es la razón por la que el presente artículo adopta un enfoque principalmente orientado a éste tipo de sistemas.
Si bien hay una tremenda cantidad de categorías en las cuales podríamos ahondar, juzgamos que los tres casos presentados a continuación son una buena muestra de las vulnerabilidades más comunes, peligrosas, y aquellas de las cuales es más importante estar consciente y atento al programar — O al auditar sistemas existentes.
3. Ejemplo 1: Inyecciones de SQL
-----------------------------
Las vulnerabilidades más comunes son también las más fáciles de explotar para un atacante - Y utilizando algunas prácticas base, son también las más fáciles de evitar o corregir: Casi todas ellas se originan en la falta de validación (o exceso de confianza) en los datos proporcionados por el usuario.
Prácticamente la totalidad de los sistemas desarrollados procesarán datos provenientes de terceros. Ya sea mostrando o grabando lo expresado en formas HTML, determinando el flujo de la aplicación a través de rutas y parámetros o «galletas» HTTP (ver sección 4), o incluso -considerando la tendencia de migración hacia un esquema de «cloud computing»- tomando resultados de procedimientos remotos en sistemas no controlados por nosotros, a cada paso es necesario emplear datos no confiables, o generados por una entidad no confiable.
Esta puerta de entrada permite a un atacante una amplia variedad de modalidades de intrusión. En general, podemos hablar de ellas como inyección de código interpretado - Dedicaremos nuestra atención a la inyección de SQL (Wikipedia, 2004-2009b).
En el desarrollo de sistemas debemos partir siempre del principio de mínima confianza: No debemos confiar en ningún dato proveniente de fuera de nuestro sistema, independientemente de quién sea el usuario. Esto es especialmente importante cuando requerimos que un elemento cruce entre las principales barreras de las diversas capas de nuestro sistema.
3.1 Comprendiendo la inyección
--------------------------
Tomaremos como ejemplo un URL típico generado por uno de los sistemas de administración de contenido (CMS) en boga hoy en día: Joomla. Por razones obvias, el nombre verdadero del sitio en cuestión ha sido reemplazado por «www.ejemplo.com».
http://www.ejemplo.com/content/view/825
Todos hemos analizado URLs, y resultará obvio que «825» corresponda al ID de la nota en la base de datos, y que los componentes «content» y «view» indiquen la operación que el sistema debe realizar ante una solicitud. Ahora bien, ¿a qué me refiero a que cruzamos las barreras entre las capas? ¿Y cuáles son las principales?
Enfoquémonos en el ID. Al analizar el URL, el ID es un pedazo de texto (formalmente es una cadena que es recibida como parte del método GET, uno de los métodos definidos para el protocolo HTTP). El servidor Web que recibe mi solicitud interpreta este método GET y encuentra -utilizando mod_rewrite, en caso de tratarse de un servidor Apache como la mayoría de los sitios de la red, a través de configuración típicamente indicada en el archivo .htaccess- que el contenido indicado por la ruta «/content/view/*» debe ser procesado por el archivo index.php, que a su vez (dada su terminación o demás reglas que pueden aplicarse) es manejado por el lenguaje PHP. El archivo index.php es provisto por el sistema Joomla, que reconoce la ruta, convierte al ID en su representación numérica y lo utiliza para pedir a la base de datos le entregue los datos relacionados con determinado artículo. Entonces, aquí podemos reconocer los siguientes puntos principales de manipulación de la solicitud:
• Apache recibe una solicitud HTTP, y (via mod_rewrite) la reescribe, indicando «content», «view» y «825» como parámetros a index.php
• PHP analiza, separa y estructura los parámetros recibidos para ser utilizados por Joomla
• Joomla solicita el artículo 825 a la base de datos
La variabilidad de los primeros pasos es en realidad menor - Pero al solicitar a la base de datos el artículo «825» (y este es el caso base, el más sencillo de todos) deben pasar muchas cosas. Primero que nada, «825» es una cadena de caracteres. PHP es un lenguaje débilmente tipificado (los números se convierten en cadenas y viceversa automáticamente según sea requerido), pero una base de datos maneja tipos estrictamente.
Un atacante, una persona que quiere causar daño u obtener acceso mayor al cual tiene autorizado en nuestro sistema, basará su acercamiento en ser creativo respecto a cómo engañar a nuestro sistema: Es muy poco frecuente que busque adivinar usuarios/contraseñas; más bien, intentará engañar al sistema para entregar resultados distintos de aquello que parece estar siendo solicitado. ¿Y cómo se engaña a un sistema? Pidiéndole algo que no se espere - Por ejemplo, «825aaa». En este caso (¡felicidades!), el código PHP que invoca a la base de datos sí verifica que el tipo de datos sea correcto: Hace una conversión a entero, y descarta lo que sobra. Sin embargo, en muchos sistemas desarrollados a en casa, una solicitud similar lleva a un mensaje como el siguiente:
Warning: pg_execute() [function.pg-execute]: Query failed: ERROR: invalid input syntax for integer: "825aaa" in /home/(...)/index.php on line 192
Esto indica que uno de los parámetros fue pasado sin verificación de PHP al motor de base de datos, y fue éste el que reconoció al error.
Ahora, esto no califica aún como inyección de SQL (dado que el motor de bases de datos supo reaccionar ante esta situación), pero estamos prácticamente a las puertas. El código desarrollado por una determinada persona en un lapso de tiempo dado tiende a repetir muchos patrones — Es casi un hecho que si desarrollador no validó la entrada en un punto, habrá muchos otros en que no lo haya hecho. Este error en particular nos indica que el código construye la cadena de consulta SQL a través de una interpolación parecida a la siguiente:
$id_art = $_GET['id'];
$sql = "SELECT * FROM articulo WHERE id = $id_art"
La vulnerabilidad aquí consiste en que el programador no tomó en cuenta que $id_art puede contener cualquier cosa enviada por el usuario - Por el atacante en potencia. ¿Cómo puede aprovecharse esto? No hay límites más que la imaginación.
Presentamos a continuación algunos ejemplos, evitando enfocarnos a ningún lenguaje en específico - Lo importante es el proceso y el tratamiento que se da al SQL generado.
Para estos ejemplos, cambiemos un poco el caso de uso — Nuevamente, recordando que errores derivados del estilo de codificación detectados en un punto muy probablemente se repitan a lo largo del programa. En vez de ubicar recursos, hablemos acerca de una de las operaciones más comunes: La identificación de un usuario vía login y contraseña. Supongamos que el mismo sistema del código recién mencionado utiliza la siguiente función para validar a sus usuarios:
$data = $db->fetch("SELECT id FROM usuarios WHERE login = '$login' AND passwd = '$passwd'");
if ($data) {
$uid = $data[0];
} else {
print "<h1>Usuario inválido!</h1>";
}
Aquí pueden apreciar la práctica muy cómoda y común de /interpolar/ variables dentro de una cadena - Muchos lenguajes permiten construir cadenas donde se expande el contenido de determinadas variables. En caso de que su lenguaje favorito no maneje esta característica, concatenar las sub-cadenas y las variables nos lleva al mismo efecto. Por ejemplo, en VisualBasic obtendríamos la misma vulnerabilidad construyendo nuestra cadena así:
Dim sql as String = "SELECT id FROM usuarios WHERE login = '" & login & "' AND passwd = '" & passwd & "'"
Sin embargo... ¿Qué pasaría aquí si el usuario jugara un pequeño truco? Si solicitara, por ejemplo, entrar al sistema utilizando como login a «fulano';--», esto llevaría al sistema a ignorar lo que nos diera por contraseña: Estaríamos ejecutando la siguiente solicitud:
SELECT id FROM usuarios WHERE login = 'fulano';--' AND PASSWD = ''
La clave de este ataque es confundir a la base de datos para aceptar comandos generados por el usuario - El ataque completo se limita a cuatro caracteres: «';--». Al cerrar la comilla e indicar (con el punto y coma) que termina el comando, la base de datos entiende que la solicitud se da por terminada, y cualquier cosa que siga es otro comando. Podríamos enviarle más de un comando consecutivo que concluyera de forma coherente, pero lo más sencillo es utilizar el doble guión indicando que inicia un comentario. De este modo, logramos vulnerar la seguridad del sistema, entrando como un usuario cuyo login conocemos, aún desconociendo su contraseña.
Pero podemos ir más allá - Siguiendo con este ejemplo, típicamente el ID del administrador de un sistema es el más bajo. Imaginen el resultado de los siguientes nombres de usuario falsos:
ninguno' OR id = 1;--
«ninguno» no es un usuario válido del sistema, pero ésto resultaría en una sesión con privilegios de administrador.
'; INSERT INTO usuarios (login, passwd) VALUES ('fulano', 'de tal'); --
Esto no otorgaría en un primer momento una sesión válida, pero crearía una nueva cuenta con los valores especificados. Obviamente, es posible que fuera necesario averiguar -a prueba y error- qué otros valores es necesario agregar para que ésto nos otorgue un usuario válido con suficientes privilegios.
'; DROP TABLE usuarios; --
Un atacante puede darse por satisfecho con destruir nuestra información. En este caso, el atacante destruiría de un plumazo nuestra tabla de usuarios. Me es imposible dejar de sugerirles visitar al ya famoso «Bobby Tables» (Munroe, 2007).
3.2 Evitando las inyecciones de SQL
-------------------------------
¿Y qué podemos hacer? Protegerse de inyección de SQL es sencillo, pero hay que hacerlo en prácticamente todas nuestras consultas, y convertir nuestra manera natural de escribir código en una segura.
La regla de oro es nunca cruzar fronteras incorporando datos no confiables - Y esto no sólo es muy sencillo, sino que muchas veces (específicamente cuando iteramos sobre un conjunto de valores, efectuando la misma consulta para cada uno de ellos) hará los tiempos de respuesta de nuestro sistema sensiblemente mejores. La respuesta es separar /preparación/ y /ejecución/ de las consultas. Al preparar una consulta, nuestro motor de bases de datos la compila y prepara las estructuras necesarias para recibir los parámetros a través de «placeholders», marcadores que serán substituídos por los valores que indiquemos en una solicitud posterior. Volvamos al ejemplo del login/contraseña. En este caso, presentamos el ejemplo como sería construído desde el lenguaje Perl:
$query = $db->prepare('SELECT id FROM usuarios WHERE login = ? AND passwd = ?');
$data = $query->execute($login, $passwd);
Los símbolos de interrogación son enviados como literales a nuestra base de datos, que sabe ya qué le pediremos y prepara los índices para respondernos. Podemos enviar contenido arbitrario como login y password, ya sin preocuparnos de si el motor lo intentará interpretar.
Algunos lenguajes y bibliotecas de acceso a bases de datos (notablemente, la popular combinación PHP+MySQL) no implementan la funcionalidad necesaria para separar los pasos de preparación y ejecución. La respuesta en dichos lenguajes es utilizar funciones que /escapen/ explícitamente los caracteres que puedan ser nocivos. En el caso mencionado de PHP+MySQL, esta función sería mysql_real_escape_string (Achour, 1997-2009):
$login = mysql_real_escape_string($_GET['login']);
$passwd = mysql_real_escape_string($_GET['passwd']);
$query = "SELECT id FROM usuarios WHERE login = '$login' AND passwd = ''";
$data = $db->fetch($query);
Una gran desventaja que ésto conlleva es la cantidad de pasos que el programador debe efectuar manualmente — Especialmente cuando entran en juego mayores cantidades de datos, y hay que verificar a cada uno de ellos. Cabe mencionar que las bibliotecas que implementan conectividad a otras bases de datos para PHP (por ejemplo, PostgreSQL) sí ofrecen las facilidades necearias para la preparación y ejecución como dos pasos separados, con una semántica muy similar a la anteriormente descrita.
Revisar todas las cadenas que enviamos a nuestra base de datos puede parecer una tarea tediosa, pero ante la facilidad de encontrar y explotar este tipo de vulnerabilidades, bien vale la pena. En las referencias (Mavituna, 2007), (Microsoft, 2009), (Friedl, 2007) podrán encontrar información mucho más completa y detallada acerca de la anatomía de las inyecciones SQL, y diversas maneras de explotarlas aún incluso cuando existe cierto grado de validación.
3.3 Alternativa específica: El uso de ORMs
--------------------------------------
Otra alternativa interesante que todo programador debe conocer es el uso de marcos de abstracción, como los mapeos objeto-relacionales (ORMs (Wikipedia, 2007-2009c)). Estos marcos se encargan de crear todo el "pegamento" necesario para hermanar a dos mundos diferentes (el de las bases de datos relacionales, basados en registros almacenados en tablas, y el de la programación orientada a objetos, basado en objetos instanciados de clases), mundos que comparten algunas características (estructura homogénea a todos los elementos del mismo tipo) pero no otras (manejo de relaciones complejas como composición o agregación). Pero, en el ámbito aquí discutido, la principal característica de los ORMs es que se encargan de cubrir los detalles relativos a la integración de dos lenguajes y dos formas de ver al mundo muy distintas. Uno de los grandes atractivos de los ORMs es que, entre otras muchas ventajas, su uso nos puede liberar por completo (o en una gran medida) de escribir directamente código SQL en la totalidad de nuestro proyecto.
Una solicitud similar a la anterior a través del ORM ActiveRecord en el lenguaje Ruby sería sencillamente:
usuario = Usuario.find_by_login(login, :conditions => 'passwd = ?', passwd)
En este caso, sería directamente la biblioteca la que convierte una llamada find a la clase Usuario (que hereda de ActiveRecord::Base) en una consulta SQL, escapa/limpia las entradas y envía la solicitud a la base de datos. Esto proporciona la ventaja adicional de que todo el código relativo al paso de parámetros a la base de datos está concentrado en un sólo punto (y en un punto ampliamente utilizado y escrutado por profesionales de todo el mundo); toda omisión o error que vaya siendo detectado llevará a que éste sea corregido en un sólo punto — Y nuestra aplicación recibirá, en todas las consultas que pasen a través del ORM, el beneficio de esta mejoría. Además, estando desarrollada verdaderamente en un sólo lenguaje, la aplicación se mantiene más limpia y resulta más fácil de comprender y depurar.
ActiveRecord es sólo uno de muchos ORMs existentes; está implementado para Ruby (Heinemeier, 2004-2009) y para .NET (Verissimo, 2003-2009), y hay implementaciones muy cercanas a este patrón en varios otros lenguajes.
4. Ejemplo 2: Cross-Site Scripting (XSS)
-------------------------------------
Como ya mencionamos, las inyecciones se presentan cuando /cruzamos fronteras/. Las inyecciones SQL no son, ni mucho menos, el único tipo de inyección de código malicioso; cualquier lugar en que un mismo dato puede significar cosas diferentes dependiendo del contexto en que es evaluado es susceptible a ser vulnerable a inyección. Las siguientes categorías las menciono únicamente para invitar al lector a empaparse en la problemática que conllevan.
Del mismo modo que debemos /sanitizar/ (limpiar, escapar) los datos que llevamos hacia abajo a través de las capas del diseño de nuestro sistema, debemos hacer lo mismo al subir. ¿Qué significa esto? Que no sólo debemos proteger las capas privadas de nuestra aplicación, a las cuales un posible atacante no debería tener acceso directo, sino que debemos también proteger a las capas superiores — Aquellas que están incluso fuera de nuestro control — Como el navegador de nuestros demás usuarios (MITRE, 2008-2009b).
En un sistema Web (especialmente si queremos participar de eso a lo que llaman /Web 2.0/, muchas veces desplegaremos a un usuario información provista por otros usuarios. Para ofrecer toda la funcionalidad y respuesta ágil de un sitio moderno, los navegadores están típicamente configurados para ejecutar todo código JavaScript que reciben, confiando en quien lo origina. Ahora, ¿qué pasaría si un usuario malicioso deja en un blog el siguiente comentario?
window.location="http://www.hackme.org/1234";
En efecto, inmediatamente al cargar la página en cuestión, el usuario sería redirigido a un sitio diferente (y con justa razón: Para su navegador, ésta indicación viene del sitio, no puede saber que viene de un elemento hostil).
Éste sitio podría hacerse pasar por el sitio víctima, sin que el usuario se diera cuenta, y podría llevar al usuario a diferentes escenarios donde se le extrajera información confidencial - Por ejemplo, se le puede pedir que se vuelva a autenticar. La mayor parte de los usuarios caerán en el engaño, con lo que éste puede volverse un potente mecanismo para suplantación de identidad.
Por si no bastara, cada usuario, obviamente, tiene un perfil diferente — y normalmente, nivel o credenciales de acceso también diferentes. ¿Qué pasaría si el código JavaScript fuera muy ligeramente más malicioso? Por ejemplo (y nuevamente, meramente como ejemplo ficticio), podría hacer que un administrador le diera acceso completo al sitio. Si el atacante recibió el usuario número 152, podría enviar un mensaje privado al administrador del sitio que incluyera:
window.location="/admin/user/152/edit?set_admin=1";
Claro está, asignar una nueva dirección a window.location es probablemente la manera más burda y notoria para llevar a cabo estos ataques; hay muchas maneras más sigilosas, que pueden pasar completamente desapercibidas por un usuario casual.
Este tipo de ataques son conocidos genéricamente bajo el nombre de /XSS/ o /Cross-Site Scripting/ (MITRE, 2008-2009c). La clave para evitarlos es nuevamente sanitizar toda la información — Pero en este caso, toda la información a enviar al cliente. En el caso de HTML, prácticamente basta con escapar ciertas /entidades/ (caracteres que pueden tener significados especiales). Por ejemplo, reemplazando todos los caracteres «<» por su representación «<» y todos los caracteres
«>» por «>» (como primer acercamiento), éste código será desplegado de una manera limpia. Éste es típicamente un proceso aún más engorroso que sanitizar la entrada, por la cantidad de puntos donde hay que repetir la validación. Dependiendo del caso, muchos desarrolladores optan por limpiar a la entrada todo lo que será eventualmente desplegado — pero esto puede llevar al usuario a algunas condiciones en que el navegador no lo /des-sanitiza/, resultando sencillamente en una salida aparentemente llena de basura.
Como nota adicional: Es posible (y altamente deseable) sanitizar toda la información a la entrada, desechando todo lo que no sea claramente aceptable. Sin embargo, siempre hay casos en que requerimos guardar la información completa y sin manipular.
Si bien evitar XSS es más dificil que evitar inyecciones de SQL. A pesar de que el impacto de XSS, a primera vista, es menos severo que el de una inyección de SQL, éste puede tardar mucho más tiempo en ser corregido, puede estar presente en más puntos de nuestro código, y por sobre todo, es más tedioso de arreglar — Por lo que es fundamental acostumbrarnos a verificar toda la información que despleguemos /a tiempo/.
Además, si bien el impacto es menos inmediato, es típicamente más sigiloso. Si un atacante obtiene la información de acceso de una gran cantidad de usuarios, para propósitos prácticos no podemos volver a confiar en ninguno de nuestros usuarios — Todos pueden estar potencialmente controlados por el atacante.
5. Ejemplo 3: Manejo de sesiones a través de galletas HTTP
-------------------------------------------------------
La conjunción de un protocolo verdaderamente simple para la distribución de contenido (HTTP) con un esquema de marcado suficientemente simple pero suficientemente rico para presentar una interfaz de usuario con la mayor parte de las funciones requeridas por los usuarios (HTML) crearon el entorno ideal para el despliegue de aplicaciones distribuídas.
Desde sus principios, el estándar de HTTP menciona cuatro /verbos/ por medio de los cuales se puede acceder a la información: GET (solicitud de información sin requerir cambio de estado), POST (interacción por medio de la cual el cliente manda información compleja y que determinará la naturaleza de la respuesta, así como posibles cambios de estado del lado del servidor), PUT (creación de un nuevo objeto en el servidor) y DELETE (destrucción de un determinado objeto en el servidor). Sin embargo, por muchos años, los verbos fueron mayormente ignorados — La mayor parte de los sistemas hace caso omiso a través de qué verbo llegó una solicitud determinada; muchos navegadores no implementan siquiera PUT y DELETE, dado su bajísimo nivel de uso — Aunque con la popularización del paradigma REST (Costello, s.f.), principalmente orientado a servicios Web (interfaces expuestas vía HTTP, pero orientadas a ser consumidas/empleadas por otros programas, no por humanos), esto probablemente esté por cambiar.
El protocolo HTTP, sin embargo, junto con su gran simplicidad aportó un gran peligro — No una vulnerabilidad inherente a los sistemas Web, sino que un peligro derivado de que muchos programadores no presten atención a un aspecto fundamental de los sistemas Web: Cómo manejar la interacción repetida sobre de un protocolo que delega el mantener el estado o /sesión/ a una capa superior. Esto es, para un servidor HTTP, toda solicitud es única. En especial, un criterio de diseño debe ser que toda solicitud GET sea /idempotente/ — Esto significa que un GET no debe alterar de manera significativa el estado de los datos — Es aceptable que a través de un GET, por ejemplo, aumente el contador de visitas, (que haya un cambio no substantivo) — Pero muchos desarrolladores han sufrido por enlazar a través de un GET (como todo navegador responde a una liga HTML estándar), por ejemplo, el botón para eliminar cierto objeto.
¿Cuál es el peligro? Que diversas aplicaciones, desde los robots indexadores de buscadores como Google y hasta aceleradores de descargas ingenuos que buscan hacer más ágil la navegación de un usuario (siguiendo de modo preventivo todas las ligas GET de nuestro sistema para que el usuario no tenga que esperar en el momento de seleccionar alguna de las acciones en la página) van a disparar éstos eventos de manera inesperada e indiscriminada.
HTTP fue concebido (Berners-Lee, 1996) como un protocolo a través del cual se solicitaría información estática. Al implementar las primeras aplicaciones sobre HTTP, nos topamos con que cada solicitud debía incluir la totalidad del estado. En términos de redes, TCP implementa exclusivamente la capa 4 del modelo OSI, y si bien mantiene varios rasgos que nos permiten hablar tambien de /sesiones/ a nivel conexión, estas son sencillamente descartadas. Las capas 5 y superiores deben ser implementadas a nivel aplicación. HTTP es un protocolo puramente capa 6 (omite toda información relacionada con la sesión y sirve únicamente para presentar ya sea la aplicación o el contenido estático). Es por esto que los muchos sistemas Web hacen un uso extensivo de los campos ocultos (hidden) en todos sus formularios y ligas internas, transportando los valores de interacciones previas que forman parte conceptualmente de una sóla interacción distribuída a lo largo de varios formularios, o /números mágicos/ que permiten al servidor recordar desde quién es el usuario en cuestión hasta todo tipo de preferencias que ha manifestado a lo largo de su interacción.
Sin embargo, éste mecanismo resulta no sólo muy engorroso, sino que muy frágil: Un usuario malicioso o curioso puede verse tentado a modificar estos valores; es fácil capturar y alterar los campos de una solicitud HTTP a través de herramientas muy útiles para la depuración. E incluso sin estas herramientas, el protocolo HTTP es muy simple, y puede "codificarse" a mano, sin más armas que un telnet abierto al puerto donde escucha nuestro sistema. Cada uno de los campos y sus valores se indican en texto plano, y modificar el campo «user_id» es tan fácil como decirlo.
En 1994, Netscape introdujo un mecanismo denominado /galletas/ (cookies) que permite al sistema almacenar valores arbitrarios en el cliente. Éste mecanismo indica que todas las galletas que defina un servidor a determinado cliente serán enviadas en los encabezados de cada solicitud que éste le realice, por lo que se recomienda mantenerla corta — Atendiendo a esta recomendación, varias implementaciones de galletas no soportan más de 4KB. Un año más tarde, Microsoft lo incluye en su Internet Explorer; el mecanismo fue estandarizado en 1997 y extendido en el 2000 con (Kristol, Montulli, 1997) y (Kristol, Montulli, 2000). El uso de las galletas libera al desarrollador del engorro antes mencionado, y le permite implementar fácilmente un esquema verdadero de manejo de sesiones — Pero, ante programadores poco cuidadosos, abre muchas nuevas maneras de —adivinaron— cometer errores.
Dentro del cliente (típicamente un navegador) las galletas están guardadas bajo una estructura de doble diccionario — En primer término, toda galleta pertenece a un determinado servidor (esto es, al servidor que la envió). La mayor parte de los usuarios tienen configurados a sus navegadores, por privacidad y por seguridad, para entregar el valor de una galleta únicamente a su dominio origen (de modo que al entrar a un determinado sitio hostil éste no pueda robar su sesión en el banco); sin embargo, todo sistema puede solicitar galletas arbitrarias guardadas en el cliente. Para cada servidor, pueden almacenarse varias galletas, cada una con una diferente llave, un nombre que la identifica dentro del espacio del servidor. Además de estos datos, cada galleta guarda la ruta a la que ésta pertenece, si requiere seguridad en la conexión (permitiendo sólo su envío a través de conexiones cifradas), y su periodo de validez, pasado el cual serán consideradas "rancias" y ya no se enviarán. El periodo de validez se mide según el reloj del cliente.
Guardar la información de estado del lado del cliente es riesgoso, especialmente si es sobre un protocolo tan simple como HTTP. No es dificil para un atacante modificar la información enviada al servidor, y si bien en un principio los desarrolladores guardaban en las galletas la información de formas parciales, llegamos a una regla de oro: Nunca guardar información real en ellas. En vez de esto, es recomendado guardar un /token/ (literalmente, ficha o símbolo) que /apunte/ a la información. Esto es, en vez de guardar el ID de un usuario, debe enviarse una cadena /criptográficamente fuerte/ (Wikipedia, 2004-2009d) que apunte a un registro en la base de datos del servidor. ¿A qué me refiero con esto? A que tampoco grabe directamente el ID de la sesión (dado que siendo sencillamente un número, sería para un atacante trivial probar con diferentes valores hasta "aterrizar" en una sesión interesante), sino una cadena aparentemente aleatoria, creada con un algoritmo que garantice una muy baja posibilidad de colisión y un espacio de búsqueda demasiado grande como para que un atacante lo encuentre a través de la fuerza bruta.
Los algoritmos más comunes para este tipo de uso son los llamados funciones de resumen (digest) (Wikipedia, 2001-2009e). Estos generan una cadena de longitud fija; dependiendo del algoritmo, hoy en día van de los 128 a los 512 bits. Las funciones de resumen más comunes hoy en día son las variaciones del algoritmo SHA desarrollado por el NIST y publicado en 1994; usar las bibliotecas que los implementan es verdaderamente trivial. Por ejemplo, usando Perl:
use Digest::SHA1;
print Digest::SHA1->sha1_hex("Esta es mi llave");
nos entrega la cadena:
c3b6603b8f841444bca1740b4ffc585aef7bc5fa
Pero, ¿qué valor usar para enviar como llave? Definitivamente no serviría enviar, por ejemplo, el ID de la sesión - Esto nos dejaría en una situación igual de riesgosa que incluir el ID del usuario. Un atacante puede fácilmente crear un diccionario del resultado de aplicar SHA1 a la conversión de los diferentes números en cadenas (mecanismo conocido como «rainbow tables», tablas arcoíris; hay varios proyectos [10] que han construido tablas para diversas aplicaciones, como la recuperación de contraseñas en sistemas Windows). La representacíon hexadecimal del SHA1 de '1' siempre será d688d9b3d3ba401b25095389262a3ecd2ad5ad68, y del de 100 siempre será daaaa8121aa28fca0edb4b3e1f7b7c23d6152eed; el identificador de nuestra sesión debe contener elementos que varíen según algún dato no adivinable por el atacante (como la hora exacta del día, con precisión a centésimas de segundo) o, mejor aún, con datos aleatorios.
Este mecanismo nos lleva a asociar una cadena suficientemente aleatoria como para que asumamos que las sesiones de nuestros usuarios no serán fácilmente "secuestradas" (esto es, que un atacante no le atinará al ID de la sesión de otro usuario), permitiéndonos dormir tranquilos sabiendo que el sistema de manejo de sesiones en nuestro sistema es prácticamente inmune al ataque por fuerza bruta.
Como último punto: Las galletas son muchas veces vistas como un peligro por los activistas de la privacidad y el anonimato, dado que permiten crear un perfil de las páginas que va visitando un usuario (especialmente en el caso de empresas como Google o DoubleClick, que han sido especialmente exitosas en ofrecer herramientas de anuncios o de monitoreo/estadísticas a muy diversos administradores de sitios en todo el mundo). Es importante recordar que algunas personas han elegido desactivar el uso de galletas en su navegación diaria, a excepción de los sitios que expresamente autoricen. Tomen en cuenta que una galleta puede no haber sido guardada en el navegador cliente, y esto desembocará en una experiencia de navegación interrumpida y errática para dichos usuarios. Es importante detectar si, en el momento de establecer una galleta, ésta no fue aceptada, para dar la información pertinente al usuario, para que sepa qué hacer y no se encuentre frente a un sistema inoperativo más.
6. Conclusiones
------------
A lo largo de este artículo revisamos tres de las principales categorías de vulnerabilidades/errores de programación que, a juicio del autor, más prevalentes y peligrosas resultan hoy en día. Ahora bien, no es casualidad que el encabezado de cada una de las secciones correspondientes fuera «Ejemplo» — Con este artículo no implico que baste con estar conciente y alerta ante éstas amenazas para dejar de lado las demás.
La seguridad en cómputo, si bien es un campo fascinante, es un campo que requiere de constante actualización. Además, si bien éste artículo se enfoca a las vulnerabilidades más comunes en servicios Web, no es ni busca ser comprehensivos — Hay amplísimas categorías a las cuales no nos acercamos siquiera, y eso no debe leerse como que carezcan de importancia — Las tres categorías analizadas son meramente ejemplos de lo que hay que tener en mente.
Ser desarrollador de sistemas es una profesión demandante. Para cumplirla a cabalidad, requiere estar al día en lo tocante a seguridad — No estarlo significa una irresponsabilidad ante usuarios o clientes de nuestro desarrollo.
La sociedad depende más que nunca de la sistematización de los procesos y de la capacidad de sustentarlos a distancia. Los programadores, y muy en especial los programadores de sistemas en red, se han vuelto piezas fundamentales del tejido social. Es fundamental que reconozcamos y aceptemos nuestro nuevo rol responsablemente. Es fundamental que quienes nos decimos y nos sentimos desarrolladores de sistemas comprendamos la importancia de nuestro trabajo para la sociedad toda, y actuemos en consecuencia.
BIBLIOGRAFÍA
ACHOUR, Mehdi; BETZ, Friedhelm; DOVGAL, Antony et. al. (1997-2009)
PHP Manual [en línea]
Página: mysql_real_escape_string
[Consulta: 08/2009]
BERNERS-LEE, Tim (1996) The Original HTTP as defined in 1991 [en línea]
[Consulta: 08/2009]
COSTELLO, Roger (s.f.) Building Web Services the REST Way [en línea]
[Consulta: 08/2009]
ERICKSON, Cal (2002) Memory Leak Detection in Embedded Systems.
En: Linux Journal, N° 101 (sep 2002) Beltdown Media, ISSN 1075-3583
FRIEDL, Steve (2007) SQL Injection Attacks by Example [en línea]
[Consulta: 08/2009]
HEINEMEIER, David (2004-2009) ActiveRecord para Ruby [en línea]
[Consulta: 08-2009]
KRISTOL, David M and MONTULLI, Lou (1997) RFC 2109: HTTP State
Management Mechanism [en línea]
[Consulta: 08/2009]
KRISTOL, David M and MONTULLI, Lou (2000) RFC 2965: HTTP State
Management Mechanism [en línea]
[Consulta: 08/2009]
MAVITUNA, Ferruh (2007) SQL Injection Cheat Sheet [en línea]
[Consulta: 08/2009]
MICROSOFT (2009) SQL Server 2008 Product Documentation - SQL Server
2008 Books Online - Threat and Vulnerability Mitigation - SQL
Injection [en línea]
[Consulta: 08/2009]
MITRE (2008-2009a) Common Weakness Enumeration (CWE) 415: Double Free [en línea]
[Consulta: 08/2009]
MITRE (2008-2009b) Common Weakness Enumeration (CWE) 116: Improper
Encoding or Escaping of Output [en línea]
[Consulta: 08/2009]
MITRE (2008-2009c) Common Weakness Enumeration (CWE) 79: Failure to
Preserve Web Page Structure ('Cross-site Scripting') [en línea]
[Consulta: 08/2009]
MUNROE, Randall (2007): Webcomic xcdr [en línea].
[Consulta: 08/2009]
SANS/MITRE (2009) TOP 25 Most Dangerous Programming Errors [en línea]
[Consulta: 08/2009]
SHMOO GROUP (2005-2006) Rainbow Tables [en línea]
[Consulta: 08/2009]
VERISSIMO, Hamilton et. al. (2003-2009) Castle ActiveRecord [en línea]
[Consulta: 08-2009]
WHEELER, David A. (1999-2003) Secure Programming for Linux and Unix
HOWTO; capítulo 6: Avoid Buffer Overflow [en línea]
[Consulta: 08/2009]
WIKIPEDIA (2008-2009a), Not Invented Here [en línea].
[Consulta: 08/2009]
WIKIPEDIA (2004-2009b) SQL Injection [en línea].
[Consulta: 08/2009]
WIKIPEDIA (2007-2009c) Mapeos objeto-relacionales [en línea]
[Consulta: 08-2009]
WIKIPEDIA (2004-2009d) Cryptographic hash function [en línea]
[Consulta: 08/2009]
WIKIPEDIA (2001-2009e) SHA hash functions [en línea]
[Consulta: 08/2009]
WILLIAMS, Jeff, et. al. (2006-2009) Integer overflow [en línea].
OWASP: the free and open application security community
[Consulta: 08/2009]

AttachmentSize
Versión impresa (PDF)395.62 KB

Asegurando tu red con Linux

Written in...: 
2005

Short text going over several tools that can help a system administrator work on incident prevention, network monitoring and intrusion detection in Linux. I presented this talk in UNAM's Departamento de Seguridad en Cómputo internal admin-unam seminar, in June 2005. It was also published in the August 2005 issue of PC Magazine en español.

Resumen: 

Texto corto mencionando diversas herramientas que pueden ayudar a un administrador de sistemas implementar prevención de incidentes, monitoreo de red y detección de intrusos en Linux. Presenté esta plática en el seminario interno Admin-UNAM del Departamento de Seguridad en Cómputode la UNAM, en junio de 2005. Fue publicado además en la revista de agosto de 2005 de PC Magazine en español.

Respaldos multinivel robustos y simples utilizando rsync

Written in...: 
2005

Are you looking for an easy to implement backup solution that allows you to have incremental backups, with low resources consumption, and allowing for immediate retrieval of your data? Rsync and the basic characteristics of any Unix filesystem can be your greatest allies. I prepared this talk for the Admin-UNAM December 2005 seminary, organized by the Computer Security Department, DGSCA, UNAM.

Resumen: 

¿Buscas una solución de respaldos simple de implementar, con bajo uso de recursos, que te permita tener respaldos incrementales disponibles de inmediato? Rsync y las características del sistema de archivos de cualquier Unix pueden ser tu principal aliado - Preparé esta plática para el seminario Admin-UNAM de diciembre del 2005, organizado por el Departamento de Seguridad en Cómputo, DGSCA, UNAM.

AttachmentSize
Respaldos con rsync — Presentación en PDF624.11 KB
Respaldos con rsync — Fuente en LaTeX Beamer146.86 KB

Principios para mantener la seguridad en redes TCP/IP

Written in...: 
2004

This talk was prepared for IV National Free Software Conference in Universidad Mayor, Real y Pontificia
de San Francisco Xavier de Chuquisaca
, Sucre, Bolivia. This is more or less the second part for my Network security talk, bringing down to earth some of the concepts to more concrete solutions (although still fairly generic).
I presented it in 2005 for UNAM's Computer Security Department's Admin-unam internal seminar; I re-wrote it as a full-text article, also available here.

Resumen: 

Plática preparada para el IV Congreso Nacional de Software Libre en la Universidad Mayor, Real y Pontificia
de San Francisco Xavier de Chuquisaca
, Sucre, Bolivia. Es una continuación a la plática de Seguridad en redes, aterrizando algunos de los conceptos a soluciones más concretas (aunque aún bastante genérico).
Presenté este trabajo en 2005 para el seminario interno Admin-UNAM del ; re-escribí el material como un artículo a texto completo, también disponible aquí.

Evolución de los esquemas de seguridad extendidos en Unix

Written in...: 
2003

This talk was prepared for the National Free Software Conference CONSOL 2003 and for Computer Security DGSCA/UNAM 2003 Conference. I analize the main ideas that were used for designing Multics, which of those ideas were adapted for the Unix model, which main shortcomings the traditional Unix model has, and what ideas have evolved to make Unix better.

Resumen: 

Plática preparada para el Congreso Nacional de Software Libre CONSOL 2003 y para el Congreso de Seguridad en Cómputo DGSCA/UNAM 2003. Analizo las ideas principales que fueron empleadas en Multics, cuáles de ellas fueron adaptadas para el modelo de Unix, qué carencias tiene el modelo tradicional de Unix, y qué propuestas ha habido para mejorarlo.

Los sniffers y las redes Ethernet

Written in...: 
2003

I presented this tutorial at Computer Security DGSCA/UNAM 2003 Conference. I talk about the basic characteristics for an Ethernet network, what is sniffing, some sniffers useful for a network administrator, and some advices for protecting against unauthorized sniffers in our network.

Resumen: 

Presenté este tutorial en el Congreso de Seguridad de Cómputo DGSCA/UNAM 2003, menciono en ella las características básicas del funcionamiento de las redes Ethernet, qué es el sniffing, varios sniffers útiles para un administrador, y algunos consejos para protegernos de sniffers no autorizados en nuestra red.

Preguntas y respuestas relativas a la seguridad en redes inalámbricas

Written in...: 
2002

I was invited to give a talk on wireless networks to 27 Simposium Internacional de Sistemas Computacionales y Tecnologías de la Información, organized by Tecnológico de Monterrey.
I did not prepare a presentation or slides, so instead of that, I promised I would answer to every question made by the audience. Here are the promised answers.

Resumen: 

Fui invitado a dar una conferencia de Seguridad en Redes Inalámbricas al 27 Simposium Internacional de Sistemas Computacionales y Tecnologías de la Información, organizado por el Tecnológico de Monterrey. A falta de llevar una presentación
preparada, me comprometí a responder a todas las preguntas que me hicieron por escrito los asistentes. Aquí están, pues, las respuestas.

Si quieres agregar algo a esta página, ya sea enviarme una pregunta adicional, ampliar una respuesta, o lo que sea, mándame un correo.

Preguntas relativas al software libre

  1. ¿Qué diferencia hay entre software libre y gratuito?
  2. ¿Qué tan confiable es su sistema si est&aacute programado en un sistema operativo que cualquier persona puede modificar?
  3. ¿Cuál será el sistema operativo más seguro?
  4. ¿Qué ventajas da Linux o Unix contra Windows Server 2000? ¿Es seguro?
  5. Actualmente, ¿Qué desarrollos ha habido en Linux para el Internet Móvil?

Preguntas relativas a la seguridad en general

  1. ¿Qué medidas podemos tomar para tener una red segura?
  2. ¿Qué programa me ayudaría a encontrar contraseñas de usuarios de Internet
  3. ¿Con qué programa puedo proteger mejor mis redes?
  4. ¿Qué páginas Web recomienda para adentrarnos más y aprender sobre seguridad?
  5. ¿Cómo estructuraría un buen cifrado para que sea segura la red?

Preguntas relativas a la seguridad en redes inalámbricas


  1. ¿Cómo se conectó a la red del Tec?

    ¿Cómo puedo conectarme a una red inal´mbrica con una PC (laptop)? ¿Se tiene que hacer alguna configuración?


  2. ¿Para qué son las antenas?

  3. ¿WEP es la mejor opción en cuanto a la seguridad en redes, o hay alguna mejor?

  4. ¿A qué se debe que gran parte de las organizaciones que utilizan redes inalámbricas no cuentan con la seguridad necesaria en ellas?

  5. ¿No es posible tener una WLAN con varias llaves privadas para cada usuario y con un algoritmo como RSA o más avanzado que permita una alta seguridad al usuario, o incluso es fácil desencriptar usando estos algoritmos?

Bibliografía empleada la preparación de esta plática

Investigaciones formales

Notas de prensa

Otros documentos

Bibliografía útil que no tuve a tiempo para la plática

Preguntas relativas al software libre

  1. ¿Qué diferencia hay entre software libre y gratuito?
    Esta tan común y desafortunada confusión se debe a que en inglés la palabra para definir libertad y gratuidad es la misma -- free. En español, afortunadamente, tenemos dos conceptos muy sencillos y fáciles de diferenciar:
    • Gratuito significa que no cuesta nada. Es un término aplicable al valor monetario de, en este caso, el programa. Por ejemplo, el navegador Opera y el cliente de correo Eudora son software gratuito, que subsanan su costo por medio de la inserción de publicidad. De hecho, también el navegador Internet Explorer y el cliente de correo Outlook Express de Microsoft son software gratuito.
    • Libre significa que nos da libertad. ¿Qué tipos de libertad? para una explicación más a profundidad, puedes visitar los sitios de la Free Software Foundation, la Open Source Initiative, el proyecto Debian. Hay importantes diferencias entre los puntos de vista de los organismos que menciono, pero todos ellos concuerdan en las siguientes libertades básicas:
      • Libertad de utilizarlo: Un programa libre no debe estar restringido para su uso a ningún sector de la población, ni con ningún fin específico. Por ejemplo, restringir el libre uso de un programa a ser empleado sólamente en entornos académicos o prohibir que sea utilizado con fines militares lo descalificaría como software libre.
      • Libertad de aprender de él: Es muy importante para un programador aprender de lo que hicieron otros programadores, Esto le evita duplicar esfuerzos, le permite aprender de los errores de terceros, le da la posibilidad de incluir el código hecho por alguna otra persona en sus programas en vez de tener que reescribir la solución a problemas que ya han sido resueltos.
      • Libertad de modificarlo: Si un programa hace algo muy parecido a lo que necesito, ¿Por qué no ha de hacer exactamente lo que necesito? Es muy importante tener la libertad de modificar un programa adaptándolo a mis necesidades, extendiendo su funcionalidad, incluyendo fragmentos o la totalidad de él en algún otro programa mío, etc.
      • Libertad de redistribuirlo: Redistribuir software libre no es ilegal. Tenemos, por el contrario, todo el derecho de redistribuirlo como más nos guste. Podemos dar copias del programa en su estado original, podemos redistribuirlo modificado. El programa, si bien fue hecho por su autor para satisfacer cierta necesidad, y probablemente él haya sido retribuído económicamente por crearlo, no tiene restricciones para su posterior redistribución y usufructo.

    Hay una gran cantidad de licencias libres, que aplican probablemente de diferente manera alguno de estos criterios. Las más conocidas son:

    • GPL y similares: La licencia GPL fue creada por el Proyecto GNU, que busca crear un sistema operativo completo libre, objetivo que ya ha sido cubierto con creces. La característica principal de esta licencia es que cubre al programa y a toda obra derivada de él, asegurándose que el código libre se mantendrá por siempre libre.

      El núcleo de Linux, la colección de compiladores GCC, el editor Emacs, el lenguaje Perl, la base de datos MySQL, las utilidades básicas de los sistemas Linux, y una muy gran cantidad de aplicaciones están protegidas con la licencia GPL.

    • BSD y similares: Esta es una licencia de caracter académico, y toma su nombre del software desarrollado en la Universidad de California en Berkeley, donde fue hecha una muy buena parte del Unix que conocemos hoy en día. Esta licencia exige únicamente que en trabajos derivados se dé crédito a los autores originales, no imponiendo ninguna restricción a la manera en que estos puedan ser redistribuídos -- Es inclusive posible su inclusión en software no libre. De hecho, en casi todos los sistemas operativos comerciales (incluídos los principales Unixes y Windows) la implementación del protocolo TCP/IP es la hecha por los investigadores de la Universidad de California.

      El servidor de Web Apache, el servidor de XWindow XFree, el lenguaje PHP, la base de datos PostgreSQL, la mayor parte de los sistemas operativos FreeBSD, OpenBSD y NetBSD, y muchos otros proyectos están liberados bajo licencias BSD.

    • Dominio público: Si bien poca gente lo utiliza, el liberar código al dominio público también lo calificaría como software libre. Al liberar algo al dominio público lo hacemos libre de cualquier tipo de licencia o restricción. No hay proyectos importantes liberados al dominio público.

    En resumen, el software gratuito no necesariamente es libre. El software libre es gratuito en el sentido de que no es necesario pagar por redistribuirlo. Sin embargo, el desarrollo del software libre sí cuesta dinero, al igual que cualquier desarrollo profesional. Este costo se cubre al liberar lo que fue programado específicamente para un proyecto y puede servir para los demás, al hacer un programa o biblioteca de funciones que muy probablemente nos pueda servir a futuro en otros desarrollos, etc.

    La comunidad del software libre tiene una ética muy clara y muy marcada. Muchas veces hacemos desarrollos simplemente por hobby, por creerlos necesarios o porque son una buena idea, no para recibir una remuneración por ellos. Por último, es importante agregar que los usuarios y desarrolladores del software libre no promovemos ni apoyamos la piratería - Defendemos que el modelo de desarrollo que seguimos es superior, y que es mucho mejor utilizar código libre a utilizar programas propietarios, tanto para el desarrollador como para el usuario o cliente. Sin embargo, si queremos que nuestras licencias sean respetadas, tenemos que respetar a las licencias que otros decidan elegir.

  2. ¿Qué tan confiable es su sistema si est&aacute programado en un sistema operativo que cualquier persona puede modificar?
    Este es un error de concepción muy común, y me da gusto haber recibido esta pregunta.

    El que el código fuente esté disponible y que cualquier pueda meterle mano y redistribuirlo no significa que los cambios que haga cualquiera sean admitidos en el proyecto principal. Yo puedo, por ejemplo, modificar una copia de los fuentes de Linux e intentar redistribuirla con mis modificaciones malignas. Sin embargo, mis modificaciones no serán aceptadas obviamente por los mantenedores oficiales del núcleo, y por tanto no llegarán a las distribuciones, mecanismo por el cual casi todos los usuarios nos hacemos de nuestras copias del sistema. Podrí intentar distribuirlo yo mismo, sin embargo por medio de firmas criptográficas (MD5 checksum, típicamente) cualquiera puede confirmar que los paquetes que tenemos sean legítimos. Además, si yo distribuyo una copia modificada, tendré que hacerlo entre mis conocidos, dañando únicamente mi propio prestigio.

    Por último, no es indispensable contar con el código fuente de un programa para distribuirlo modificado - Tomemos, por ejemplo, los programas típicos en Windows - Probablemente sean miles de archivos, y cada uno de ellos ocupa al menos decenas de megabytes. Estos paquetes no contienen ningún tipo de verificación criptográfica. Agregar un archivo al paquete, un binario que envuelva a uno de los binarios legítimos, modificando parte de su conducta o su interacción con el mundo, no es en absoluto difícil.

  3. ¿Cuál será el sistema operativo más seguro?
    El proyecto OpenBSD ha creado el sistema operativo mundialmente reconocido como el sistema más seguro del mundo. El equipo de desarrollo de OpenBSD nació de una escisión del proyecto NetBSD, un sistema Unix libre y multiplataforma. El motivo de la separación fue precisamente el énfasis en la seguridad - Theo de Raadt, líder del proyecto, prefirió por sobre de agregar nuevas capacidades al sistema el llevar a cabo una árdua auditoría del código fuente, erradicando no únicamente las vulnerabilidades de seguridad que fueran encontrando, sino que todos los errores detectados, e inclusive todas las malas prácticas de programación.

    De este tan difícil esfuerzo surgió el sistema operativo OpenBSD, el cual desde su liberación en 1996 no ha tenido ni una sóla vulnerabilidad que proporcione privilegios de administrador a un atacante remoto en la instalación por default. El grupo de programadores de OpenBSD ha continuado el desarrollo de su sistema orientándolo hacia la seguridad. El exitoso proyecto OpenSSH, una implementación completamente libre y no cubierta por patentes del protocolo Secure Shell (ssh) disponible para prácticamente todos los sistemas operativos, fue lidereado por varios programadores de OpenBSD. OpenBSD es también el primer sistema operativo en proporcionar soporte a aceleradoras criptográficas en hardware.

  4. ¿Qué ventajas da Linux o Unix contra Windows Server 2000? ¿Es seguro?
    La primera ventaja, en la que no voy a abundar pues ya mucho he hablado en esta sección, es que Linux y los BSDs son libres, en tanto que Windows no lo es. Una segunda ventaja es la trayectoria histórica de los grupos o empresas que impulsan a cada sistema: Unix es un sistema operativo creado hace ya más de 30 años, y los cambios importantes que ha sufrido desde su creación son muy pocos. Existen numerosas implementaciones, tanto libres como propietarias, de Unix, y todas ellas conforman con las líneas básicas del estándar POSIX, y utilizar uno u otro no es demasiado diferente. Microsoft diseñó la primera versión de Windows en 1985, y en cada cambio mayor de versión, hay muy fuertes cambios tanto ante el usuario como ante los programadores, que tienen que aprender una nueva serie de APIs y olvidar los anteriores. Microsoft ha comprado o sacado del negocio a toda empresa que pudiera hacerles competencia, y son dueños de la uacute;nica implementación existente de Windows. Pueden, por tanto, hacer lo que quieren sin preservar continuidad en el sistema.

    A lo largo de los años, Microsoft ha sido muy poco responsable respecto a la seguridad. En el ciclo de vida de sus productos de rango servidor (NT Server, W2k, XP Professional) sólo hay cinco o seis actualizaciones (Service Packs), cada una de las cuales mide varios megabytes, y I>parcha varias decenas de vulnerabilidades y otros problemas. Esto, en contraposición a un gran número de pequeños parches específicos a uno u otro paquete, disponibles a los pocos dís de haber sido descubierto el problema.

    Por último, la granularidad de la instalación es muchísimo mayor en los sistemas libres. Cuando hago una instalación de un sistema libre tengo varios miles de paquetes que puedo decidir instalar. Algunos de estos paquetes medirán sólamente un par de kilobytes, mientras que otros serán de decenas de megabytes. Puedo elegir si instalar o no entorno gráfico, motor de bases de datos, servidores de diferentes tipos, etc. Esto no sólo reduce la carga que en determinado momento tiene nuestro servidor, sino que lo mantiene más seguro -- Todo código introduce posibles vulnerabilidades, y entre menos código tengamos instalado, más seguro será nuestro sistema. En un sistema Unix podemos elegir mucho mejor qué instalar y qué no.

  5. Actualmente, ¿Qué desarrollos ha habido en Linux para el Internet Móvil?
    Hay un gran empuje en Linux hacia los dispositivos empotrados y el cómputo móvil, demasiados como para listarlos aquí. Sin embargo, te doy un par de ligas, esperando que te sean de utilidad:

Preguntas relativas a la seguridad en general

  1. ¿Qué medidas podemos tomar para tener una red segura?
    ¿Cómo podemos hacer una red segura?
    Asegurar una red no es un proceso simple, y no existe una receta simple para hacerlo. Sin embargo, los siguientes puntos básicos siempre nos ayudarán:
    • Seguridad física: El primer paso para considerar una red segura es asegurarla físicamente - Tanto para evitar intrusiones como para asegurar la conectividad. El no permitir que la red crezca sin un plan, crear una infraestructura apta para llevar el cableado, atenerse completamente a los estándares propuestos por los fabricantes, el mantener la claridad y limpieza en todos los puntos importantes de nuestro cableado constituyen lo necesario para decir que tenemos cableado estructurado. El cableado estructurado nos evita negaciones de servicio, ya que es más difícil que haya pérdida de señal o interferencia eléctrica con buen cableado.

      No podemos dejar de lado, claro está, el mantener un claro registro de dónde tenemos instalados puntos de red, a quién pertenecen, la direcci&oacut;en MAC dirección física del adaptador de red) de los dispositivos que ahí conectemos, y siempre que sea posible no instalar puntos en espacios públicos, ya que para un intruso es muchas veces mucho más fácil conectarse a través de la red local que buscar el acceso remotamente.

      Si tenemos una red inalámbrica es mucho más difícil asegurar físicamente nuestra red. De todos modos, utilizando las capacidades de cifrado de las redes inalámbricas, como las que menciono aqu&iacute, ubicando nuestros puntos de acceso tan al centro de nuestras instalaciones como sea posible para evitar "derramar" señal, y en general utilizando el sentido común al instalar nuestra red, podremos evitar exponernos de más.

      Recuerden que una red inalámbrica puede ser muy conveniente y económica, pero si es instalada sin el cuidado necesario, puede ser nuestra mayor vulnerabilidad. Les sugiero fuertemente no instalar redes inalámbricas sin antes haber hecho un estudio en el que concluyan que las ventajas son superiores a los riesgos.

    • Seguridad perimetral: Una vez que tenemos confianza en nuestra instalación de red, tenemos que definir perímetros de seguridad, los cuales serán divididos por uno o varios firewalls. La configuración más simple consiste en sólamente poner un firewall entre nuestra red local y nuestra salida a Internet, permitiendo uacute;nicamente la entrada y salida a las conexiones autorizadas. Sin embargo, esta configuración es muy simplista. Para una red importante y de complejidad mediana, les recomiendo fuertemente tener delimitados cuando menos los siguientes perímetros:
      • Servidores de uso interno
      • Servidores de uso externo
      • Red local
      • Red inalámbrica

      El poder controlar granularmente el acceso entre áreas les dará una gran flexibilidad para definir las reglas de filtrado de paquetes, incrementando fuertemente la seguridad de su red. Es importante recordar que la mayor parte de ataques, tanto intencionales como no intencionales, que sufre cualquier organización tienden a venir del interior de la misma.

    • Monitorear constantemente la red: Parte importante de la seguridad en una red consiste en monitorearla activamente. Hay muchas condiciones que pueden llevarnos a fallas, y muy fáciles de corregir -o por lo menos diagnosticar- si contamos con herramientas de monitoreo. Podemos utilizar herramientas libres como MRTG, que nos da un reporte gráfico -diario, semanal, mensual y anual- de los datos que le configuremos. Otro aspecto importante a monitorear es los intentos de ataque que estemos recibiendo, para saber de qué protegernos, cuáles son nuestros principales riesgos, quién está intentando atacarnos, por qué medios, y qué es lo que buscan. Para ello, podemos instalar sistemas de detección de intrusos (IDSs, por sus siglas en inglés). El IDS más poderoso y popular hoy en día es libre, y se llama Snort. Hay varios proyectos que agregan capacidades a Snort, como ACID, Hogwash y Demarc.
    • Mantener las computadoras al día: La instalación de nuestra red puede haber sido muy segura. Podemos tener firewalls delimitando cada área específica. Sin embargo, si no mantenemos actualizados nuestros sistemas operativos, programas y herramientas, nuestra red no podrá ser considerada segura. Es muy frecuente, en software tanto libre como propietario, que sean encontradas fallas de programación que pueden traducirse en agujeros de seguridad - un administrador de redes responsable debe mantener sus sistemas con los parches al día, para no sufrir ataques prevenibles.
  2. ¿Qué programa me ayudaría a encontrar contraseñas de usuarios de Internet
    ¿Cómo capturó los datos de los usuarios conectados al servidor del Tec?

    La mayoría de las redes inalámbricas hoy en día están basadas en la especificación 802.11b de la IEEE, que es equivalente a una red Ethernet normal, sobre un medio inalámbrico, por lo que la respuesta a esta pregunta no se limita únicamente a redes inalámbricas. En una red Ethernet, el medio de comunicación (sea el cable o el espacio en el espectro electromagnético) es compartido entre todas las computadoras que conforman un segmento. Esto significa que cuando cualquier computadora quiere enviar un paquete a cualquier otra, tiene que cerciorarse primero que ninguna otra computadora esté utilizando la red - Si te interesa investigar más acerca de cómo funciona una red Ethernet, busca información acerca del mecanismo de resolución de conflictos CSMA/CD (Carrier Sense Multiple Access / Collision Detect).

    Bueno... A lo que iba - En una red Ethernet, todo el tráfico generado por cualquiera de las computadoras llega a todas las demás. Normalmente, las interfaces de red de una computadora est´n configuradas para no enviar al procesador interrupciones innecesarias. Basta configurar la tarjeta de red para que entre en modo promiscuo (con la bandera I>promisc en ifconfig en los sistemas libres derivados de Unix) para que todo el tráfico de red sea procesado por el kernel. Hay varios programas que nos permiten volcar la información que recibimos con la interfaz de red en modo promiscuo, muy uacute;tiles para depurar el funcionamiento de una red. Estos programas se conocen como sniffers, dado que olfatean lo que ocurre en la red y me lo reportan de la manera que yo prefiera. Uno de los más simples y comunes, que fue el que utilicé en la demostración que hice en la red del ITESM, es tcpdump. Hay muchos más, pero todos se basan en el mismo principio de operación. Utilicé tcpdump pues viene como parte de varios sistemas operativos y es el de más simple uso, si bien pueden especificársele parámetros que me permiten especificar a detalle el modo de operación.

  3. ¿Con qué programa puedo proteger mejor mis redes?
    Proteger una red implica proteger a cada uno de sus componentes. Hay una gran cantidad de puntos que hay que tomar en cuenta al proteger una red, algunos de los cuales ya mencioné en los incisos anteriores. Para mayor recomendaciones al respecto, les sugiero consultar los sitios que comento en esta pregunta, o mandarme un correo.
  4. ¿Qué páginas Web recomienda para adentrarnos más y aprender sobre seguridad?
  5. ¿Cómo estructuraría un buen cifrado para que sea segura la red?

    Me permito reformular esta pregunta, dado que un buen cifrado no puede ser estructurado - Al menos no por mí, el administrador de la red. La pregunta, entonces, se convierte en cómo elegir un buen cifrado para dar seguridad a nuestra red. Es importante llevar el cifrado a todos los niveles. No podemos confiar únicamente en cifrado al nivel que nos ofrece WEP, pues sería lo mismo que confiar en la confidencialidad que nos da una red Ethernet tradicional.

    Si en su red van a desarrollar o implementar aplicaciones sobre Web, les sugiero hacerlas sobre canal cifrado - Prácticamente todos los navegadores actuales manejan comunicación sobre SSL, y del lado del servidor, también casi la totalidad de los servidores -tanto libres como propietarios- manejan este cifrado. Queda a ustedes la decisión de si comprar un certificado de identidad de alguna autoridad certificadora (como Verisign o Thawte) o firmar ustedes mismos su certificado - aquí tengo una justificación para no acudir a autoridades certificadoras.

    Bases de datos como PostgreSQL permiten manejar todas las comunicaciones sobre canal cifrado con SSL. Para manejar sesiones remotas en servidores, sugiero fuertemente utilizar Secure Shell, específicamente la implementación OpenSSH, programada por el grupo de desarrolladores de OpenBSD. En caso de que el protocolo que ustedes requieran, o un programa cliente o servidor que lo implementen, no manejen cifrado nativamente, siempre pueden "envolverlo" con STunnel, programa que crea un túnel SSL para la comunicación de manera casi transparente para los programas.

    El correo puede ser protegido fácilmente con PGP, con su implementación libre GnuPG. PGP nos permite, claro, además crear llaveros de confianza, dando a un medio tan poco confiable como el correo electrónico garantís de integridad, confidencialidad, autenticidad e irrefutabilidad. Buena parte de estos programas están basados en una biblioteca de cifrado SSL. La más común es OpenSSL, la cual deriva de SSLeay.

    Los invito a revisar un documento que realicé para el Congreso de Seguridad en Cómputo 2000 realizado por el Departamento de Seguridad en Cómputo de la DGSCA, UNAM. Este documento habla acerca de la Infraestructura de llaves públicas (PKI - Public Key Infrastructure), parte fundamental de todas estas implementaciones.

Preguntas relativas a la seguridad en redes inalámbricas

  1. ¿Cómo se conectó a la red del Tec?
    ¿Cómo puedo conectarme a una red inalámbrica con una PC (laptop)? ¿Se tiene que hacer alguna configuración?
    La red inalámbrica del Tec es, por diseño, una red abierta. Esto tiene mucha lógica - Es una red para uso público en una universidad, cuya razón de ser es dar conectividad a los alumnos. En esta pregunta hablo de las organizaciones que no activan cifrado en sus redes inalámbrica - Obviamente, el Tec no tiene por qué activar cifrado, pues esto entorpecería el objetivo de uso público de la red del Tec.

    Una vez hecha esta aclaración... Para conectarse a una red inalámbrica que no implementa cifrado WEP basta con ponerle la tarjeta de red inalámbrica a una portátil cualquiera. Típicamente en sistemas Unix no es necesario siquiera configurar los controladores de la tarjeta. Basta con esperar a que el servidor DHCP, típicamente existente en redes inalámbricas, nos asigne una dirección, y podemos comenzar a utilizar la red.

    Dejando de lado el ejemplo del Tec, si hablamos de una red genérica, en la que sí hay WEP configurado, lo que necesitamos hacer es configurar a nuestra tarjeta de red con una de las llaves de uso de la red. ¿Cómo podemos hacer esto? Depende del sistema operativo y tipo de tarjeta que empleemos. Por ejemplo, en Linux podemos especificar el ESSID y la llave de cifrado WEP utilizando el programa iwconfig.

  2. ¿Para qué son las antenas?
    Tanto los Access Points como las tarjetas de red están equipados con pequeñas antenas, aptas para un par de cientos de metros en condiciones ideales, lo cual en el mundo real se traduce a varias decenas de metros, por la sombra proyectada por las construcciones, interferencias externas, etc. Estos equipos, sin embargo, están diseñados para permitirnos montar redes mucho más amplias. Pueden servir como infraestructura muy económica entre edificios separados por más de quince kilómetros - Nuevamente, en condiciones ideales.

    Para aumentar el alcance de los equipos, estos pueden conectarse a diferentes tipos de antenas. Existen antenas de alta ganancia unidireccional, de muy diferentes tipos (colinear, helicoidal, Yagi, semiparabólicas, etc.). Hay también antenas omnidireccionales, para aumentar tanto el radio de cobertura de un dispositivo inalámbrico como para aumentar la resistencia a interferencia. En esta página podrán encontrar información mucho más detallada acerca de los tipos de antena, cuándo conviene cada una de ellas y cómo construirlas en casa.
    Estas antenas se pueden comprar prefabricadas, o se pueden hacer artesanalmente. Esto es un interesante y divertido experimento, que seguro les enseñará mucho. Hay instrucciones para hacer esto en las diferentes redes de aficionados que dan cobertura inalámbrica -conocidas como Guerrilla.net- a diferentes ciudades en todo el mundo (incluyendo a Tampico en nuestro país, y con la Ciudad de México en proyecto) - Una lista de estas redes en los Estados Unidos está aquí. Estas antenas típicamente se hacen ya sea con tubos PVC o similares, logran una ganancia muy similar a la de una Yagi profesional, a una fracción del precio.

  3. ¿WEP es la mejor opción en cuanto a la seguridad en redes, o hay alguna mejor?
    WEP no es una buena opción, sin embargo, es la única opción que tenemos compatible con todo el hardware disponible actualmente. Hay una opción, sí, compatible con WEP, pero -como explica este artículo, sufre de los mismos problemas que WEP. La WECA (Wireless Ethernet Compatibility Alliance) definió un mecanismo destinado a reemplazar a WEP sin requerir modificaciones al hardware existente - TKIP (Temporary Key Integrity Protocol) hace un tanto más complejo el trabajo de quien desee romper la seguridad adivinando las llaves, pero definitivamente no es suficiente, ya que sigue siendo vulnerable al mismo tipo de ataques. Cabe mencionar que TKIP fue diseñado desde el principio únicamente como una medida paliativa temporal a las debilidades de WEP, haciendo el máximo uso posible del hardware ya disponible en los miles de tarjetas inalámbricas ya disponibles.

    La IEEE recomienda el uso de AES (Advanced Encryption Standard), que será pronto un estándar de cifrado en todo tipo de productos, pero actualmente este nivel de cifrado requiere mucho mayor trabajo matemático del que puede realizar un dispositivo tan simple como una tarjeta de red, y seguramente elevará el precio de venta del hardware que lo implemente, que se espera que aparezca a principios del 2003.

    Una buena solución, como lo indica este artículo, es el uso de cifrado en capas superiores, específicamente en la capa de red (IP), requiriendo el uso del estándar IPSec para el uso de nuestra red inalámbrica. Si bien este es el mejor mecanismo para implementar verdadera seguridad, sigue teniendo la desventaja de significar una carga adicional al CPU - El cifrado que realiza IPSec es matemáticamente muy complejo. Sin embargo, de entre todas las opciones que tenemos, es sin duda la más completa y confiable.

  4. ¿A qué se debe que gran parte de las organizaciones que utilizan redes inalámbricas no cuentan con la seguridad necesaria en ellas?

    Desafortunadamente, por simple omisión. La seguridad en muchas organizaciones, inclusive organizaciones muy grandes, es relegada, dándole muy baja prioridad o hasta ignorándola por completo. Es desafortunadamente demasiado común ver grandes organizaciones en las que no se han tomado ni las más básicas precauciones relativas a la seguridad - Y a nadie sorprende cuando reportan pérdidas millonarias por un ataque.
    ¿Por qué es tan común que, siendo tan importante y tan simple, la seguridad es relegada? En mi opinión, esto no puede calificarse más que de negligencia. Si bien no me es posible justificar que una organización no invierta en la seguridad adecuada para su red, sí puedo entender que hasta que no tengan un primer incidente importante no contraten a un equipo dedicado a seguridad. Sin embargo, el no configurar los aspectos más básicos de seguridad en una red inalámbrica, los cuales pueden ser implementados sin costo adicional, no puede calificarse más que de negligencia.

  5. ¿No es posible tener una WLAN con varias llaves privadas para cada usuario y con un algoritmo como RSA o más avanzado que permita una alta seguridad al usuario, o incluso es fácil desencriptar usando estos algoritmos?
    Claro que sí. Un dispositivo puede tener configuradas hasta cuatro llaves, y podrá hablar con cualquier otro dispositivo que tenga una de estas llaves o que no esté utilizando cifrado, a menos que sea configurado explícitamente para no aceptar comunicaciones no cifradas.

    Cabe mencionar que, como lo menciona este artículo, configurar dos dispositivos, por más que ambos cumplan con el estándar 802.11b, para que interoperen correctamente con WEP puede ser mucho más difícil de lo que debería, por la falta de homogeneidad en las interfaces.

Security in Perl scripts / Seguridad en scripts de Perl

Written in...: 
2002

I presented this tutorial at Congreso de Seguridad en Cómputo 2000, and later rewrote it (and moved it to a free, portable format) for Días de Software Libre at Guadalajara, May 2002. In this tutorial, I review some important key points not to fall in security errors while programming with Perl. I later adapted it together with a coworker, Alex Juárez, and we presented it in English at YAPC::Europe 2002. Here you will find this text both in Spanish and in English.

Resumen: 

Un tutorial que presenté para el Congreso de Seguridad en Cómputo en noviembre del 2000, y tras reescribirlo en un formato libre y portable, lo presenté de nuevo en los Días de Software Libre en Guadalajara, mayo del 2002. Lo adapté y traduje junto con mi compañero de trabajo Alex Juárez, y lo presentamos en el YAPC::Europe::2002. Reviso aquí una serie de puntos importantes para no caer en importantes errores de seguridad al programar con Perl. Está tanto en inglés como en español.

Seguridad en Redes: ¿Qué es? ¿Cómo lograrla?

Written in...: 
2002

I presented this talk ath the II Computer Systems Engineering Conference at Nuevo León Technological Institute. Here I review general security concepts, explaining to a non-expert audience various important factors that as security experts -and as conscious users in general- we must take into account.

Resumen: 

Presenté esta plática en el II Congreso de Ingeniería en Sistemas Computacionales del Instituto Tecnológico de Nuevo León. Reviso conceptos generales de seguridad, explicando a un público no iniciado en el tema los diversos factores que como profesionales en la seguridad -y como usuarios conscientes en general- debemos tener en cuenta.

AttachmentSize
seg_en_redes.tar_.gz72.34 KB
seg_en_redes.pdf355.04 KB

Implementación de seguridad con sistemas operativos y herramientas libres

Written in...: 
2001

I gave this talk at the GNU/Linux 2001 conference in Jalapa, Veracruz, in September 2001. In this article I show different characteristics and security reccomendations using free operating systems and tools.

Resumen: 

Esta plática la dí en el Congreso GNU/Linux 2001 en Jalapa, Ver., en septiembre del 2001. En este artículo muestro diferentes características y recomendaciones de seguridad utilizando los diferentes sistemas operativos y herramientas libres.

  • PDF (apto para imprimir)
  • HTML (apto para consultar en línea)
  • Fuente en LyX (apto para editar o modificar)

ProtoWrap: Using wrappers to protect specific network services

Written in...: 
2001

I wrote my final paper for graduation on implementing a generic connection wrapper that can be extended to understand and protect specific protocols. I presented this project at YAPC::NA 2001, and published a short article on Usenix's ;login: magazine (published in the June 2002 number).

Resumen: 

Escribí mi proyecto final de graduación implementando un wrapper genérico de conexiones que puede ser extendido para comprender y proteger protocolos específicos. Presenté mi proyecto en el YAPC::NA 2001, y publiqué un corto artículo en la revista ;login: de Usenix, en el número de Junio del 2002.

Recomendaciones de seguridad en Linux

Written in...: 
2001

Once again, I was invited to the seminar, with Computer Security Department of UNAM, this time in April 2001. The topic this time: Security guidelines in a Linux installation. How you can make a newly made Linux installation a difficult target for an attacker.
This same material, although updated and enhanced, was also presented as a tutorial at Congreso de Seguridad en Cómputo 2001, also organized (of course) by DSC, UNAM.

Resumen: 

De nueva cuenta, me invitaron a participar en el Admin-UNAM del Departamento de Seguridad en Cómputo de la UNAM, esta vez en abril del 2001. El tema expuesto en esta ocasión: Recomendaciones de seguridad en una instalación de Linux. Cómo hacer que un Linux recién instalado sea una presa muy
difícil para cualquier atacante.
Este mismo material, aunque bastante ampliado, lo presenté también como tutorial en el Congreso
de Seguridad en Cómputo 2001
, organizado también (claro está) por el DSC de la UNAM.

  • PDF (apto para imprimir)
  • HTML (apto para consultar en línea)
  • Fuente en LyX (apto para editar o modificar)

SOMBI - Still One More Backup Implementation

Written in...: 
2001

I presented this proposal about a backup system in the Computer Security 2001 Conference. Here I present a proposal for the implementation of a cyphered, automatic remote backup scheme.

Resumen: 

Presenté esta propuesta de esquema de respaldo en el Congreso de Seguridad en Cómputo 2001, presenta una propuesta para la implementación de un esquema de respaldo remoto, cifrado, automático.

SOMBI: Still One More Backup Implementation

Gunnar Wolf
gwolf@campus.iztacala.unam.mx
Congreso de Seguridad en Cómputo 2001
UNAM FES Iztacala

Abstract:

Hay una gran cantidad de implementaciones ya existentes para llevar a cabo de manera automática en sistemas en red -- Por diferentes razones, ninguno de ellos me convenció para las necesidades (nada atípicas, en mi opinión) de mi situación. Lo que aquí presento es un esquema muy simple que permite hacer respaldos de manera automática sobre la red con cifrado y contemplando diferentes tipos de respaldo.

¿Qué hay de malo con los esquemas de respaldo existentes?

Si estoy proponiendo un nuevo esquema de respaldos, esto es porque los ya existentes tienen alguna carencia que no me permite resolver de una manera simple mis necesidades. Entonces pues, ¿qué hay de malo con los esquemas de respaldo que existen hoy?

1.1 Mis necesidades

...Que pueden no ser las de los demás, pero seguramente habrá alguien con necesidades similares

  • Hacer los respaldos de manera periódica y automática
  • Hacer los respaldos sobre la red
  • Cifrar los respaldos conforme son realizados
  • Almacenarlos en un medio que me proporcione acceso fácil, rápido y confiable
  • Que sea simple y poco intrusivo, para cualquier administrador
  • Que sea software libre

1.2 El medio donde se almacena el respaldo

¿Por qué no usar cintas DAT?

  • Confiabilidad
  • Costo
  • Reusabilidad del medio
  • Velocidad
  • Compatibilidad entre plataformas

1.3 La transmisión de datos sensibles sobre la red

  • ¿Hacernos de la vista gorda y pasarlo en claro? ¿''ocultarlo'' con gzip?
  • ¿Cifrado en el transporte?
  • ¿Cifrado en el archivo?
  • Tiempo de procesador que esto ocupa

2 Consideraciones previas a SOMBI

2.1 Lo más común que he visto

  • Directo a la cinta, conectada localmente
    • ¿Y si no tengo una cinta en esta computadora?
    • ¿Y si no confío en las cintas?
  • Directo a cinta, en un host remoto
    • Típicamente con rsh -- Tremendamente inseguro!
    • ¿Y si no confío en las cintas?
  • Respaldo local con tar o equivalente
    • Un respaldo debería ser remoto o desmontable...

2.2 Mi esquema previo - sus fuerzas y debilidades

  • tar xf - /etc /home /var/mail | ssh $SERVER 'cat > respaldo'
  • Funciona, pero
    • Requiere root tanto en cliente como en servidor
    • No es automatizable (¿pondrías tu contraseña de root en un script?)

3 Esquema operativo de SOMBI

3.1 Soporte a diferentes tipos de respaldo

  • Como está en este momento, permite tres tipos de respaldo: Completo, de configuración y de datos de usuario. Ampliarlo, sin embargo, a que acepte otros tipos de respaldo es trivial.
  • Las pruebas que he hecho son con tar, pero podemos usar algún otro método para archivar, siempre que permita enviar la salida a un flujo de datos, con modificar bkCmd

3.2 Cifrado del lado del cliente

  • El cifrado se hace con un programa externo que nos permita trabajar sobre un flujo de datos
  • GPG (versión GNU de PGP) parece ideal
    • Cifrado con llave pública: No es necesario siquiera poder descifrar el respaldo con la información contenida en el cliente ni en el servidor
    • GPG incluye compresión (probablemente gzip)
  • Podrían usarse otros métodos -- Basta con modificar cryptCmd

3.3 Doble conexión

El proceso que sigue una conexión es:

  1. El cliente se conecta al puerto indicado del servidor
  2. El servidor verifica que la conexión venga de una dirección aprobada
  3. El cliente abre un puerto aleatorio, e informa al servidor cuál puerto abrió
  4. El servidor se conecta de vuelta con el cliente por este puerto
  5. El cliente verifica que la conexión venga del servidor
  6. El cliente envía el respaldo completo cifrado al servidor a través de este nuevo puerto
  7. El servidor almacena los datos en un lugar predeterminado

Proceso a agregar próximamente:

  • En el paso 3, enviar el puerto cifrado con una llave secreta que tengan tanto cliente como servidor
  • En el paso 5, verificar no sólo por la IP, sino que por una cadena cifrada con la llave secreta, que es realmente el servidor.

3.4 Medio en el que se almacena el respaldo

  • Se almacena en el disco duro de un servidor remoto
    • ¿Cuánto cuesta hoy en día un disco duro grande?
    • Velocidad, confiabilidad
  • Se puede combinar con crontab para quemar un CD-ROM periódicamente
    • Hacer más granular lo que se graba -- ¿Necesitas grabar en CD TODO el sistema?
    • Los CD-Rs y CD-RWs son ya muy baratos

3.5 Seguridad implementada por el esquema

  • Cifrado con GPG
  • Spoofing difícil (aunque a estas alturas, aún no imposible)
  • El respaldo es almacenado en un medio confiable
  • El respaldo puede trasladarse sin mayor problema a un medio removible

3.6 Problemas con este esquema

  • Está hecho para resolver mis necesidades, no cualquier necesidad
  • Costo de disco duro para respaldos masivos
  • No contempla (nativamente) guardar respaldos en medio removible
  • Estando cifrado con GPG, un bit corrupto puede hacer inútil al respaldo entero
  • Es una idea nueva y, por tanto, no del todo confiable

El arte de la administración de sistemas

Written in...: 
2000

Presented on March 30, 2000, at CECEC 2000, ESIME Culuhacan

Resumen: 

Presentado el 30 de marzo del 2000 en el CECEC 2000 en la ESIME Culuhacan

Infraestructura de llave pública

Written in...: 
2000

The full text for the lecture I gave for the GASU seminar organized by Computer Security
Department
at UNAM in july, 2000.

Resumen: 

El texto completo de la conferencia que dí para el Seminario GASU del Departamento de Seguridad en Cómputo de la UNAM en julio del 2000.

Logcheck

Written in...: 
2000

Talk I gave at the Admin-UNAM seminar, with Computer Security Department of UNAM, in September 2000.
Logcheck is a tool that checks periodically the system's log files, reporting to the administrator whatever is -according to operator-defined patterns- important.

Resumen: 

Plática que dí acerca de esta herramienta en el seminario Admin-UNAM del Departamento de Seguridad en Cómputo de la UNAM en septiembre del 2000.
Logcheck es una herramienta encargada de revisar periódicamente las bitácoras del sistema y reportar al administrador lo que sea -según patrones predefinidos por el administrador- importante.

Portsentry

Written in...: 
2000

Talk I gave at the Admin-UNAM seminar, with Computer Security Department of UNAM, in September 2000.
PortSentry is a tool that permits easy detection of port scanning, and has the ability to act immediately upon detection.

Resumen: 

Plática que dí acerca de esta herramienta en el seminario Admin-UNAM del Departamento de Seguridad en Cómputo de la UNAM en septiembre del 2000.
PortSentry es una herramienta que permite la fácil detección de barridos de puertos y tiene la capacidad de actuar de inmediato al detectarlos.

Scripts de seguridad en Perl

Written in...: 
2000

Tutorial I presented at Computer Security conference 2000, giving many examples of small Perl scripts that can help improve security at a site.

Resumen: 

Tutorial que presenté en el congreso Seguridad en Cómputo 2000, dando varios ejemplos de pequeños scripts en Perl que pueden ayudar a la seguridad de un sitio.

1. Introducción

¿Y quién es el tal Gunnar?

  • Administrador de sistemas en la ENEP Iztacala
    • Si bien sé algo de programación, disto mucho de ser programador
  • Miembro externo del DSC
  • Administrador de sistemas desde 1993
  • Paranóico - La paranoia es úncamente la realidad vista a mayor resolución<

¿Y qué es Perl?

Un maravilloso y últimamente muy popular lenguaje de programación de todo propósito, fácilmente extensible.
El lenguaje está diseñado particularmente para buena parte de las necesidades que como administradores de sistemas podemos requerir: Procesar grandes cantidades de datos, buscar patrones en grandes cantidades de datos, manejar conexiones de red, etc.

Acerca de la licencia del código

Todo el código que encuentres aquí está disponible bajo la Licencia Pública de GNU (GPL) versión 2 o posterior, a elección del usuario.
La licencia GPL estipula que el código puede ser libremente distribuído, leído, modificado y redistribuído, incluído en otros proyectos, tomar fragmentos, o utilizado en cualquier manera, siempre y cuando éste y todo código derivado de él sean siempre distribuídos bajo la licencia GPL.
Para mayor información acerca de las licencias libres (copyleft y no copyleft) y no libres, aquí hay una interesante exposición.

¿Y por qué en inglés?

No, no es porque me guste el inglés. No hago esto por facilitarme el copiar ejemplos de un libro ni por pocho.
Creo que alguno de estos scripts será útil cuando menos a una persona que no sea hispanoparlante. Espero que así sea. Entre los hispanoparlantes con nivel técnico medio o elevado es mucho más
frecuente el dominio del inglés que en el caso contrario.
Espero que esta decisión mía no ofenda a ninguno de ustedes.

Formato del tutorial

En este tutorial analizaremos varios scripts de Perl de diferentes grados de complejidad. Dada la naturaleza de éste medio, no reproduciré los scripts en la presentación, sino que daré un esbozo estructural y daré ligas a páginas donde éstos estén disponibles.
Los scripts no están preparados, procesados y listos, sino que son muestras de diferentes técnicas que ustedes podrán utilizar en sus programas, o primeros esbozos de programas que requieren ser
perfeccionados para utilizarse en ambientes de producción.

2. Analizando datos

Expiración

En un servidor con más de cien cuentas se puede volver imposible llevar a mano el registro de qué cuentas están activas, qué cuentas ya expiraron y hace cuánto tiempo. Este sencillo script de menos de 70 líneas puede generar un reporte periódico al administrador del estado de las cuentas en su sistema.
Por simplicidad, el script está construído alrededor de la estructura fija del archivo /etc/shadow. Transportarlo a otros sistemas, sin embargo, debe ser trivial.

Consideraciones de seguridad

Estamos ante uno de los mayores riesgos de seguridad: un programa que debe correr con privilegio de root, el único usuario con derecho de leer el archivo /etc/shadow. Es muy importante tomar todas las precauciones; el script corre con use strict y en modo -Tw (tainted y warnings). Fuera de la lectura inicial no tiene ninguna interacción con el mundo; la salida la envía a STDOUT. Esto es para evitar que alguien se aproveche de sus elevados atributos para atacar al sistema.
Este script está pensado para correr desde el crontab de root.

Funcionamiento general

El funcionamiento de este script es muy sencillo. Tras cargar el módulo Date::Calc y activar el pragma strict, iteramos sobre cada línea del archivo /etc/shadow, revisando su octavo campo (recuerden que el número base de un arreglo es 0), acomodándolo acorde a su estado respecto a la fecha actual en uno de cinco arreglos.Posteriormente, por medio de otra muy simple rutina, imprime cada uno de estos arreglos en órden. El programa nos reportará en este órden las cuentas próximas a expirar o recién expiradas, las que expiraron en el último mes, las que llevan ya más de un mes expiradas, las que no han expirado y las que no tienen fecha de expiración.

Funcionamiento: Obtención y comparación de la fecha

En la línea 12 vemos que:

  1. $dias=Delta_Days(1970,1,1,@fecha);

En los sistemas Unix, las fechas se guardan como el número de días transcurridos desde el 1 de enero de 1970. Las fechas de expiración en
/etc/shadow están en este mismo formato, por lo cual compararlas posteriormente será únicamente comparar dos valores numéricos.

Funcionamiento: Generación del reporte

Al poblar los cinco arreglos pueden haber notado que lo hacemos con una referencia a un arreglo [$login,$dias]. Esto es para pasar dos datos en una sola variable escalar.
Al recibir estos datos en &reporta los separamos expresamente en $login y $dias para evitar que los datos nos lleguen en un formato no
previsto y afecten de alguna manera la ejecución y seguridad de nuestro programa.

  1. #!/usr/bin/perl -Tw
  2. # expira.pl
  3. #
  4. # Reporta las fechas de expiracion de las cuentas de los usuarios
  5. #
  6. use strict;
  7. use Date::Calc qw(Today Delta_Days);
  8. my ($dias,@fecha,$file,@linea,@nuncaExpira,@expiraPronto,@expiraMes,@expiraAntes,@noExpirada);
  9. @fecha=Today;
  10. $dias=Delta_Days(1970,1,1,@fecha);
  11. $file='/etc/shadow';
  12. # Solo root puede abrir el archivo /etc/shadow
  13. open(FILE,$file) or die 'Es necesario ejecutar este script como root';
  14. while (@linea=split(/:/,&lt;FILE&gt;)) {
  15. if ($linea[7] eq '' || $linea[7] &lt; 0) {
  16. # La cuenta no expira
  17. push (@nuncaExpira,[$linea[0],$linea[7]]);
  18. } elsif (($linea[7]-5)&lt;$dias &amp;&amp; ($linea[7]+5)&gt;$dias) {
  19. # La cuenta expira o expiro en estos dias
  20. push (@expiraPronto,[$linea[0],$linea[7]]);
  21. } elsif ($linea[7]+30&gt;=$dias &amp;&amp; $linea[7]&lt;$dias) {
  22. # La cuenta expiro hace menos de 30 dias
  23. push (@expiraMes,[$linea[0],$linea[7]]);
  24. } elsif ($linea[7]&lt;$dias) {
  25. # La cuenta expiro hace mas de un mes
  26. push (@expiraAntes,[$linea[0],$linea[7]]);
  27. } else {
  28. # La cuenta no ha expirado
  29. push (@noExpirada,[$linea[0],$linea[7]]);
  30. }
  31. }
  32. close(FILE);
  33. print &quot;\n&quot;;
  34. print '='x37,&quot;\n Cuentas que expiran en estos dias \n&quot;,'='x37,&quot;\n&quot;;
  35. &amp;reporta(\@expiraPronto);
  36. print '='x37,&quot;\n Cuentas que expiraron el ultimo mes \n&quot;,'='x37,&quot;\n&quot;;
  37. &amp;reporta(\@expiraMes);
  38. print '='x37,&quot;\n Cuentas que expiraron hace tiempo \n&quot;,'='x37,&quot;\n&quot;;
  39. &amp;reporta(\@expiraAntes);
  40. print '='x37,&quot;\n Cuentas que no han expirado \n&quot;,'='x37,&quot;\n&quot;;
  41. &amp;reporta(\@noExpirada);
  42. print '='x37,&quot;\n Cuentas que no expiran \n&quot;,'='x37,&quot;\n&quot;;
  43. &amp;reporta(\@nuncaExpira);
  44. sub reporta {
  45. my ($login,$dias);
  46. foreach (@{$_[0]}) {
  47. ($login,$dias)=@{$_};
  48. printf(&quot; %-15s %6s\n&quot;,$login,$dias);
  49. }
  50. }

Atributos

Es muy importante mantener verificada la integridad de nuestro sistema. Si no llevamos registro de los cambios efectuados a nuestros equipos, un atacante podrá entrar y modificar nuestro sistema sin ninguna dificultad, y será imposible determinar el alcance de los daños provocados por él.
Hay varios paquetes que hacen algo parecido a este script, el más conocido de ellos Tripwire. Todos ellos, sin embargo, pueden ser perfeccionados de más de una manera. Ilustramos aquí el funcionamiento del módulo central.

Dos versiones - El dilema de la firma

Presentamos dos versiones del programa - una que revisa únicamente los atributos de los archivos y una que calcula las firmas MD5 de cada
uno de ellos. ¿Por qué?

  • Seguridad- Si firmamos cada archivo, nos es necesario poder leer cada uno de ellos. Muchos archivos claves del sistema requieren tener root para leerlos. Si buscamos que un usuario cualquiera ejecute el programa, sólo podremos revisar los atributos.
  • Velocidad- Calcular la firma MD5 de un par de archivos es muy rápido. Sin embargo, calcular la de cientos o miles de archivos puede tomar mucho más tiempo del que estamos dispuestos a invertir. Cada usuario deberá poder elegir lo que juzgue mejor.

Consideraciones de seguridad

Aparte del punto de seguridad antes mencionado, nuestro programa debe poder listar todos los directorios a los que entre, ya que de ellos sacará la información necesaria. Si tenemos directorios protegidos con permisos 700, por ejemplo, nuestro programa no podrá entrar a este a menos que corra como el dueño del directorio.
Si decidimos no correr la versión MD5 del programa, un atacante con cierto conocimiento del sistema puede sin ningún problema alterar los
datos para cubrir sus huellas. Esta es una protección contra cambios no deseados y contra script kiddies.

Funcionamiento general

El programa revisa primero que nada si fue llamado en modo de creación de la base de datos o de revisión del sistema. En el primer caso, es llamado para únicamente procesar un archivo. La operación es muy sencilla - Imprime una línea con las características que stat arroja sobre el archivo. Esta línea la podemos guardar en nuestra base de datos.
Al verificar archivos, el programa itera sobre el archivo con los datos y, si hay alguna discrepancia con el estado actual, lo reporta de
una manera fácil de leer y comprender.

Funcionamiento general: Ejemplo de salida

  1. [gwolf@server gwolf]$ ./atributos.pl -p /home/gwolf/archivo_prueba.txt
  2. /home/gwolf/archivo_prueba.txt|1811|246064|33188|2|1160|0|1035916|2543|973982482|973982482|8192|6
  3. [gwolf@server gwolf]$ ./atributos.pl -p /home/gwolf/archivo_prueba.txt &gt; database.ck
  4. [gwolf@server gwolf]$ ./atributos.pl -c database.ck
  5. [gwolf@server gwolf]$ echo 'modificando' &gt;&gt; archivo_prueba.txt
  6. [gwolf@server gwolf]$ ./atributos.pl -c database.ck
  7. /home/gwolf/archivo_prueba.txt:
  8. size is now 2918 (should be 2907)
  9. mtime is now 973982824 (should be 973982482)
  10. ctime is now 973982824 (should be 973982482)

Funcionamiento: Procesando opciones

En el script utilizamos el módulo Getopt::Std. Con él, las opciones de línea de comando que son especificadas con el comando

  1. getopt('p:c:');</code
  2. son recibidas en las variables <code>$opt_p
y $opt_c.

Funcionamiento: stat

Para conseguir los atributos de un archivo, no hay nada más útil que stat. Esta función nos regresa el siguiente arreglo:

  • dev Dispositivo físico
  • ino Número de i-nodo
  • mode Tipo y permisos del archivo
  • nlink Número de ligas duras
  • uid UID
  • gid GID
  • rdev Identificador de dispositivo (archivos especiales)
  • size Longitud total
  • atime Último acceso (formato epoch)
  • mtime Última modificación (formato epoch)
  • ctime Tiempo de modificación del inodo (formato epoch)
  • blksize Tamaño de bloques preferido para el sistema de archivos
  • blocks Número de bloques utilizados

  1. #!/usr/bin/perl -Tw
  2. use Getopt::Std;
  3. # We use this for prettier output later in &amp;printchanged()
  4. @statnames = qw(dev ino mode nlink uid gid rdev size mtime ctime blksize blocks);
  5. getopt('p:c:');
  6. die &quot;Usage: $0 [-p &lt;filename&gt;|-c &lt;filename&gt;]\n&quot; unless ($opt_p or $opt_c);
  7. if ($opt_p) {
  8. die &quot;Unable to stat file $opt_p: $!\n&quot; unless (-e $opt_p);
  9. print $opt_p,&quot;|&quot;,join('|',(lstat($opt_p))[0..7,9..12]),&quot;\n&quot;;
  10. exit;
  11. }
  12. if ($opt_c) {
  13. open(CFILE,$opt_c) or die &quot;Unable to open check file $opt_c: $!\n&quot;;
  14. while (&lt;CFILE&gt;){
  15. chomp;
  16. @savedstats = split('\|');
  17. die &quot;Wrong number of fields in line beginning with $savedstats[0]&quot; unless ($#savedstats == 12);
  18. @currentstats = (lstat($savedstats[0]))[0..7,9..12];
  19. # print the changed fields only if something has changed
  20. &amp;printchanged(\@savedstats,\@currentstats) if (&quot;@savedstats[1..12]&quot; ne &quot;@currentstats&quot;);
  21. }
  22. close(CFILE);
  23. }
  24. # iterates through attributes lists and prints any changes between
  25. # the two
  26. sub printchanged{
  27. my ($saved,$current) = @_;
  28. # print the name of the file after popping it off of the array read
  29. # from the check file
  30. print shift @{$saved},&quot;:\n&quot;;
  31. for (my $i = 0 ; $i &lt; $#{$saved} ; $i++) {
  32. if ($saved-&gt;[$i] ne $current-&gt;[$i]) {
  33. print &quot;\t&quot;.$statnames[$i].&quot; is now &quot;.$current-&gt;[$i];
  34. print &quot; (should be &quot;.$saved-&gt;[$i].&quot;)\n&quot;;
  35. }
  36. }
  37. }

Atributos y MD5

Es muy importante mantener verificada la integridad de nuestro sistema. Si no llevamos registro de los cambios efectuados a nuestros equipos, un atacante podrá entrar y modificar nuestro sistema sin ninguna dificultad, y será imposible determinar el alcance de los daños provocados por él.
Hay varios paquetes que hacen algo parecido a este script, el más conocido de ellos Tripwire. Todos ellos, sin embargo, pueden ser perfeccionados de más de una manera. Ilustramos aquí el funcionamiento del módulo central.

Dos versiones - El dilema de la firma

Presentamos dos versiones del programa - una que revisa únicamente los atributos de los archivos y una que calcula las firmas MD5 de cada
uno de ellos. ¿Por qué?

  • Seguridad- Si firmamos cada archivo, nos es necesario poder leer cada uno de ellos. Muchos archivos claves del sistema requieren tener root para leerlos. Si buscamos que un usuario cualquiera ejecute el programa, sólo podremos revisar los atributos.
  • Velocidad- Calcular la firma MD5 de un par de archivos es muy rápido. Sin embargo, calcular la de cientos o miles de archivos puede tomar mucho más tiempo del que estamos dispuestos a invertir. Cada usuario deberá poder elegir lo que juzgue mejor.

Consideraciones de seguridad

Aparte del punto de seguridad antes mencionado, nuestro programa debe poder listar todos los directorios a los que entre, ya que de ellos sacará la información necesaria. Si tenemos directorios protegidos con permisos 700, por ejemplo, nuestro programa no podrá entrar a este a menos que corra como el dueño del directorio.
Si decidimos no correr la versión MD5 del programa, un atacante con cierto conocimiento del sistema puede sin ningún problema alterar los
datos para cubrir sus huellas. Esta es una protección contra cambios no deseados y contra script kiddies.

Funcionamiento general

El programa revisa primero que nada si fue llamado en modo de creación de la base de datos o de revisión del sistema. En el primer caso, es llamado para únicamente procesar un archivo. La operación es muy sencilla - Imprime una línea con las características que stat arroja sobre el archivo. Esta línea la podemos guardar en nuestra base de datos.
Al verificar archivos, el programa itera sobre el archivo con los datos y, si hay alguna discrepancia con el estado actual, lo reporta de
una manera fácil de leer y comprender.

Funcionamiento general: Ejemplo de salida

  1. [gwolf@server gwolf]$ ./atributos.pl -p /home/gwolf/archivo_prueba.txt
  2. /home/gwolf/archivo_prueba.txt|1811|246064|33188|2|1160|0|1035916|2543|973982482|973982482|8192|6
  3. [gwolf@server gwolf]$ ./atributos.pl -p /home/gwolf/archivo_prueba.txt &gt; database.ck
  4. [gwolf@server gwolf]$ ./atributos.pl -c database.ck
  5. [gwolf@server gwolf]$ echo 'modificando' &gt;&gt; archivo_prueba.txt
  6. [gwolf@server gwolf]$ ./atributos.pl -c database.ck
  7. /home/gwolf/archivo_prueba.txt:
  8. size is now 2918 (should be 2907)
  9. mtime is now 973982824 (should be 973982482)
  10. ctime is now 973982824 (should be 973982482)

Funcionamiento: Procesando opciones

En el script utilizamos el módulo Getopt::Std. Con él, las opciones de línea de comando que son especificadas con el comando
getopt('p:c:');
son recibidas en las variables $opt_p y $opt_c.

Funcionamiento: stat

Para conseguir los atributos de un archivo, no hay nada más útil que stat. Esta función nos regresa el siguiente arreglo:

  • dev Dispositivo físico
  • ino Número de i-nodo
  • mode Tipo y permisos del archivo
  • nlink Número de ligas duras
  • uid UID
  • gid GID
  • rdev Identificador de dispositivo (archivos especiales)
  • size Longitud total
  • atime Último acceso (formato epoch)
  • mtime Última modificación (formato epoch)
  • ctime Tiempo de modificación del inodo (formato epoch)
  • blksize Tamaño de bloques preferido para el sistema de archivos
  • blocks Número de bloques utilizados

  1. #!/usr/bin/perl -Tw
  2. use Getopt::Std;
  3. use Digest::MD5 qw(md5);
  4. # We use this for prettier output later in &amp;printchanged()
  5. @statnames = qw(dev ino mode nlink uid gid rdev size mtime ctime blksize blocks md5);
  6. getopt('p:c:');
  7. die &quot;Usage: $0 [-p &lt;filename&gt;|-c &lt;filename&gt;]\n&quot; unless ($opt_p or $opt_c);
  8. if ($opt_p) {
  9. die &quot;Unable to stat file $opt_p: $!\n&quot; unless (-e $opt_p);
  10. open(F,$opt_p) or die &quot;Unable to open $opt_p: $!\n&quot;;
  11. $digest = Digest::MD5-&gt;new-&gt;addfile(F)-&gt;hexdigest;
  12. close(F);
  13. print $opt_p,&quot;|&quot;,join('|',(lstat($opt_p))[0..7,9..12]),&quot;|$digest\n&quot;;
  14. exit;
  15. }
  16. if ($opt_c) {
  17. open(CFILE,$opt_c) or die &quot;Unable to open check file $opt_c: $!\n&quot;;
  18. while (&lt;CFILE&gt;){
  19. chomp;
  20. @savedstats = split('\|');
  21. die &quot;Wrong number of fields in line beginning with $savedstats[0]&quot; unless ($#savedstats == 13);
  22. @currentstats = (lstat($savedstats[0]))[0..7,9..12];
  23. open(F,$savedstats[0]) or die &quot;Unable to open $opt_c: $!\n&quot;;
  24. push(@currentstats,Digest::MD5-&gt;new-&gt;addfile(F)-&gt;hexdigest);
  25. close(F);
  26. # print the changed fields only if something has changed
  27. &amp;printchanged(\@savedstats,\@currentstats) if (&quot;@savedstats[1..13]&quot; ne &quot;@currentstats&quot;);
  28. }
  29. close(CFILE);
  30. }
  31. # iterates through attributes lists and prints any changes between
  32. # the two
  33. sub printchanged{
  34. my ($saved,$current) = @_;
  35. # print the name of the file after popping it off of the array read
  36. # from the check file
  37. print shift @{$saved},&quot;:\n&quot;;
  38. for (my $i = 0 ; $i &lt; $#{$saved} ; $i++) {
  39. if ($saved-&gt;[$i] ne $current-&gt;[$i]) {
  40. print &quot;\t&quot;.$statnames[$i].&quot; is now &quot;.$current-&gt;[$i];
  41. print &quot; (should be &quot;.$saved-&gt;[$i].&quot;)\n&quot;;
  42. }
  43. }
  44. }

3. Búsqueda de patrones

Bitácoras - Uso del sistema

Es muy importante para un administrador de sistemas analizar los datos generados por las bitácoras de su sistema. De ellas podemos, entre otras cosas, sacar posibles errores que estemos cometiendo con nuestra configuración del sistema o encontrar posibles intentos de intrusión. Desafortunadamente, leer bitácoras puede ser tedioso.
Presento aquí un script que analiza la salida de last buscando cuántas veces se ha conectado un usuario y por cuánto tiempo en el último mes.

Consideraciones de seguridad

Las bitácoras del sistema típicamente seran legibles únicamente para root. En este caso decidí utilizar un programa que funciona en el espacio de usuario y nos presenta la bitácora binaria wtmp para evitar hacer otra demostración que requiera correr como superusuario.

Funcionamiento general

El programa itera sobre cada línea resultante de correr el programa indicado en $lastProg, ignorando las líneas que no van asociadas a un login verdadero. Utilizando el hash %usedTime registra en una sencilla estructura cuántas veces entró un usuario, y por cuánto tiempo lo hizo. Por último, nos lo reporta utilizando un formato de printf.

Funcionamiento: Sumando minutos y horas

En la función toMinutes primero que nada verificamos que el formato de la hora sea el correcto: Dos dígitos representando la hora y otros dos representando los minutos, separados por dos puntos. Nos es más fácil guardar un valor fácil de sumar, como lo son los minutos, por lo que multiplicamos las horas por 60 y sumamos el resultado a los minutos. Sumamos esto al valor ya existente en $usedTime{$user}[0].

Funcionamiento: Separando horas de minutos por el camino fácil

Al principio del programa tenemos la directiva use integer;. Esta indica al compilador que use aritmética entera, en vez de trabajar con puntos flotantes, el comportamiento normal de Perl. Esto, además de darnos un poco de velocidad al hacer operaciones, nos permite dar menos rodeos en la función printResults. Para separar horas y minutos basta con que dividamos los minutos entre 60 - El entero resultante son las horas, el residuo los minutos, y no tendremos que pelearnos con fracciones decimales.

  1. #!/usr/bin/perl -w
  2. use integer;
  3. use strict;
  4. my (%usedTime, $lastProg);
  5. $lastProg = '/usr/bin/last';
  6. foreach my $line (`$lastProg`) {
  7. next if ($line =~ /^(reboot|ftp|wtmp begins)/ || $line =~ /^\s*$/);
  8. $line =~ s/\s+$//g;
  9. my $user = substr($line,0,10);
  10. $user =~ s/\s.+//g;
  11. my $time = &amp;toMinutes(substr($line,length($line)-6,5));
  12. $usedTime{$user} = [0,0] unless defined($usedTime{$user});
  13. $usedTime{$user}[0] += $time;
  14. $usedTime{$user}[1] += 1;
  15. }
  16. &amp;printResults(\%usedTime);
  17. exit 0;
  18. sub toMinutes {
  19. my ($in,$hr,$min);
  20. $in = shift;
  21. return 0 unless ($in =~ /^\d\d\:\d\d$/);
  22. $hr = substr($in,0,2);
  23. $min = substr($in,3,2);
  24. return ($hr*60+$min);
  25. }
  26. sub printResults {
  27. my ($totMin,$hr,$min,$numLogins);
  28. print &quot;Login Time used Logins\n&quot;;
  29. print &quot;============================\n&quot;;
  30. foreach my $user (sort(keys(%usedTime))) {
  31. $totMin=$usedTime{$user}[0];
  32. $numLogins=$usedTime{$user}[1];
  33. $hr=$totMin / 60;
  34. $min=$totMin % 60;
  35. printf(&quot;%-10s %02s:%02s %-2s\n&quot;,$user,$hr,$min,$numLogins);
  36. }
  37. }

Bitácoras - Errores del servidor HTTP

Muchos programas analizan, de alguna u otra manera, el contenido de las bitácoras del sistema (como ejemplos, Logcheck (tutorial en español disponible aquí) y Swatch). Hay programas también dedicados a monitorear y reaccionar en tiempo real a los errores producidos por Apache, como el Apache Guardian.
Sin embargo, un programa que recorra un archivo de bitácora de Apache y reporte, de una manera limpia y fácil de entender los errores ocurridos tenía que ser ideado a mano por los administradores. Es eso lo que intento aquí cubrir.

Consideraciones de seguridad

Este script debe correr con un usuario que tenga derecho de ver el archivo de bitácoras de Apache, típicamente localizado en /var/www/logs/error_log/var/log/httpd/error_log. Para evitar que este script requiera privilegios de root para correr, sugiero que dicho archivo pertenezca a un grupo de administración (daemon o wheel, por ejemplo), permitiendo a dicho grupo acceso únicamente de lectura, de la siguiente manera:
-rw-r-----  1 root  daemon  2188152 Dec  7 10:03 /var/www/logs/error_log

Funcionamiento general

El script procesa una tras otra todas las líneas del archivo indicado en la variable $file. Reporta un resúmen de lo que encuentre en dicho archivo con el siguiente formato:

  1. Directory index forbidden by rule
  2. 1
  3. 1 /var/www/htdocs/comun/
  4. 7 /var/www/htdocs/data/Icons/
  5. 2 /var/www/htdocs/images/
  6. File does not exist
  7. 1
  8. 5 /var/www/htdocs/biblio/
  9. 2 /var/www/htdocs/CURSO
  10. 1 /var/www/htdocs/adm_list/approve.cgi
  11. (...)

Funcionamiento: Organizando los datos

El formato de las bitácoras de error de Apache es el siguiente:
[<i>fecha</i>] [<i>categoría</i>] [client <i>w.x.y.z</i>] <i>tipo de error</i>: <i>archivo que lo ocasionó</i>
por ejemplo,
[Thu Dec  7 10:03:27 2000] [error] [client 192.168.2.45] File does not exist: /var/www/htdocs/esta/pagina/no/existe
Lo dividimos, entonces, utilizando el caracter ] como separador de campo. Descartamos todas las líneas que no lleven error como categoría, y de las líneas que nos interesen, el último campo lo dividimos en tipo de error y archivo que lo ocasiona utilizando el
caracter :.
En el hash %errores guardamos los datos resultantes, utilizando como llave el tipo de error, y agregando el archivo que lo ocasionó a la lista guardada por referencia relacionada a esa llave.

Funcionamiento: Reportando

Al reportar, recorremos los tipos de error y, para cada uno de ellos, recorremos el arreglo, guardando ahora en el hash %sumado como llave el nombre de cada uno de los causantes de error, y sumándole uno al valor de esta llave cada que lo encontremos. Una vez procesado el arreglo completo, reportamos primero el tipo de error, y después (indentando por claridad) cada uno de los archivos que lo ocasionaron, con el número de veces que fue llamado.

  1. #!/usr/bin/perl -Tw
  2. use integer;
  3. use strict;
  4. my (%errores, $file);
  5. $file = '/var/www/logs/error_log';
  6. open(IN,&quot;&lt;$file&quot;) or die &quot;Could not open $file - $@ $!&quot;;
  7. foreach my $line (&lt;IN&gt;) {
  8. chomp($line);
  9. my (@datos,@detalles);
  10. @datos = split(/\]/,$line);
  11. next if ($datos[1] ne ' [error');
  12. @detalles = split(/: /,$datos[3]);
  13. $errores{$detalles[0]} = [] if (not defined $errores{$detalles[0]});
  14. my ($tipoErr,$archErr) = @detalles;
  15. push(@{$errores{$tipoErr}},$archErr);
  16. }
  17. &amp;printResults(\%errores);
  18. sub printResults {
  19. my ($llave,%hash,%sumado);
  20. %hash = %{$_[0]};
  21. foreach $llave (sort(keys(%hash))) {
  22. print &quot;$llave\n&quot;;
  23. while (@{$hash{$llave}}) {
  24. my ($tmp);
  25. $tmp=shift(@{$hash{$llave}});
  26. $sumado{$tmp}++;
  27. }
  28. foreach my $file (sort(keys(%sumado))) {
  29. printf (&quot; %3d %25s\n&quot;,$sumado{$file},$file);
  30. }
  31. }
  32. }

Formato

Hay varios archivos fundamentales para la operación de nuestro sistema que requieren seguir un formato específico - probablemente, el mejor ejemplo de esto sea el archivo de información de los usuarios, /etc/passwd, y los archivos íntimamente relacionados con él, /etc/groups y /etc/shells. Además de esto, no es difícil para un atacante esconder su presencia utilizando trucos muy sencillos, algunos de los cuales encontraremos con este programa.

Consideraciones de seguridad

No me cansaré de repetirlo: Si no hay una razón que nos obligue a correr como root determinado programa, no tenemos por qué hacerlo
Este script todavía puede ser muy mejorado - No porque este programa no nos reporte una situación riesgosa en estos archivos significa que están seguros. Podríamos agregar verificaciones para cuentas 0 que no pertenecieran única y exclusivamente a root, cuentas con login root que no tuvieran UID 0, cuentas de usuario con UID 65536 (equivalente a root), nombres de usuario pertenecientes a cuentas del sistema (kmem, mail, adm, wheel, etc.) y otras muchas posibles situaciones.

Funcionamiento general

Primero que nada, creamos dos arreglos, uno con el contenido relevante de /etc/group y otro con el de /etc/shells. Al hacer esto, aprovechamos para verificar su correcto formato - En /etc/group revisamos que tenga el número correcto de campos y que no haya ni nombres de grupo ni GIDs repetidos. Después de esto, revisamos que cada uno de los shells listados en /etc/shells exista y sea ejecutable.
Utilizando las mismas estrategias, finalmente abrimos y analizamos línea por línea /etc/passwd. Revisamos número de campos, usernames/UIDs duplicados, directorio home existente y shell listado en /etc/shells.

  1. #!/usr/bin/perl -Tw
  2.  
  3. use strict;
  4.  
  5. my ($grpFileName,$shellFileName,$pwdFileName,%groups,%shells,@pwdData);
  6.  
  7. $grpFileName = '/etc/group';
  8. $shellFileName = '/etc/shells';
  9. $pwdFileName = '/etc/passwd';
  10.  
  11. # First, load all the needed groups into memory. Check, by the way, for
  12. # repeated groups and incorrect line length.
  13. %groups = &getGroups($grpFileName);
  14. %shells = &getShells($shellFileName);
  15. &checkPasswd($pwdFileName,\%groups,\%shells);
  16.  
  17. sub getGroups {
  18. my ($filename,@groups,%groupids,%groupnames);
  19. $filename = shift;
  20. open(IN,"<$filename") or die "Could not open $filename";
  21. while (my $line = &lt;IN&gt;) {
  22. # We do not chomp($line), because even an empty members field
  23. # is valid, and if we chopped it, we would get false positives.
  24. next if $line =~ /^\s*#/;
  25. my @data = split(/:/,$line);
  26. print "WARNING: Line in $filename with incorrect number of fields (should have four):\n $line\n" if ($#data != 3);
  27. print "WARNING: Duplicate GID: $data[2] refers to $data[0] and $groupids{$data[2]}\n" if (defined $groupids{$data[2]});
  28. $groupids{$data[2]} = $data[0];
  29. print "WARNING: Duplicate group name: $data[0] refers to $data[2] and $groupnames{$data[0]}\n" if (defined $groupnames{$data[0]});
  30. $groupnames{$data[0]} = $data[2];
  31. }
  32. return(%groupids);
  33. }
  34.  
  35. sub getShells {
  36. my ($filename,%shells);
  37. $filename = shift;
  38. open(IN,"<$filename") or die "Could not open $filename";
  39. while (my $line = &lt;IN&gt;) {
  40. next if ($line =~ /^\s*#/);
  41. chomp($line);
  42. print "WARNING: Shell $line does not exist\n" unless (-e $line);
  43. print "WARNING: Shell $line appears twice\n" if (defined $shells{$line} );
  44. $shells{$line} = 1;
  45. }
  46. return(%shells);
  47. }
  48.  
  49. sub checkPasswd {
  50. my (%userid,%username,$filename,%groups,%shells);
  51. $filename = $_[0];
  52. %groups = %{$_[1]};
  53. %shells = %{$_[2]};
  54. open(IN,"<$filename");
  55. while (my $line = &lt;IN&gt;) {
  56. chomp($line);
  57. next if ($line =~/^\s*#/);
  58. my @data = split(/:/,$line);
  59. print "WARNING: Line in $filename with incorrect number of fields (should have 7):\n $line\n" if ($#data != 6);
  60. print "WARNING: Duplicate UID: $data[2] refers to $data[0] and $userid{$data[2]}\n" if (defined $userid{$data[2]});
  61. $userid{$data[2]} = $data[0];
  62. print "WARNING: Dulpicate username: $data[0] refers to $data[2] and $username{$data[0]}\n"if (defined $username{$data[0]});
  63. $username{$data[0]} = $data[2];
  64.  
  65. print "WARNING: Home directory non-existant for user $data[0] ($data[5])\n" unless (-e $data[5]);
  66. print "WARNING: Shell non-existant for user $data[0] ($data[6])\n" unless (-e $data[6]);
  67. }
  68. }

4. Conexiones de red

Arpmap

Todo administrador de una red grande basada en TCP/IP se topará tarde o temprano con que algún usuario que cree saber lo que hace ha modificado su dirección IP. Esto puede llevar al caos, imposibilitándonos saber qué computadora está causando choques de direcciones o dónde está determinada dirección. Este programa nos ayuda tomando fotografías de la red en determinado momento, para que podamos compararla con fotografías futuras.

Funcionamiento general

El programa es invocado dándole la interfaz sobre la cual trabajar - recuerden que arp es un protocolo no ruteable. El programa obtiene la configuración de la red del comando definido en $ifconfigCmd. Para guardar los resultados abre el archivo indicado en $filename, y si este ya existe lee los datos ya existentes para no volver a buscar direcciones ya resueltas. Posteriormente, revisa todo el segmento (funciona únicamente con redes clase B o clase C).
Sugiero correr el programa a través de cron cada media hora por un par de días para encontrar también a las computadoras apagadas a la hora de la ejecución.

Funcionamiento: Obteniendo la configuración de la red

arpmap utiliza ampliamente la capacidad de encontrar patrones de Perl. Al llamar a ifconfig itera sobre el arreglo resultante, buscando primero que nada una línea que calce con ^[\w\d\:]+ indicando el nombre de una interfaz de red. Si no especificamos al llamar al programa, pregunta cuál de las interfaces es la que nos interesa. Después de esto, asigna la siguiente línea a $ip y a $mask, para seleccionar en ambas únicamente la porción que nos interesa, reduciéndolas a cadenas [\d\.]+

Funcionamiento: Resolviendo las direcciones

Para poder resolver una dirección IP hacia su MAC correspondiente tenemos que tenerla ya en el cache del kernel, es por ello que corremos $findCmd, que típicamente será un ping. Después de esto preguntamos por la IP utilizando $arpCmd, y buscamos en el resultado calzar con el patrón /Address.*HWtype/ (indicando una dirección encontrada) o /incomplete/ (indicando falla, usualmente por ser la dirección local). Para guardar la dirección utilizamos print a secas, dado que en la función &openFile tenemos un select(OUT), enviando toda salida estándar al archivo.

Reporte de resultados

El resultado de ejecutar este script es un archivo
con un formato como el siguiente:

  1.  
  2. 192.168.1.1 - 00:50:DA:66:DB:5C
  3. 192.168.1.3 - 08:00:20:AE:C9:0C
  4. 192.168.1.6 - 00:50:DA:1F:00:7C
  5. 192.168.1.7 - 00:50:DA:66:DB:60
  6. 192.168.1.8 - 00:50:DA:0D:12:F2
  7. 192.168.1.9 - 00:A0:24:16:92:CA
  8. 192.168.1.10 - 00:60:97:60:60:50
  9. 192.168.1.20 - 00:50:DA:60:9A:E2
  10. 192.168.1.22 - 00:01:02:60:3B:EA
  11. 192.168.1.25 - 00:A0:24:16:93:BD
  12. 192.168.1.29 - 00:50:04:01:3D:A7
  13. 192.168.1.31 - 00:60:08:48:C2:5B
  14. 192.168.1.32 - 00:A0:24:C3:F9:49
  15. 192.168.1.33 - 08:00:20:76:8D:98
  16. 192.168.1.38 - 00:60:08:C7:5B:FB
  17. 192.168.1.41 - 00:60:08:C7:5C:00
  18. 192.168.1.44 - 00:A0:24:16:93:65
  19. 192.168.1.45 - 00:60:08:C6:77:3F
  20. 192.168.1.47 - 00:A0:24:1B:51:79
  21. 192.168.1.49 - 00:A0:24:15:97:D5
  22. (...)

donde nos indica cada dirección IP localizada y su dirección
MAC correspondiente.
  1. #!/usr/bin/perl -w
  2. #
  3. # Maps the IP addresses on your local Ethernet to their ARP equivalents
  4. #
  5. # REQUIRES: Being run by any user authorized to run ping, arp and ifconfig
  6. use strict;
  7. use vars qw($ifconfigCmd $findCmd $arpCmd $interactive %done);
  8. my ($ip,$mask,$class,$filename);
  9. # ---------configuration area--------
  10. # Path to the ifconfig binary
  11. $ifconfigCmd = '/sbin/ifconfig';
  12. # Command to run to find a host
  13. # (a simple ping will do, just take care not to
  14. # execute an eternal ping)
  15. #
  16. # Put %ip% where the IP should be given.
  17. $findCmd = '/bin/ping -c 1 %ip%';
  18. # Path to the arp binary
  19. $arpCmd = '/sbin/arp';
  20. # filename for output. If the file already exists, it
  21. # will be checked, in order not to repeat the whole
  22. # process.
  23. # If left empty, output will go to STDOUT.
  24. if ($ARGV[1]) {
  25. $filename=$ARGV[1];
  26. } else {
  27. $filename = 'arpmap.txt';
  28. }
  29. # -----end of configuration area-----
  30. #
  31. # Run in interactive mode if called with no arguments
  32. $interactive = ($#ARGV==-1);
  33. ($ip,$mask) = &findIp();
  34. $class=&checkMask($mask);
  35. &openFile($filename) if (defined $filename && $filename ne '');
  36. $|=1;
  37. &getArp($ip,$class);
  38. close(OUT) if (defined $filename && $filename ne '');
  39. exit 0;
  40. sub openFile {
  41. my ($filename);
  42. $filename=$_[0];
  43. &readFile($filename) if (-f $filename);
  44. open (OUT,">>$filename") or die "Could not open $filename for output";
  45. select(OUT);
  46. }
  47. sub readFile {
  48. my ($filename,@in,$line,$ip,$mac);
  49. $filename=$_[0];
  50. open (IN,$filename) or die "Could not open $filename for input";
  51. @in=<IN>;
  52. close (IN);
  53. while ($line=shift(@in)) {
  54. ($ip,$mac) = split(' - ',$line);
  55. $done{$ip}=$mac;
  56. }
  57. }
  58. sub findIp {
  59. my ($line,@ifconfig,%interfaces,$int,$ip,$mask);
  60. @ifconfig=`$ifconfigCmd`;
  61. while ($line = shift(@ifconfig)) {
  62. chomp $line;
  63. if ($line =~ s/^([\w\d\:]+).*/$1/ && $line ne 'lo') {
  64. $interfaces{$line} = shift(@ifconfig);
  65. chomp($interfaces{$line});
  66. }
  67. }
  68. if ($interactive) {
  69. $int='';
  70. while (not defined $interfaces{$int}) {
  71. print "\nThe following interfaces were found on your system:\n";
  72. print join ("\n ",keys(%interfaces));
  73. print "\nWhich interface do you want to map? ";
  74. $int = <STDIN>;
  75. chomp ($int);
  76. }
  77. } else {
  78. if (defined $interfaces{$ARGV[0]}) {
  79. $int = $ARGV[0];
  80. } else {
  81. print "\nInterface $ARGV[0] not found\n\n";
  82. exit 0
  83. }
  84. }
  85. $ip = $mask = $interfaces{$int};
  86. $ip =~ s/^.*inet addr:([\d\.]+).*/$1/;
  87. $mask =~ s/^.*Mask:([\d\.]+).*/$1/;
  88. return ($ip,$mask);
  89. }
  90. sub checkMask {
  91. my ($mask,@mask,$class);
  92. $mask=$_[0];
  93. @mask = split(/./,$mask);
  94. if ($mask eq '255.255.255.0') {
  95. $class=24;
  96. } elsif ($mask eq '255.255.0.0') {
  97. $class=16;
  98. } elsif ($mask eq '255.0.0.0' || $mask eq '0.0.0.0') {
  99. print "Your network is too large - Stay out of troubles, don't try to map it.\n";
  100. exit 0;
  101. } elsif ($mask eq '255.255.255.255') {
  102. print "This is a point-to-point network or something weird.\n";
  103. print "I'd better cowardly stay away from it...";
  104. exit 0;
  105. } else {
  106. print "Sorry, arpmap does not handle subclasses yet.\n";
  107. exit 0;
  108. }
  109. return $class;
  110. }
  111. sub getArp {
  112. my ($myip,$class,$ip,$oct3,$oct4);
  113. $myip = $_[0];
  114. $class = $_[1];
  115. $ip = $myip;
  116. # $class must be either 16 or 24
  117. if ($class == 24) {
  118. $ip =~ s/^(\d+\.\d+\.\d+\.).*/$1/;
  119. for ($oct4=1;$oct4<255;$oct4++) {
  120. &getIp($ip.$oct4);
  121. }
  122. } elsif ($class == 16) {
  123. $ip =~ s/^(\d+\.\d+\.).*/$1/;
  124. for ($oct3=1;$oct3<255;$oct3++) {
  125. for ($oct4=0;$oct4<=255;$oct4++) {
  126. &getIp($ip.$oct3.$oct4);
  127. }
  128. }
  129. } else {
  130. die "I was waiting for a 16 or a 24 and got a $class!";
  131. }
  132. }
  133. sub getIp {
  134. my ($ip,$command,@arp,@arp2,$arp,$line);
  135. $ip=$_[0];
  136. return if (defined $done{$ip});
  137. $command = $findCmd;
  138. $command =~ s/\%ip\%/$ip/;
  139. system("$command > /dev/null");
  140. @arp=`$arpCmd $ip`;
  141. foreach $line (@arp) {
  142. chomp $line;
  143. # Go to next line if this one is the header
  144. next if ($line =~ /Address.*HWtype/ || $line =~ /incomplete/);
  145. @arp2=split(/\s+/,$line);
  146. $arp = $arp2[2];
  147. print "$ip - $arp\n" if ($arp !~ /--/);
  148. }
  149. }

spam

Todos nosotros odiamos el spam. ¿Cómo consiguen nuestras direcciones los spammers? Buscándolas por Web. Cualquiera de nuestros correos aparece casi seguramente en al menos una página.
Ahora... Si tan solo pudiéramos alimentar con basura a los recolectores de direcciones para que su trabajo fuera inútil... ¡Pero podemos! Podemos darles cantidades ilimitadas de direcciones falsas... Eso es lo que hace este script.
Gracias a Jason Costomiris por el escribirlo y publicarlo en http://www.jasons.org, de donde lo bajé.

Consideraciones de seguridad

Este CGI es bastante sencillo y está programado con cuidado. Sin embargo, hay algunos puntos a considerar:

  • La página tiene una liga que conduce de vuelta a sí misma, lo cual -con un robot recolector suficientemente rápido- puede llevar a una negación de servicio. No olviden que levantar un CGI cuesta bastante tiempo.
  • El levantar un CGI nos obliga doblemente a estar al día en problemas que pueda presentar nuestro servidor Web y el mismo Perl, dado que abrimos al mundo entero una ventana que permite ejecutar código -aunque sea nuestro- en el servidor. Si aparece algún método para explotar al servidor a través de CGIs, o algún problema con Perl, seremos vulnerables.

Funcionamiento general

Es un script muy sencillo. Después de crear dos arreglos, uno con las 26 letras del alfabeto y uno con varios top-level domains. Genera hasta 500 direcciones consistentes de hasta ocho letras para login y hasta 10 letras mas el TLD para el dominio, presentándolas en un CGI como ligas (<a href="mailto:..."&gt). Por último, genera una liga hacia el mismo script, para que un robot recolector de direcciones sin mucha inteligencia caiga en un ciclo infinito de recolección de direcciones.

  1. #!/usr/bin/perl -T
  2. # Copyleft 1997 Jason Costomiris (whois:JC1011).
  3. # Rights? You had rights? When I was a kid......
  4. require 5.003;
  5. use strict;
  6. use CGI;
  7. my ($i, $j, $k);
  8. my @abc = ('a'..'z');
  9. my @tld = ('com', 'net', 'org', 'mil', 'gov', 'hey-dork', 'spam-sucks');
  10. my $fodder = new CGI;
  11. print $fodder->header;
  12. print $fodder->start_html(-title=>'Spam fodder',
  13. -BGCOLOR=>'#FFFFFF');
  14. print "&lt;a href=\"mailto:abuse\?subject=I am a spamming luser\"&gt;abuse&lt;/a&gt;&lt;br/&gt;\n";
  15. srand;
  16. my $number = int(rand(500));
  17. for ($i = 0 ; $i <= $number ; $i++) {
  18. my $name = "";
  19. my $domain = "";
  20. my $num_name = int(rand(8));
  21. for ($j = 0 ; $j <= $num_name ; $j++) {
  22. $name .= $abc[int(rand($#abc))];
  23. }
  24. my $num_domain = int(rand(10));
  25. for ($k = 0 ; $k <= $num_domain ; $k++){
  26. $domain .= $abc[int(rand($#abc))];
  27. }
  28. my $tld = $tld[int(rand($#tld))];
  29. my $address = $name . '@' . $domain . '.' . $tld;
  30. print "&lt;a href=\"mailto:$address\?subject=I am a spamming luser\"&gt;$address&lt;/a&gt;&lt;br/&gt;\n";
  31. }
  32. #
  33. # Now that we've given lots of bad addresses to them, let's put them in an
  34. # endless loop
  35. #
  36. print "\n&lt;pgt;\n&lt;a href=\"$ENV{SCRIPT_NAME}\"&gt;endless loop of these pages for spam-spiders. Yay.&lt;/a&gt;\n";
  37. print $fodder->end_html;

honeypot

Tras un ataque a nuestro sitio es muy importante analizar qué hizo el atacante - No sólo los pasos que siguió para penetrar en nuestro sistema, sino que también qué hizo una vez dentro. Muchas veces quisiéramos poder analizar qué intentos de intrusión ha habido, o frustrarlos dando al posible atacante información falsa. Para esto podemos crear sistemas trampa, que aparenten dar cierto servicio pero en realidad no lo estén dando, y sólo estén registrando todo lo que reciban. Perl es ideal para esto, dada su facilidad para la programación en red.

Consideraciones de seguridad

  • Estamos ante un atacante. Si bien nuestro programa no debe tener ninguna característica que pueda comprometer al sistema, es importante que no lo corramos como root sino que como un usuario sin ningún privilegio, posiblemente desde inetd.conf
  • El uso de estos sistemas es un tanto controversial - Por un lado, porque al dar información falsa estamos practicando seguridad por obscuridad, lo cual nunca sirve de mucho, y por otro lado, porque si un atacante se da cuenta de que está atacando a un sistema trampa, puede reaccionar empeñándose más en lograr penetrar el sistema.

Funcionamiento general

Hay varios servicios que son muy sencillos de emular, y que pueden no ser necesarios para nuestro sistema. Los ejemplos más clásicos son finger, SMTP, POP3 y HTTP. Claro, el juzgarlos innecesarios depende de cada sitio. Nuestro programa emulará respuestas válidas de estos servicios, registrando en syslog cualquier uso que el atacante intente hacer de ellos.
Como todos estos servicios pueden ser iniciados desde inetd.conf, no nos preocuparemos de los sockets, manejando toda entrada y salida por las vías estándar.

Funcionamiento: Interacción con la red

La interacción será manejada por el demonio inet, lo cual nos simplifica mucho la tarea: Toda entrada y salida la manejamos con STDIN y STDOUT.
STDIN puede ser manejado como un socket, y lo hacemos en la función connData, donde obtenemos la dirección y puerto de la cual procede la comunicación.

Funcionamiento: Registro

Con un sistema trampa querremos registrar todo lo que el posible atacante intente hacer. Para hacerlo, utilizamos el Syslog, utilizando el módulo Sys::Syslog que viene incluído con la distribución estándar de Perl. Inicializamos el servicio con las siguientes líneas:

  1. use Sys::Syslog qw(:DEFAULT setlogsock);
  2. setlogsock('unix');
  3. openlog('honeypot','cons,pid','honeypot');

y registramos cada línea recibida a través de la función logger que simplemente hace:
syslog('info',join(' ',@_));

Funcionamiento: Lo implementado

En este script están implementados emuladores de tres populares protocolos: Finger, SMTP y POP3. Finger es un protocolo suficientemente sencillo como para poder sido emulado por completo con sólo un par de líneas. Cuando recibe una solicitud sobre cualquier usuario -válido o no- responde algo que aparenta éxito, al reportar conexiones marca que no hay nadie conectado, y al solicitar una redirección la niega.
POP3 responde en un formato similar al del servidor imapd incluído en muchas distribuciones de Linux; reporta siempre éxito al recibir nombre de usuario y error al recibir la contraseña.
SMTP aparenta ser un sendmail. La implementación es muy sencilla, tal vez demasiado simple (no olviden que estos scripts son sólo ejemplos, no deben ser utilizados sin ser estudiados y modificados por el administrador): Responde exitosamente a cualquier HELO/EHLO, y marca error a cualquier MAIL FROM. Es importante responder siempre así, pues de no hacerlo un usuario podría legítimamente enviarnos un correo y nunca llegaría a su destino.

  1. #!/usr/bin/perl -T
  2. #
  3. # This script should be run from /etc/inetd.conf as follows:
  4. #
  5. # (port) stream tcp nowait (user) (path-to-script) (script) (argument)
  6. #
  7. # for example:
  8. # finger stream tcp nowait nobody /usr/local/sbin/honeypot.pl honeypot.pl finger
  9. # pop3 stream tcp nowait nobody /usr/local/sbin/honeypot.pl honeypot.pl pop3
  10. #
  11. # IMPORTANT NOTE
  12. # Having a honeypot system does *NOT* make it any safer. In fact, it makes
  13. # it a GREAT target for attacks. An attacker might get angry at you laughing
  14. # at him and attack with greater strength. Even if you enhance its behavior,
  15. # it is not hard to notice you are not talking to a real server. Use this
  16. # ONLY at machines DEDICATED to network monitoring and information
  17. # gathering. Most important, USE AT YOUR VERY OWN RISK.
  18. use strict;
  19. use Sys::Syslog qw(:DEFAULT setlogsock);
  20. use IO::Socket;
  21. use vars qw($hostname);
  22. # Set to the hostname you want to tell the clients
  23. $hostname = 'asdf.qwerty.org';
  24. $|=1;
  25. setlogsock('unix');
  26. openlog('honeypot','cons,pid','honeypot');
  27. &connData;
  28. if ($ARGV[0] eq 'finger') {
  29. &finger;
  30. } elsif ($ARGV[0] eq 'pop3') {
  31. &pop3;
  32. } elsif ($ARGV[0] eq 'smtp') {
  33. &smtp;
  34. } else {
  35. &logger("ERROR - $ARGV[0] not defined\n");
  36. }
  37. exit 0;
  38. sub pop3 {
  39. # emulates a POP3 connection, accepting every username and
  40. # denying every password. It honors the 'quit' command, in
  41. # case a legitimate client tries to connect and refuses to
  42. # leave unpolitely. Everything else is denied.
  43. my ($request);
  44. print "+OK POP3 $hostname v4.76 server ready\n";
  45. while ($request=<STDIN>) {
  46. &logger("RECEIVED: '$request'");
  47. $request =~ s/[\r\n]//g;
  48. if ($request=~/^user\b.+\w+/i) {
  49. print "+OK User name accepted, password please\n";
  50. } elsif ($request=~/^pass\b.+\w+/i) {
  51. print "-ERR Bad login\n";
  52. } elsif ($request=~/^quit\b/i) {
  53. print "+OK Sayonara\n";
  54. exit 0;
  55. } else {
  56. print "-ERR Unknown AUTHORIZATION state command\n";
  57. }
  58. }
  59. }
  60. sub smtp {
  61. # emulates a SMTP connection, denying access to all senders.
  62. # HELO/EHLO is honored. It honors the 'quit' command, in
  63. # case a legitimate client tries to connect and refuses to
  64. # leave unpolitely. Everything else is denied.
  65. my ($request);
  66. print "220 $hostname ESMTP MailServer 6.4.5\n";
  67. while ($request = <STDIN>) {
  68. &logger("RECEIVED: '$request'");
  69. $request =~ s/[\r\n]//g;
  70. if ($request =~ /^mail\s+from:\s?(.+)/i) {
  71. print "550 $1...Access denied\n";
  72. } elsif ($request =~ /^helo\s+(.+)/i || $request =~ /^ehlo\s+(.+)/i) {
  73. print "250 $hostname Hello $1, pleased to meet you\n";
  74. } elsif ($request =~ /^quit/i) {
  75. print "221 $hostname closing connection\n";
  76. exit 0;
  77. } else {
  78. print "Command unrecognized: $request\n";
  79. }
  80. }
  81. }
  82. sub finger {
  83. # emulates a finger connection. If a user request is recieved
  84. # (no '@' characters), it is served with a dummy template, making
  85. # each and every user searched appear as valid. If an empty request
  86. # is recieved, it shows no users logged in. If a redirect request is
  87. # recieved, it is denied right away.
  88. my ($request);
  89. $request = <STDIN>;
  90. &logger("RECEIVED: '$request'");
  91. $request =~ s/[\r\n]//g;
  92. if ($request =~ /\@/) {
  93. # Forwarding
  94. print "fingerd: forwarding not allowed\n";
  95. } elsif ($request =~ /^$/) {
  96. # Who is online
  97. print "Login Name Tty Idle Login Time Office Office Phone\n";
  98. } elsif ($request =~ /^\w+$/) {
  99. # user's login information
  100. print "Login: $request".' 'x(33-length($request)).
  101. "Name:$request\nDirectory: /home/$request".
  102. ' 'x(23-length($request))."Shell: /bin/bash\nNever logged in.
  103. \nNo mail.\nNo Plan.\n";
  104. }
  105. }
  106. sub connData {
  107. # Gets and logs connection data
  108. my ($src_conn,$src_port,$src_iaddr,$src_ip_address);
  109. $src_conn=getpeername(STDIN);
  110. ($src_port,$src_iaddr)=unpack_sockaddr_in($src_conn);
  111. $src_ip_address=inet_ntoa($src_iaddr);
  112. &logger("Connection recieved from $src_ip_address, source port $src_port for $ARGV[0]");
  113. }
  114. sub logger {
  115. syslog('info',join(' ',@_));
  116. }

ProtoWrap

Concepto general:

Para evitar ataques a diferentes servicios, ProtoWrap envuelve la comunicación, permitiendo que pase únicamente lo que sea validado como correcto.
Consultar http://www.gwolf.org/seguridad/wrap

5. Conclusión

Bibliografía

Varios de los ejemplos aquí presentados fueron tomados del libro Perl for System Administration, de David N. Blank-Edelman, publicado por O’Reilly en junio del 2000 (ISBN 1-56592-609-9).
Otras importantes fuentes de recursos para scripts aplicables a la seguridad son:

  • The Perl Journal, revista cuatrimestral dedicada exclusivamente a Perl.
  • SysAdmin, revista mensual dedicada a la administración de sistemas.
  • Programming Perl 3rd edition, Larry Wall, Tom Christiansen y Jon Orwant (O’Reilly 2000)
  • Perl Cookbook, Tom Christiansen y Nathan Torkington (O’Reilly 1998)
  • Advanced Perl Programming, Sriram Srinivasan (O’Reilly 1997)
  • http://www.ora.com/ - O’Reilly Associates, editores de una gran cantidad de libros de Perl y de administración de sistemas de muy buena calidad.
  • http://www.cpan.org/ - Comprehensive Perl Archive Network, miles de módulos, scripts, ports y documentación de Perl.
  • http://www.perl.com/ y http://www.perl.com - Los sitios oficiales de Perl
  • http://use.perl.org/ - Noticias de Perl
  • http://www.metronet.com/1/perlinfo/scripts/ - Colección de juguetes, trucos y trampas en Perl