Este documento resume la historia de los buffer overflows desde sus comienzos en la década de 1990 hasta las defensas actuales como ASLR y canarios de pila. A pesar de décadas de intentos por mitigarlos, los buffer overflows siguen siendo una amenaza debido a factores culturales como la priorización de la velocidad sobre la seguridad en el desarrollo de software. El documento concluye sugiriendo que una mayor capacitación y cambios en los procesos de desarrollo podrían ayudar a prevenir este tipo de vulnerabilidades
2. Comienzos..
Luego de algunas décadas en existencia
podemos ponerle punto final a los buffer
overflows?
La respuesta no es clara, los overflows son
peligrosos, emocionantes y aterradores. Para
responder, tenemos que entender que son.
3. Si viviste debajo de una roca..
void main(void) {
char buffer[256];
scanf("%s", buffer); /* Lee por E sin size */
}
Ejemplo de buffer overflow de 1996!
4. No es solo Scanf()
Existen una lista interminable de funciones en
ANSI C y otros lenguajes que llevan a una
sobreescritura silenciosa del buffer.
Ejemplos: Strcpy, Memcpy, Gets, Sprintf, etc.
5. Contratemos programadores SR.
Seguramente un programador experimentado
podria evitar un desbordamiento (sick).
La verdad es que no, y para ejemplos el
mercado actual. La seguridad informática es
tabu, en el ambiente de desarrollo se premia
la rapidez, la agilidad y la entrega por sprints.
6. Ejemplo de Mysql 5.5.x
Los desarrolladores de la DB Mysql son
expertos, los usuarios miles de millones. Pero
hace menos de 12 meses apareció un BoF
remoto. Y ya estamos pisando el 2014!
Mas de 40 años de overflows demostraron: Es
increíblemente difícil no escribir overflows!
7. Otro ejemplo y no jodemos mas!
int main(int argc, char *argv[])
{
char buffer[10];
strcpy(buffer, argv[1]);
return 0;
}
8. Hey estamos en el 2013..
Claro, seguramente estarás pensando: Deben
existir algunas medidas de seguridad contra 40
años de overflows.
Por supuesto! Pero para entender como
funcionan esas defensas debemos saber como
es la estructura de un buffer.
9. Desmitificando un overflow
La sobreescritura comienza en
el principio del buffer.
Se sobreescribe hasta llegar al
RA, y controlandolo ejecutamos
codigo. Y así obtenemos Root :-)
10. For fun and profit
El básico de la “Era Aleph One” es inyectar
código x86 directo al buffer y modificar el
return address para que salte al código
inyectado.
Típicamente una System Call para spawnear
una shell, es por eso que lo conocemos como
shellcode. Ahhhh entonces era por eso? :-)
12. Y como obtengo el código x86?
Un atacante debería compilar el código,
extraer el assembler y construirlo formateado
para que se pueda ingresar dentro de una
funcion.
El programa vulnerable ya tiene su funcion!
13. Estructura del exploit
<basura para llenar el buffer y variables>
<return address: donde estara la shellcode>
<shellcode>
Voila! Obtuviste root de algunas máquinas!
Excepto que ya no estamos en 1996..
14. Historia de las defensas
Una de las principales es DEP o Data Execution
Prevention. Tambien conocida como W xor X.
Nunca van a haber dos regiones de memoria
desde donde se pueda a la vez ejecutar y
escribir. El proceso va a “crashear” si el CPU
intenta realizar una acción que active DEP.
15. Deep in DEP..
Esta defensa está basada en la premisa de que
el atacante inyecta código, osea la shellcode!
Por lo tanto nunca, jamás debería ser posible
tomar control de un programa..
Bueno, no exactamente.. ;-)
16. ROP! Return Oriented Programming
Un atacante en vez de inyectar el código que
quiere ejecutar, puede simplemente
encadenar retornos de jumps y reutilizar el
código ya existente.
El target más común de ROP suele ser: La
librería C ( libc ) y el código del programa.
17. Estructura de ROP
<basura para llenar el buffer y variables>
<return address: direccion de system()>
<proximo return address (de system()):
usualmente mas basura>
<argumento 1 para system(): puntero al
command string>
<command string>
18. Deep in ROP
Las cosas se ponen más complicadas cuando
empezamos a trabajar con ARM y x86-64, ya
que los argumentos se pasan en los registros,
pero aun así es posible.
TIP: Estamos en assembler así que podemos
saltar en el medio de una funcion si queremos!
19. ASLR: Address Space Layout Rand..
Para mitigar ROP apareció ASLR donde se
randomiza el stack, heap y librerías
dinámicas.
Ahora ya no se puede saltar porque todas las
direcciones cambian en cada ejecución.
Suena genial no? La solución definitiva.. ?
20. Un poco de ASLR
Bueno existen problemas.. Para empezar la
sección .text no es randomizada. En Linux se
puede saltar a cualquier función de la lib C
utilizada por el programa mediante la PLT (
Procedure Link Table )
PLT es una tabla que mapea justamente.
21. Deep in ASLR
Ya no suena tan genial no? Bueno hay mas.
Brute force: El page size en x86-32 es de 4kb,
los 12 bits de una direccion de memoria. Otros
8 bits son reservados para regiones especiales.
Son solo 4096 posibilidades.. No tan ASLR no?
22. Pero hay mas y llego Stack Guard
Canarios, en una mina de carbón se usaban
para saber si el nivel de monóxido de carbono
era habitable. Esta defensa usa el mismo
principio dejando un valor random o null antes
del return address.
Si el canario se modificó.. laejecución para.
23. Estructura de buffer con canario
<256 char de un buffer explotable>
<variables locales>
<valor de canario>
<return address>
<función argumentada 1>
<función argumentada 2>
24. Creo que he visto a un lindo gatito..
Para evitar al canario tenemos que salvarlo,
no se lo tiremos al gato! Ejemplo:
<char buffer[256]>
<char *src>
<canario>
<return address>
<char *dest>
25. Deep in Stack Guard
Con esa estructura se podria modificar SRC y
DST durante el overflow. Lo que se debería
hacer es restaurar el valor del canario.
Apuntar &[dest] al address del canario y luego
restaurarlo, por ejemplo: dest[255] = ‘0′
26. Y que se viene?
Durante 1990s y 2000s se conectaron a
internet por primera vez las PCs y el furor de
los overflows exploto!
Ya nada era seguro, cualquier desarrollador en
manos de un 0day podía ser potencialmente
muy peligroso! Y divertirse mucho.. ;)
27. Enserio, cual es el futuro?
Los dispositivos embebidos, cameras Go Pro!,
routers, autos, heladeras, dispositivo de
conexión remota (IPMI).
Pero si existen lenguajes como D, Go, Rust,
etc? Cual es el problema entonces..
28. La cultura.
El desarrollo ágil, la velocidad de entrega y el
desconocimiento son las principales causas.
No existe un paso a paso, se debe capacitar al
personal, tomar medidas y analizar.
Esto se traduce en costos.. Billetera mata.. ?