Comprueba si tu correo es propenso a clasificarse como SPAM

Hoy he estado configurando un servidor de correo electrónico para poder enviar y recibir correos desde mi propio servidor y con mi propio dominio y de esta forma saltarme a los proveedores de correo electrónico que te piden una cuota mensual para ofrecerte un correo electrónico.

Para el servidor saliente he usado Postfix y para el servidor IMAP he usado dovecot, todo esto unido a mysql para poder tener cuentas virtuales. Pero aquí no voy a hablar de la configuración del correo, que es bastante engorrosa.

Después de tener todo configurado he estado haciendo pruebas de enviar y recibir correo electrónico y todo iba bien, exceptuando que algunos correos eran clasificados como SPAM.

Y buscando por ahí he encontrado un método bastante interesante para saber la probabilidad de que un correo sea clasificado como SPAM. Solamente necesitas enviar un correo a la dirección test@allaboutspam.com y esperar un rato. Al cabo de un rato recibirás un correo como este:

This is the mail system at host (angelluis)anlu.********.es.

I'm sorry to have to inform you that your message could not
be delivered to one or more recipients. It's attached below.

For further assistance, please send mail to postmaster.

If you do so, please include this problem report. You can
delete your own text from the attached returned message.

                   The mail system

<test@allaboutspam.com>: host mx.allaboutspam.com[96.126.107.60] said:
    552-Thanks for using ALLABOUTSPAM.COM Email server test. Your test results
    are 552 available at
    http://www.allaboutspam.com/email-server-test-report/?key=************************
    (in reply to end of DATA command)

Es el típico correo que nos dice que la dirección de correo no existe o que no se ha podido entregar el correo eléctronico, pero en este caso se nos facilita un enlace donde obrenemos un resumen de parametros de nuestro correo y nuestro servidor que están relacionados con la clasificación como SPAM.

spam

Si bajamos en la página que se nos facilita veremos

spam

Concretamente el correo que he enviado ha obtenido una puntuación de 5.4 y lo ideal es tener una puntuación inferior a 5, así que este correo es clasificado como SPAM. La razón básicamente es que el correo que he enviado a test@allaboutspam.com lo he enviado sin asunto y sin cuerpo de mensaje.

ByPassing DEP y ASLR

Para compilar el programa name.c para este artículo es necesario desactivar DEP:

gcc -m32 -fno-stack-protector name.c -o name

Esta vez no hay que desactivar ASLR, si estuviese desactivado se puede activar de la siguiente forma:

echo 2 > /proc/sys/kernel/randomize_va_space

En los dos capítulos previos estudiamos las protecciones DEP y ASLR y rompimos su seguridad por separado. Lógicamente este artículo va a ir sobre como conseguir atacar satisfactoriamente un programa protegido por estas dos protecciones.

Lo primero que hay que tener en cuenta es que ahora ya no podemos ejecutar desde la zona de datos (porque DEP protege contra tal acto) y además no tenemos una zona fija donde almacenar datos (puesto que ASLR aleatoriza el espacio de direcciones de un proceso).

Hay varias soluciones para afrontar este problema. Aquí voy a explicar una bastante sencilla basada en técnicas usadas en artículos anteriores, por lo que este artículo no será muy largo.

Para empezar hemos hecho una pequeña reforma a nuestro programa vulnerable:

Vemos que los principales cambios es añadir la función exit(0) en vez de return 0 y el uso de la función system() en vez de printf.

En este ejemplo en concreto queda raro y forzado, pero no es raro encontrar estas funciones en programas.

¿Por que hemos hecho estos cambios? Básicamente porque vamos a emplear una técnica llamada Return to PLT que es similar a Return to Libc. Si recordamos bien, Return to Libc la utilizamos cuando quisimos saltarnos DEP y básicamente consistia en proporcionar en EIP la dirección de una función de Libc (en nuestro caso fue de system).

Ahora no podemos usar Return to Libc porque no podemos proporcionar una dirección exacta de la función system debido a la protección ASLR. Pero aquí viene en nuestro ayuda la PLT.

PLT significa Procedure Linkage Table y es usada junto a GOT (Global Offset Table) para que el loader del Sistema Operativo sepa linkar nuestro programa con las librerías compartidas. Básicamente nuestro programa tiene una PLT donde almacena las llamadas a procedimientos de librerias compartidas. La primera vez que nuestro programa llama a una de estas funciones, la tabla se rellena con la dirección real de dicha función. Por tanto, la primera vez que llamamos a printf, nuestro programa consulta PLT ve que no tiene la dirección de printf y la resuelve en tiempo de ejecución, la próxima vez que se llame a printf su direccion real ya estará resuelta y no hará falta resolverla de nuevo. PLT y GOT se escapan del ámbito de estos artículos pero se puede encontrar mucha información sobre ellos buscando sobre Linkers y Loaders.

Y no, la tabla PLT no se ve afectada por la aleatorizacion de ASLR.

Conclusión, tenemos una tabla con las direcciones a funciones que nuestro programa usa, y estas direcciones son fijas ¡incluso con ASLR activado!. La desventaja es que la llamada a dicha función se debe encontrar dentro de nuestro programa (de ahí que hayamos tenido que usarla de una forma un tanto forzada).

