Desbordamiento de búfer (o desbordamiento de búfer), en Ciencias de la computación, es una condición de error que ocurre en tiempo de ejecución cuando se escriben datos más grandes en un búfer de un tamaño determinado.
Los desbordamientos de búfer eran conocidos, y fueron parcialmente documentados al público en 1972, cuando el estudio de planificación de tecnología de seguridad informática identificó un exploit que es capaz de explotar la vulnerabilidad: "el código que realiza esta función no verifica las direcciones de origen y destino correctamente, permitiendo que partes del monitor sean superpuestas por el usuario. Esto se puede utilizar para inyectar código en el monitor que permitirá al usuario tomar el control de la máquina." , donde por monitor se entendía lo que es hoy el núcleo. El primer ejemplo llamativo de un ataque de desbordamiento de búfer fue el gusano Morris (también conocido como el gusano de Internet), que en 1988 resultó en más de 6 accidentes. 000 sistemas conectados a Internet en unas pocas horas, aprovechando el desbordamiento de búfer en el proceso del demonio finger de UNIX para propagarse a través de la red. Más tarde, en 1995, Thomas Lopatic publicó en la lista de correo Bugtraq un exploit basado en el stack smashing en el servidor web, NCSA HTTPD, en el sistema operativo HP - UX, y un año más tarde, en 1996, Elias Levy (también conocido como Aleph One) publicó un artículo titulado "Smashing the Stack for Fun and Profit" en el ezine Phrack, una guía, una guía paso a paso para las técnicas de explotación de desbordamientos de búfer de pila. Más tarde, los desbordamientos de búfer fueron explotados por dos gusanos principales de internet: en 2001, el gusano Code Red, que explotó los desbordamientos de búfer en los servidores de Microsoft Internet Information Services (IIs) 5. 0, y en 2003 el gusano SQL Slammer, que comprometía las máquinas que ejecutaban Microsoft SQL Server 2000. A pesar de ser una de las vulnerabilidades conocidas durante más tiempo, todavía hoy, el desbordamiento de búfer es un defecto de seguridad generalizado y extremadamente actual: organizaciones como CERT/CC y SANS todavía publican alertas relacionadas con la seguridad cibernética, incluyendo un gran número de exploits basados en desbordamientos de búfer; además, varios elementos de la lista "CWE/SANS Top 25 error de Software más peligroso" son variantes del desbordamiento de búfer. Esta biblioteca es utilizada por cientos de aplicaciones, y la mayoría de las distribuciones de Linux (incluidas las instaladas en los routers y otros hardware): la función afectada es la que se encarga de la búsqueda DNS (resolución de nombres de host y direcciones IP) y la vulnerabilidad puede permitir que un atacante envíe dominios o servidor DNS sea malicioso, sobre el cual ataca el ataque man - in - the - middle hasta que ejecute el código arbitraria en el coche de la víctima En febrero de 2016, investigadores de Google y Red Hat descubrieron una vulnerabilidad de desbordamiento de búfer de pila en la función getaddrinfo de la biblioteca glibc (todas las versiones desde 2). 9).
Cuando, por error o malicia, se envían más datos de la capacidad del búfer asignado para mantenerlos a todos (que error, malicia, o superficialidad no está diseñado correctamente), los datos adicionales se sobrescribirá las variables internas del programa, o la misma pila; como resultado de esto, dependiendo de lo que se ha sobrescrito y con tales valores, el programa puede resultar en resultados incorrectos o imprevisibles, dejar de responder, o (si es un controlador o el mismo sistema operativo) bloquear el ordenador Para el lenguaje de bajo nivel, como el ensamblado, los datos son una simple matriz de bytes, almacenados en un registro o en memoria: la interpretación correcta de estos datos (direcciones, enteros, caracteres, instrucciones, etc.)...) se confía a las funciones e instrucciones que les permiten acceder y manipular; utilizando un lenguaje de bajo nivel por lo tanto tiene un mayor control de los recursos de la máquina, pero que necesitan más atención en fase de programación para garantizar la integridad de los datos (y así evitar fenómenos como desbordamiento de búfer) Conociendo muy bien el programa en cuestión, el sistema operativo y el tipo de equipo en el que se ejecuta, podemos precalcular un conjunto de datos como maliciosos que se envían para provocar un desbordamiento de búfer permite a un atacante tomar el control del programa (y a veces, a través de este, de todo el equipo). No todos los programas son vulnerables a este tipo de inconvenientes. Entre estos dos extremos está el lenguaje C, que tiene algunas de las abstracciones típicas de los lenguajes de alto nivel con elementos típicos del lenguaje de bajo nivel, como la capacidad de acceder y manipular direcciones de memoria: Esto hace que el lenguaje sea menos susceptible al mal uso de la memoria; si consideramos el hecho de que algunas bibliotecas de funciones que son muy comunes (especialmente cadenas como gets) no llevan a cabo un control adecuado del tamaño del búfer sobre el que trabajan, y que la C se utilizó en los años 70 para escribir el sistema operativo UNIX (y de esto se derivan sistemas como Linux y muchas aplicaciones que están diseñadas para realizar en él, se deduce que todavía está presente y circula una gran cantidad de código que es vulnerable al desbordamiento de búfer Los lenguajes del nivel más alto, como Java y Python (y muchos otros), que definen el concepto del tipo de una variable, y definen un conjunto de operaciones permitidas en función del tipo, no sufren de vulnerabilidades como el desbordamiento de búfer, ya que no le permite almacenar en un búfer más datos que su tamaño. No todos los programas son vulnerables a este tipo de inconvenientes, de hecho para que un programa determinado esté en riesgo es necesario que:.
Cuando esto sucede, parte del área de memoria inmediatamente adyacente al búfer en cuestión se sobrescribe, con diferentes efectos posibles dependiendo de dónde se encuentre el búfer y cómo se organice la memoria en esa plataforma de software en particular; en algunos programas de software Esto causa vulnerabilidades de seguridad. Los lenguajes gestionados, es decir, basados en un modelo de tiempo de ejecución gestionado por memoria como Java, deberían en teoría ser inmunes a este tipo de error, pero en la práctica, la posibilidad permanece presente en el caso de llamadas a código nativo, o debido a un bug en el compilador module manager (el JVM en el caso de Java) o JIT. El búfer de desbordamiento puede recibir diferentes nombres dependiendo de la posición ocupada por el búfer dentro de la memoria asignada para el proceso. La posición del búfer es importante ya que los efectos del desbordamiento del búfer están relacionados principalmente con: .
Este espacio de almacenamiento en general tiene una estructura dada por (de arriba a abajo): la ejecución del programa, a su vez, consta de varias llamadas a funciones, cada llamada genera un marco de pila dentro de la pila (que a medida que crece hacia la parte inferior de la estructura descrita anteriormente, con la política LIFO); dentro del marco de la llamada a la función, almacena las variables locales, la dirección la función que llama debe devolver el control (dirección de retorno) y el puntero al marco de la función que llama; estos dos últimos, en particular, juegan un papel fundamental para garantizar el flujo adecuado de ejecución del programa entre una llamada a la función y la otra, de hecho: la pila crece hacia abajo para cada llamada de la función, y cada marco se genera por lo que tiene una estructura del tipo (siempre desde la parte superior low): cuando el búfer se asigna en la pila, es decir, es una variable local de una función, la posible entrada en el búfer de una cantidad de datos mayor que su ámbito se denomina Stack buffer overflow (o stack smashing, o stack-based buffer overflow) Si los datos están en exceso sobrescribir el puntero de marco y la dirección de retorno, después de ejecutar la función intentará devolver el control a la instrucción apuntada por la dirección de retorno puede contener: en este segundo caso incluye los ataques se basan en la inyección de shellcode; los datos almacenados dentro del búfer contienen código ejecutable en lenguaje máquina (ensamblaje), y la sobreescritura forma de referirse al código inyectado dentro del búfer Cuando se ejecuta un programa, el sistema operativo normalmente genera un nuevo proceso y asigna un espacio de memoria virtual reservado para el proceso en la memoria central. En este caso, los datos adyacentes al búfer que podrían ser sobrescritos por los datos adicionales son la dirección de retorno y el puntero del marco. La tarea de este código es normalmente invocar una interfaz de línea de comandos, o shell, por lo que dicho código se llama shellcode (una llamada a la función execve que está ejecutando el shell de Bourne para sistemas UNIX, una llamada al sistema (" command ") . exe ") en sistemas Windows). En cualquier caso, el programa en ejecución es reemplazado por el shell, que se ejecutará con los mismos privilegios que el programa de inicio. El ataque consiste en explotar el desbordamiento para reemplazar el puntero de Marco almacenado para apuntarlo a una pila de Marco falsa, inyectada en el búfer junto con el shellcode; en esta pila de Marco falso el atacante ha insertado como dirección de retorno un puntero al shellcode: cuando la función afectada finaliza su ejecución, entonces, devuelve correctamente el control a la de hecho no se ha cambiado), pero esto reanudará la ejecución con un contexto falso y, cuando a su vez también termine de ejecutarse, el control finalmente se transferirá al shellcode (ya que en este marco de pila el RA se ha alterado para apuntar al código malicioso) Attacks off-by-one se basa en este principio: si un error de escritura, el programador permite la entrada al búfer interno, incluso si solo un byte más de lo que debería (por ejemplo, mediante el uso de un < = en lugar de < en la prueba de una condición de control), este simple bytes puede ser utilizado por un atacante para cambiar el puntero de marco se almacena lo suficiente para apuntar a una pila frame, y así obtener indirectamente la transferencia de control al código malicioso inyectado Hay una variante de este tipo de ataque que se basa en reemplazar solo el puntero de marco, y que se puede utilizar cuando el desbordamiento permitido es limitado y no permite llegar a la sobrescritura de la dirección de retorno. Por último, debemos recordar que Stack overflow y Stack buffer overflow no son sinónimos: el primero indica una situación que requiere demasiada memoria en la pila, el segundo una situación en la que (por varias razones) se inserta en un búfer en la pila, una cantidad de datos mayor que la capacidad del propio búfer. Un programa puede requerir que el sistema operativo asigne dinámicamente una cierta cantidad de memoria en el área del montón, aprovechando llamadas al sistema como malloc () y free () en C/UNIX. Estos búferes también pueden ser susceptibles a problemas de desbordamiento cuando se pueden insertar más datos que la memoria asignada, y estos datos como de costumbre sobrescribirían las áreas de memoria adyacentes al búfer. Se habla en estos casos de desbordamiento de montón, pero a diferencia de la pila, en el área de montón no se almacenan ni direcciones de retorno, ni marcos de puntero que pueden ser alterados por un atacante para transferir el control de ejecución a código arbitrario. Sin embargo, esto no significa que estas anomalías no constituyan vulnerabilidades peligrosas: en 2002 se encontró una vulnerabilidad de desbordamiento de montón en una extensión de Microsoft IIS que podría ser explotada para ejecutar código arbitrario en este tipo de servidor. Cuando un programa tiene varias funciones que realizan la misma tarea pero de una manera diferente (por ejemplo, ordenar), y desea determinar en tiempo de ejecución cuál usar para procesar los datos de entrada, a menudo utilizados para almacenar punteros de función en el área del montón: estos punteros que contienen las direcciones de inicio de las funciones, y se utilizan para invocar la ejecución posterior. En tal escenario, un atacante podría aprovechar el desbordamiento de búfer asignado en el montón para sobrescribir estos punteros, reemplazándolo con un puntero a la shellcode se inyecta a través del desbordamiento: la siguiente llamada a una función implicaría la transferencia de control a la shellcode en lugar de la función de retención.
Hay varias técnicas para prevenir o revelar el fenómeno de desbordamiento de búfer, con varias compensaciones. En general, estas defensas se pueden tomar en varios niveles: la mejor defensa contra ataques basados en desbordamiento de búfer está en la elección de un lenguaje de programación que proporcione controles automáticos sobre el tamaño del búfer (o en tiempo de compilación o ejecución), como Java, Python o Perl. Si bien esta opción puede considerarse para el desarrollo de nuevos programas, sigue siendo difícil aplicarla en el caso de los proyectos existentes, donde esto implicaría reescribir el código en el nuevo lenguaje. Una alternativa es usar bibliotecas seguras, es decir, bibliotecas de funciones que implementan protecciones de desbordamiento de búfer: en C representan funciones vulnerables strcat, strcpy, gets, sprintf (y más. .) de los cuales hay contrapartes "seguras" como strncpy, strncat, snprintf. Un ejemplo de estas bibliotecas seguras son "libsafe" , "libparanoia" y "libverify" . Libsafe, por ejemplo, implementa una técnica de protección de pila de desbordamiento de búfer basada en la comprobación de cualquier cambio en la pila cuando una función termina de ejecutarse: si se cambia la pila, el proceso termina con un error de segmentación. Hay herramientas que pueden detectar vulnerabilidades al desbordamiento de búfer dentro del código fuente realizando análisis más o menos complejos sobre él, tanto estáticos como dinámicos. "Its4" es un ejemplo muy sencillo de analizador estático que hace que la búsqueda de cualquier llamada a funciones con notas vulnerables (como strcpy o popen), pensado como un reemplazo a la búsqueda utilizando grep : fecha de su simplicidad y el análisis rudimentario del código que lo implementa es muy fácil de ejecutar en falsos positivos y negativos. Alternativamente, existen herramientas más complejas que pueden realizar el análisis dinámico del programa, como "Rational Purify" , un depurador de memoria hecho por IBM que puede detectar cualquier anomalía en la gestión de memoria durante la ejecución del programa (acceso a variables no inicializadas, desbordamiento de búfer, desasignación inadecuada de memoria, etc.).). Los lenguajes de nivel medio / inferior como C proporcionan un alto rendimiento precisamente porque "guardan" algunos controles que no se manejan automáticamente a nivel de lenguaje, dejando esta responsabilidad al programador, y lanzando así las bases de las vulnerabilidades, como el desbordamiento de búfer en caso de falta de controles sobre el tamaño del búfer durante los accesos. El enfoque diferente es "StackShield" , una extensión del compilador gcc para la protección de la rotura de la pila en sistemas Linux; en lugar de insertar en tiempo de compilación comprobaciones para la comprobación de límites del búfer, el objetivo de StackShield es evitar la sobreescritura de la dirección de retorno después de una copia en un área segura, no una escritura Una vez (al principio del segmento de datos) al comienzo de cada llamada función, la copia que luego se compara con el final de la ejecución de la función con el valor almacenado en la pila: si los valores no coinciden, el StackShield puede terminar la ejecución del programa o intentar continuar ignorando el ataque y arriesgándose a que se bloquee un máximo del programa Una de las técnicas de defensa de estas anomalías es predecir que el compilador insertará las comprobaciones sobre el tamaño del búfer en el código compilado sin requerir ningún cambio en el código fuente, pero solo al compilador, sin embargo a expensas de los tiempos que pueden aumentar más del 200%. Esta fue la dirección emprendida por dos diferentes proyectos de parches para el compilador GCC escrito por Herman ten Brugge y Greg McGary. Otra extensión del compilador GCC, "StackGuard" , permite tanto la detección de cualquier desbordamiento de búfer de pila como la prevención de ellos: la primera defensa, sin embargo, es mucho más eficiente y portátil que la segunda, generalmente menos confiable y segura. La revelación se basa en la escritura en el marco de pila de una palabra Canaria entre las variables locales y la dirección de retorno almacenada en el supuesto de que no es posible sobrescribir la RA sin alterar la palabra Canaria, que luego toma su nombre, en analogía con el uso de Canarias en las minas de carbón como el primer sistema de alarma. Antes de devolver el control a la declaración señalada por el RA, comprobamos si la palabra Canaria ha sufrido cambios: cualquier cambio se considera como un intento potencial de alterar el control de la ejecución del programa y, por lo tanto, atacar. La técnica adoptada por StackGuard solo es efectiva si el atacante no es capaz de predecir la palabra Canaria, en este caso, de hecho, sería capaz de diseñar el desbordamiento para sobrescribir la palabra Canaria con su valor original: StackGuard para este propósito, ejecute la aleatorización del canario. Muchos sistemas operativos han intentado abordar el problema del desbordamiento de búfer imponiendo restricciones al uso de memoria y, por lo tanto, haciendo que los ataques sean más complejos. Un amplio mecanismo de defensa a nivel de sistema operativo se basa en hacer que ciertas páginas de memoria, como las que contienen pilas y montones, no sean ejecutables: cualquier intento de transferir el control de ejecución al código dentro de estas áreas genera una excepción, evitando que se ejecuten. Esto se puede lograr mediante la explotación de ciertas características de hardware de los procesadores conocidos como bits "NX" (" no ejecutar ") o bits "XD" (" ejecutar desactivado ") , o mediante técnicas de software que emulan esta operación. Otra técnica de defensa a nivel del sistema operativo es la '' address space layout randomization (ASLR), que consiste en hacer aleatorizar parcialmente la dirección de las funciones de la biblioteca y de las áreas de memoria las más importantes; Esto hace que sea más difícil (pero no imposible) ejecutar el código a través de exploits, ya que obliga al atacante a buscar la dirección del código para ejecutar a través de una serie de intentos detectables tanto por víctima, ya sea de cualquier protección SW Algunos sistemas operativos basados en UNIX como OpenBSD y OS X soportan directamente la protección del espacio ejecutable, para otros sistemas operativos está disponible a través de extensiones opcionales como: las versiones más recientes de Microsoft Windows lo soportan bajo el nombre Data Execution Prevention (DEP) (o program execution protection).
Hackers venezolanos