Programar se asemeja mucho a conducir, se requiere tiempo para adquirir destreza, importa tener talento natural y nadie está libre de cometer errores.
Una pequeña distracción se puede convertir en un error fatal que deje un bug explotable en tu código fuente.
Indudablemente programar con una metodología segura ayuda a evitar problemas mayores, no obstante, siempre viene bien contar con una serie de ayudas extra para minimizar fallos.
En C y C++ los principales problemas que se pueden tener son los temidos buffer overflows. Con el paso del tiempo los compiladores han ido introduciendo sistemas para detectar y abortar este tipo de ataques. Veamos como activar esas protecciones en Windows y Linux:
Una pequeña distracción se puede convertir en un error fatal que deje un bug explotable en tu código fuente.
Indudablemente programar con una metodología segura ayuda a evitar problemas mayores, no obstante, siempre viene bien contar con una serie de ayudas extra para minimizar fallos.
En C y C++ los principales problemas que se pueden tener son los temidos buffer overflows. Con el paso del tiempo los compiladores han ido introduciendo sistemas para detectar y abortar este tipo de ataques. Veamos como activar esas protecciones en Windows y Linux:
Visual Studio
El entorno de desarrollo de Microsoft dispone desde hace tiempo de una opción que activa una protección de tipo 'Canary' para evitar que se pueda sacar partido de un overflow. Para activar esta protección, en las propiedades de nuestro proyecto:
Linux (gcc)
En el caso de GCC tenemos disponible, mediante linea de comandos, la opción -fstack-protector-all que activa todas las protecciones de ProPolice para evitar desbordamientos de buffer.
Veamos un ejemplo real:
Tomando un binario vulnerable a un típico buffer overflow, si lo compilamos de forma normal y tratamos de explotarlo:
Ahora con ProPolice:
Veamos un ejemplo real:
Tomando un binario vulnerable a un típico buffer overflow, si lo compilamos de forma normal y tratamos de explotarlo:
# gcc vulnerable.c -o vulnerableComo se puede ver, el programa es explotable y, una vez ejecutado el exploit, devuelve una shell.
# ./vulnerable `perl -e 'print "A"x173, "\x90"x271,"\x29\xc9\x83\xe9\xf5\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\xb9\x1c\xc9\x53\x83\xeb\xfc\xe2\xf4\xd3\x17\x91\xca\xeb\x7a\xa1\x7e\xda\x95\x2e\x3b\x96\x6f\xa1\x53\xd1\x33\xab\x3a\xd7\x95\x2a\x01\x51\x14\xc9\x53\xb9\x33\xab\x3a\xd7\x33\xba\x3b\xb9\x4b\x9a\xda\x58\xd1\x49\x53","\x98\xf7\xff\xbf"'`
#
Ahora con ProPolice:
# gcc -fstack-protector-all vulnerable.c -o vulnerableProPolice detecta y bloquea el intento haciéndolo fútil.
# ./vulnerable `perl -e 'print "A"x173, "\x90"x271,"\x29\xc9\x83\xe9\xf5\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\xb9\x1c\xc9\x53\x83\xeb\xfc\xe2\xf4\xd3\x17\x91\xca\xeb\x7a\xa1\x7e\xda\x95\x2e\x3b\x96\x6f\xa1\x53\xd1\x33\xab\x3a\xd7\x95\x2a\x01\x51\x14\xc9\x53\xb9\x33\xab\x3a\xd7\x33\xba\x3b\xb9\x4b\x9a\xda\x58\xd1\x49\x53","\x98\xf7\xff\xbf"'`
*** stack smashing detected ***: ./vulnerable terminated
======= Backtrace: =========
/lib/libc.so.6(__fortify_fail+0x48)[0x889bd8]
/lib/libc.so.6(__fortify_fail+0x0)[0x889b90]
./vulnerable[0x804861d]
./vulnerable[0x8048700]
Abortado
Lenguajes Dinámicos
En el caso de los lenguajes dinámicos los problemas son diferentes, en concreto la mayor preocupación viene a la hora de emplearlos para construir aplicaciones web. Ataques de tipo SQL Injection, XSS y derivados son un quebradero de cabeza a la hora de afrontar un desarrollo web.
En el caso de PHP existe un proyecto llamado PHP-IDS que, a modo de librería que se añade al código fuente, permite fortificar un script programado en PHP para evitar ataques.
Si tu eres de los que prefieren los Simpson a Padre de Familia y desarrollas en Perl, también existe un port de PHP-IDS llamado Perl-IDS que permite defender los scripts en Perl.
También existe un port de PHP-IDS para .NET llamado DotNetIDS
5 comments :
En cuanto a Visual Studio, añadir que hay dos tipos de protecciones incluidas. Primero estan las que buscan que un overflow no sea posible, llamemoslas medidas proactivas, aqui se distinguen dos opciones de compilación o flags. Por un lado esta el flag /GS, que creo que es el que comentas en el post, que añade un valor a modo de cookie en la pila y además reorganiza las variables en la pila para que datos de la aplicación y/o argumentos no sean machacables. Por otro lado tenemos el flag /NXCOMPAT que permite que el binario compilado soporte DEP que a su vez establece regiones de memoria donde hay datos (pila, etc...) como no ejecutables.
Y para terminar estan las medidas reactivas que buscan hacer la explotación de un posible bug más dificil una vez este exista. Para ello Visual Studio incorpora el flag /DYNAMICBASE que permite al binario ser compatible con la tecnologia ASLR de las ultimas versiones de vista que recoloca el binario en memoria en momento de cargarlo para que las direcciones de datos conocidos no sean predecibles.
Un saludo!
Está muy bueno el tip de agregar el parámetro "-fstack-protector-all" al compilador. Me pregunto si ese parámetro sirve para cualquier programa? Digo, si me bajo el codigo fuente de, por ejemplo, mplayer y lo compilo pasandole ese parametro, deberia despreocuparme por los futuros BoF que se anuncien?
saludos
@jg Excelente explicación y magnífica web.
@Zerial, si defines la variable CFLAGS (export CFLAGS = -fstack-protector-all ) debería compilar todo con ProPolice
@yago Muchas gracias :)
En cuanto a lo que comentais, compilar pienso que se puede compilar con esos flags, otra cosa es que luego el programa funcione correctamente. Algunas aplicaciones no están pensadas para este tipo de medidas y es muy común (tanto en unix como en windows) que al compilarlas así den fallos y/o casquen. Esto se debe a que la mayoría de los desarrolladores no tienen tiempo/conocimiento para preocuparse por cada detalle a bajo nivel de la implementación (Existen casos en los que los bugs solo son visibles en el binario y inexistentes en el codigo fuente).
Aparte de eso, en el supuesto caso de que consigas compilar y que no casque, las medidas ProPolice no son efectivas en todos los casos. Segun como sea el bug, existe la posibilidad de alterar variables del programa que posteriormente permitan la explotación.
Resulta algo frustrante :(, pero es el eterno juego del gato y el ratón. Como bien se sabe un sistema nunca es 100% seguro y lo mejor que podrias hacer sería intentar minimizar la posible superficie de ataque, etc...pero que te voy a decir yo que google no sepa :-)
Un saludo
Simpson a Padre de Familia y desarrollas en Perl,..... jajajajajaja eres un perro.
Publicar un comentario