Vale, tenemos un programa vulnerable con una función system y que podemos llamar gracias a PLT, pero a system hay que pasarle un argumento y seguimos teniendo ASLR activo por lo que nuestro argumento tendrá una dirección variable de memoria.

¿Os acordais del artículo anterior? En él introdujimos nuestro exploit en una variable de entorno con una gran cantidad de NOP's para que una vez que caiga en el primer NOP se vaya desplazando hasta llegar a nuestro shellcode real. Pues esta vez vamos a emplear algo parecido, solo que en vez de introducir en nuestra variable de entorno un shellcode, vamos a introducir la orden “/bin/sh” que nos va a proporcionar una shell pero, como en el artículo anterior, esto nos arrojaria muchos fallos, hasta el punto de tener que usar un ataque de fuerza bruta de miles de intentos, así que vamos a meter también un colchon de NOPs para que una vez que la dirección proporcionada como argumento de system caiga en nuestra variable de entorno, esta se vaya desplazando hasta encontrar el comando /bin/sh.

Bueno, basta de teoría, pasemos a la práctica. Primero tenemos que hacernos con las direcciones de memoria de system@plt y exit@plt, para ello usamos gdb y desensamblamos la funcion main

0

En la imagen podemos ver como mi binario tiene la función system@plt en la dirección 0x8048370 y la función exit@plt en la dirección 0x8038390. Vamos a exportar ahora una variable de entorno que contenga una gran cantidad de comandos inútiles (o incluso inválidos, en mi caso usaré estos ultimos porque mi shell no me permite introducir espacios) y un comando “/bin/sh”

export xploit=`python -c "print 'echo_a;'*18000+'/bin/sh'"`

Una vez más hay que tener en cuenta que la variable de entorno debe ser bastante grande pero hay que tener cuidado porque algunas shells imponen límites de tamaño para las variables de entorno, en mi caso la variable es de 6*18000+7 bytes, lo que hace un total de 9007 bytes. Vamos a ejecutar ahora nuestro ya conocido programa getenv que nos devuelve la dirección de una variable de entorno con respecto al programa vulnerable.

1

Lo ejecutamos unas cuantas veces y vemos que efectivamente la dirección de memoria varía. Ahora elegimos una, la que sea, por ejemplo, en mi caso voy a elegir la última 0xfff3733e. Y si recordamos el artículo sobre Return to Libc sabremos que tendremos que pasar los argumentos de la siguiente forma

AAAA...AAAA + DIRECCIÓN_SYSTEM + DIRECCIÓN_EXIT + DIRECCIÓN_PARÁMETRO_SYSTEM

para que la pila quede así

DIRECCIÓN_PARÁMETRO_SYSTEM
DIRECCIÓN_EXIT
DIRECCIÓN_SYSTEM
AAAA...AAAA

Pero esto, es un ataque de fuerza bruta, por tanto deberemos crear una shellscript como hicimos en el artículo anterior para ir probando hasta que obtengamos una shell. El script puede ser el siguiente

damos permisos de ejecución al script mediante

chmod +x xploit.sh

y ejecutamos mediante

./xploit.sh

2

¡Tachan! ¡Volvimos a obtener una shell con DEP y ASLR activado!

Conclusiones

Aquí acaba esta serie de artículos, nos hemos dejado en el camino muchas técnicas y algunas protecciones pero hemos estado viendo lo básico sobre stacks overflows y como romper dos protecciones usadas en entornos reales.

En el camino nos hemos dejado una protección implementada por el compilador basada en cookies o canaries, estas técnicas se basan en poner un número en una dirección de memoria entre nuestro buffer y el valor de EIP, al regresar de la función, si este valor no coincide con el almacenado en un lugar seguro por el programa entonces se detendrá la ejecución. Además algunas de estas ténicas del compilador son capaces de reorganizar nuestras variables para situar a los buffers en las primeras zonas de memoria después del valor de EIP, dejando variables primitivas y punteros debajo de los buffers.

En GCC, el estandar es Stack Smash Protector o ProPolice que es capaz de usar 2 canaries distintos, o bien uno generado aleatoriamente y que es comprobado por el programa siempre que se va a recuperar el valor de EIP, o bien usar un canary prefijado: 0x000aff0d. Este canary está muy bien pensando y rompe nuestros ataques completamente, 0x00 es el byte null por lo que acabaria con los ataques basados en string, 0x0a es el salto de línea \n y acabaria con los desbordamientos mediante las familias gets, 0xff es el indicador de fin de archivo y 0x0d es el carater \r. Esta protección en algunas distribuciones Linux viene desactivada por defecto, en mi ubuntu viene activada y en cada programa vulnerable he tenido que desactivarla. En efecto, esta protección se corresponde a la opción -fno-stack-protector, si quitamos esa opción cuando compilamos, ninguno de los ataques empleados aquí tendría efecto.

3

Si realizamos el ataque de este artículo sobre el mismo programa pero quitando la opción -fno-stack-protector, veremos que el programa detecta que se ha desbordado el buffer y termina.

También se nos ha quedado en el tintero los ataques de heap overflow y los de las cadenas de formato.

Es posible que en un futuro escriba algo sobre ello.

ByPassing ASLR

Para compilar el programa name.c para este artículo es necesario desactivar DEP:

gcc -m32 -fno-stack-protector -z execstack name.c -o name

Esta vez no hay que desactivar ASLR, si estuviese desactivado se puede activar de la siguiente forma:

echo 2 > /proc/sys/kernel/randomize_va_space

En el artículo anterior estudiamos la protección DEP y ahora toca estudiar ASLR.

ASLR significa Address Space Layout Randomization y es una técnica implementada a nivel de sistema operativo para aleatorizar las direcciones de memoria dentro del espacio de memoria de un proceso, de esta forma una librería como puede ser libc no será cargada siempre en la misma zona de memoria y por tanto técnicas como Return to libc o Jump To Esp no se podrán llevar a cabo tan facilmente.

En este articulo vamos a activar ASLR. Si no lo tenemos activo podemos ejecutar el siguiente comando como root para activarlo

echo 2 > /proc/sys/kernel/randomize_va_space

Pero vamos a volver a desactivar DEP para que nos resulte un poco más sencillo.

Por tanto, el programa vulnerable tendremos que compilarlo mediante la siguiente instrucción

gcc -z execstack -fno-stack-protector name.c -o name

¿Como podemos comprobar si ASLR está activo?

Podemos comprobarlo facilmente ejecutando el comando ldd sobre nuestro programa para ver si las direcciones de memoria varian.

0

Aquí podemos ver como las direcciones de las librerías cargadas varian, si no es así significa que no tenemos ASLR activo. Por lo general algunas librerías de terceros en Windows no son aleatorizadas y en linux el segmento text de nuestro programa tampoco se aleatoriza a no ser que se compile como código independiente de la posición (-fpic).

Este descuido nos deja la puerta a abierta ataques del tipo Return to PLT que veremos en el siguiente artículo, que nos será bastante efectivo cuando DEP y ASLR está activo.

Además podemos imprimir la direccion de una variable de entorno cualquiera y ver que también cambia de dirección de memoria.

1

Pero podemos observar algo realmente interesante. Podemos observar que el byte más significativo no varía, además el byte menos significativo tampoco varia, ni el nibble a continuación del byte menos significativo tampoco varia. Si tomamos una muestra (empezando por el último) de los bytes que varian y lo pasamos a binario obtenemos.

9d8 1001 1101 1000
b59 1011 0101 1001
de4 1101 1110 0110
b81 1011 1000 0001
d0d 1101 0000 1101
d62 1101 0110 0010

Podemos ver como el bit más significativo tampoco varía.

ASLR nos promete que para la pila hay 24 bits aleatorios, obviando los bytes más significativos y teniendo en cuenta lo observado más arriba de que el bit más significativo tampoco es aletorio obtendriamos que el número de bits aleatorios es realmente 23 (2^23 = 8MB que es el tamaño máximo de pila).

Además en el artículo anterior pasamos por alto un pequeño detalle

2

¿Lo véis? En la sección GNU_STACK pone que debe de haber un alineamiento de 0x10 (16). Por tanto el número total de posibilidades para una variable en el stack seria 2^23/16 = 524288. Siguen siendo muchas posibilidades para un ataque de fuerza bruta.

¿Pero y si creamos una variable de entorno con una gran cantidad de nops? ¿Por ejemplo 100.000 nops? Pues que tendriamos una variable bastante larga y si diese la casualidad de que cuando ejecutamos el programa esta variable se encuentra en una dirección de memoria que nosotros especificamos ira recorriendo todos los nops hasta llegar a nuestro shellcode. En efecto, vamos a proceder a realizar una atque de fuerza bruta.

Para ello primero exportamos la siguiente variable de entorno:

export xploit=`python -c "print '\x90' * 100000 + '\xeb\x14\x5e\x31\xc0\x88\x46\x07\xb0\x0b\x89\xf3\x31\xc9\x31\xd2\xcd\x80\xb0\x01\xcd\x80\xe8\xe7\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68'"`

Aquí exportamos la variable xploit con 100.000 nops y acto seguido nuestro conocido shellcode.

Ahora procedemos a crear el siguiente script:

En este script básicamente llamamos al programa vulnerable con un parametro que es capaz de desbordar el valor de EIP y en EIP proporcionamos una dirección de memoria más o menos cercana o igual a las que hemos obtenido un poco más arriba cuando mostrabamos la accion de ASLR sobre la variable de entorno SHELL

Ejecutamos este script y obtenemos:

3

¡Tachan! Volvimos a poder obtener una shell. Además el ataque ha sido relativamente rápido, unos 2 segundos ha tardado en obtener una shell.

Si no conseguimos obtener una shell, podemos ampliar el número de nops en nuestra variable de entorno (pero con cuidado, ¡algunas shell limitan el tamaño de las variables de entorno!) o podemos aumentar el número de intentos del script.