¿Cuál es el principio básico del ataque de desbordamiento del búfer?
1. Concepto
Desbordamiento del búfer significa que cuando la computadora llena el búfer con bits de datos, los datos desbordados que exceden la capacidad del búfer se sobrescriben con datos legales. Idealmente, el programa verifica la longitud de los datos y no permite ingresar caracteres que excedan la longitud del búfer, pero la mayoría de los programas asumen que la longitud de los datos siempre coincide con el espacio de almacenamiento asignado, lo que deja un peligro oculto de desbordamiento del búfer. El búfer utilizado por el sistema operativo también se denomina "pila". Durante cada operación, las instrucciones se almacenan temporalmente en la "pila".
2. Daño
En la seguridad actual de redes y sistemas distribuidos, más del 50% se utilizan ampliamente en desbordamientos de búfer. El ejemplo más famoso es el uso de la vulnerabilidad fingerd en 1988. gusano. Entre los desbordamientos de búfer, el más peligroso es el desbordamiento de pila, porque un intruso puede utilizar el desbordamiento de pila para cambiar la dirección del programa de retorno cuando la función regresa, permitiéndole saltar a cualquier dirección. Un peligro es que un programa falle y provoque una denegación de servicio, y el otro es saltar para ejecutar un código malicioso, como obtener un shell, y luego hacer lo que quiera.
3. Ataque de búfer
1. Principio de desbordamiento del búfer
Al escribir contenido que excede su longitud en el búfer del programa, el búfer se desborda. destruyendo la pila del programa y haciendo que el programa ejecute otras instrucciones para lograr el propósito del ataque. La causa del desbordamiento del búfer es que los parámetros ingresados por el usuario no se verifican cuidadosamente en el programa. Por ejemplo, el siguiente programa:
voidfunction(char*str){
char buffer[16];
strcpy(buffer, str); p>
}
Strcpy() arriba copiará directamente el contenido de str al búfer. De esta manera, siempre que la longitud de str sea mayor que 16, provocará un desbordamiento del búfer y el programa se ejecutará incorrectamente. Las funciones estándar cuestionables como strcpy incluyen strcat(), sprintf(), vsprintf(), gets(), scanf(), etc.
Por supuesto, llenar casualmente el buffer hasta que se desborde generalmente solo conducirá a un "fallo de segmentación" y no logrará el propósito del ataque. El método más común es hacer que el programa ejecute un shell de usuario creando un desbordamiento del búfer y luego ejecutar otros comandos a través del shell. Si el programa pertenece a root y tiene permisos suid, entonces el atacante obtendrá un shell con permisos de root y podrá operar el sistema a voluntad.
La razón por la que los ataques de desbordamiento de búfer se han convertido en un método común de ataque a la seguridad es porque las vulnerabilidades de desbordamiento de búfer son demasiado comunes y fáciles de implementar. Y los desbordamientos de búfer se han convertido en el principal medio de ataques remotos, porque las vulnerabilidades de desbordamiento de búfer les dan a los atacantes todo lo que quieren: implantar y ejecutar código de ataque. El código de ataque implantado ejecuta un programa con una vulnerabilidad de desbordamiento del búfer con ciertos permisos, obteniendo así el control del host atacado.
En 1998, dos de los cinco ataques remotos utilizados por el Laboratorio Lincoln para evaluar la detección de intrusiones fueron desbordamientos del buffer. En 1998, 9 de las 13 recomendaciones del CERT estaban relacionadas con desbordamientos de las reservas, y en 1999, al menos la mitad estaban relacionadas con desbordamientos de las reservas. En una encuesta de Bugtraq, dos tercios de los encuestados consideraron que las vulnerabilidades de desbordamiento del buffer eran un problema de seguridad muy grave.
Las vulnerabilidades y los ataques de desbordamiento de búfer se presentan de muchas formas, que describiremos y clasificaremos en la Parte 2.
En consecuencia, los medios de defensa varían con los diferentes métodos de ataque, que se describirán en la Sección 4, que incluye medios de defensa eficaces para cada tipo de ataque.
2. Vulnerabilidades y ataques de desbordamiento de búfer
El propósito de los ataques de desbordamiento de búfer es interferir con las funciones de programas con ciertos permisos, permitiendo así que el atacante obtenga el control del programa. Si el programa tiene permisos suficientes, se controla todo el host. En términos generales, los atacantes atacan el programa raíz y luego ejecutan un código de ejecución similar a "exec(sh)" para obtener un shell con privilegios de raíz. Para lograr este objetivo, el atacante debe lograr los dos objetivos siguientes:
1. Organizar el código apropiado en el espacio de direcciones del programa.
2. A través de los registros de inicialización y la memoria adecuados, el programa salta al espacio de direcciones organizado por el intruso.
Los ataques de desbordamiento de búfer se clasifican en función de estos dos objetivos. En la Sección II.1, describimos cómo se coloca el código de ataque en el espacio de direcciones del programa atacado. En la Sección 2.2, presentaremos cómo un atacante puede desbordar el búfer de un programa y transferir la ejecución al código de ataque (de aquí proviene el "desbordamiento"). En la Sección II.3, se integrarán las técnicas de control de ejecución de programas y disposición del código discutidas en las dos secciones anteriores.
Dos. 1 Métodos para organizar el código apropiado en el espacio de direcciones del programa
Existen dos métodos para organizar el código de ataque en el espacio de direcciones del programa atacado:
Método de implantación:
El atacante ingresa una cadena en el programa atacado y el programa colocará la cadena en el búfer. Los datos contenidos en esta cadena son una secuencia de instrucciones que se pueden ejecutar en la plataforma de hardware comprometida. Aquí, el atacante utiliza el búfer del programa atacado para almacenar el código de ataque. Los buffers se pueden configurar en cualquier lugar: pila (variables automáticas), montón (área de memoria asignada dinámicamente) y área de datos estáticos.
2. Utilizar código existente:
A veces, el código que el atacante quiere ya está en el programa que está siendo atacado, y todo lo que el atacante tiene que hacer es pasarle algunos parámetros. . Por ejemplo, el código de ataque requiere la ejecución de "exec ("/bin/sh ")", y el código en la biblioteca libc ejecuta "exec(arg)", donde arg es un parámetro de puntero que apunta a una cadena, luego el El atacante solo necesita cambiar el puntero del parámetro entrante a "/bin/sh".
II.2 Métodos de transferencia del programa de control al código de ataque
Todos estos métodos buscan cambiar el proceso de ejecución del programa para que salte al código de ataque. El más básico es desbordar un buffer sin verificación de límites u otras debilidades, interrumpiendo el orden de ejecución normal del programa. Al desbordar el búfer, el atacante puede reescribir por fuerza bruta el espacio del programa adyacente y omitir directamente la verificación del sistema.
Los criterios de clasificación son los tipos de espacios de programa donde los atacantes buscan desbordamientos de búfer. En principio puede ser cualquier espacio. De hecho, muchos desbordamientos de búfer intentan cambiar el puntero del programa mediante métodos de fuerza bruta. La diferencia entre este tipo de programas radica en el avance del espacio del programa y el posicionamiento del espacio de memoria. Existen principalmente tres tipos: 1 y ActivationRecords:
Siempre que se produce una llamada a una función, la persona que llama dejará un registro de actividad en la pila, que contiene la dirección devuelta cuando finaliza la función. El atacante desborda las variables automáticas en la pila para que la dirección del remitente apunte al código de ataque. Al cambiar la dirección de retorno del programa, cuando finaliza la llamada a la función, el programa salta a la dirección establecida por el atacante en lugar de la dirección original. Este tipo de desbordamiento de búfer se denomina ataque de desbordamiento de pila y actualmente es el ataque de desbordamiento de búfer más utilizado.
2. Puntero de función:
El puntero de función se puede utilizar para localizar cualquier espacio de direcciones. Por ejemplo, "void(*foo)()" declara una variable de puntero de función foo y su valor de retorno es nulo. Por lo tanto, el atacante solo necesita encontrar un búfer de desbordamiento cerca del puntero de función en cualquier espacio y luego desbordar este búfer para cambiar el puntero de función. En algún momento, cuando el programa llama a una función a través de un puntero de función, el flujo del programa se realiza según lo previsto por el atacante. Un ejemplo de su ataque es el programa superprobe en sistemas Linux.
3.Longjmpbuffers:
El lenguaje C contiene un sistema simple de verificación/recuperación llamado setjmp/longjmp.
Significa configurar "setjmp(buffer)" en el punto de control y usar "longjmp(buffer)" para restaurar el punto de control. Sin embargo, si un atacante tiene acceso al espacio del búfer, entonces "longjmp(buffer)" es en realidad un salto al código del atacante. Al igual que los punteros de función, los buffers longjmp pueden apuntar a cualquier lugar, por lo que todo lo que un atacante tiene que hacer es encontrar un buffer desbordado. Un ejemplo típico es la vulnerabilidad de desbordamiento del búfer en Perl 5.003; el atacante primero ingresa al búfer longjmp utilizado para recuperar los desbordamientos del búfer y luego es inducido a ingresar al modo de recuperación, lo que hace que el intérprete de Perl salte al código de ataque.
2.3 Análisis completo de la implantación de código y la tecnología de control de procesos
El tipo más simple y común de ataque de desbordamiento de búfer es combinar la implantación de código y la tecnología de registro de actividad en una cadena. El atacante localiza una variable automática desbordada y luego pasa una cadena grande al programa, lo que provoca un desbordamiento del búfer y altera el registro de actividad mientras incrusta el código. Este es el modelo para el ataque que señala Levy. Debido a que C tradicionalmente solo abre un pequeño búfer para usuarios y parámetros, este tipo de ataque de vulnerabilidad es muy común.
La inyección de código y el desbordamiento del búfer no tienen que completarse en una sola acción. Un atacante puede colocar código en un búfer que no se puede desbordar. Luego, el atacante transfiere el puntero del programa desbordando otro búfer. Este método se utiliza generalmente para resolver la situación en la que el búfer disponible para el desbordamiento no es lo suficientemente grande (no cabe todo el código).
Si un atacante intenta utilizar un código ya residente, en lugar de implantar un código externo, normalmente tiene que llamar al código como parámetro. Por ejemplo, algunos segmentos de código en libc (necesarios para que casi todos los programas C se vinculen) ejecutarán "exec(algo)", donde algo es un parámetro. Luego, el atacante usa un desbordamiento de búfer para cambiar los parámetros del programa y luego usa otro desbordamiento de búfer para apuntar el puntero del programa a un segmento de código específico en libc.
En tercer lugar, análisis experimental de ataques de desbordamiento de búfer
En junio de 5438 + octubre de 2000, el equipo de seguridad de Cerberus lanzó una vulnerabilidad de desbordamiento de búfer en Microsoft IIS4/5. Explotar esta vulnerabilidad puede bloquear el servidor web o incluso obtener súper privilegios para ejecutar código arbitrario. Actualmente, IIS4/5 de Microsoft es el programa de servidor web principal. Por lo tanto, la vulnerabilidad de desbordamiento del búfer representa una gran amenaza para la seguridad del sitio web. Su descripción es la siguiente:
El navegador envía una solicitud HTTP a IIS y agrega un nombre de archivo después del nombre de dominio (o IP); dirección) y el archivo con "." en el nombre. htr" como sufijo. Por lo tanto, IIS cree que el cliente solicitó un ". El archivo "htr" y el archivo de extensión .htr están asignados a la aplicación ISAPI (InternetServiceAPI). IIS restablecerá todas las solicitudes de "". htr" al programa ISM.DLL, ISM.DLL abrirá este archivo y lo ejecutará.
El nombre del archivo contenido en la solicitud enviada por el navegador se almacena en el búfer de variables local. Si es así de largo, excederá los 600 caracteres, causará que el búfer de variables locales se desborde, sobrescriba el espacio de direcciones de retorno y cause que IIS falle. Además, se puede implantar un código bien diseñado en el búfer de 2K, como se muestra en la Figura 1, para haz que el sistema se ejecute con permiso.
4. Métodos preventivos contra ataques de desbordamiento de búfer
Los ataques de desbordamiento de búfer son la causa de la mayoría de los ataques remotos a la red, que permiten a los usuarios de Internet anónimos obtener ganancias. acceso al host. Si las vulnerabilidades de desbordamiento del búfer se pueden eliminar de manera efectiva, se puede mitigar una gran proporción de las amenazas a la seguridad.
Actualmente, existen cuatro métodos básicos para proteger los búfer de los ataques de desbordamiento del búfer. forzar la escritura de código correcto por parte del sistema operativo para hacer que los buffers no sean ejecutables, evitando así que los atacantes coloquen código de ataque, se presentan en el Capítulo 4.3. En el Capítulo 4.3, explicamos cómo usar la verificación de límites para proteger el buffer. Este método hace que el desbordamiento del búfer sea imposible, eliminando así por completo la amenaza de desbordamiento del búfer, pero el costo es relativamente alto. En 4.4, se introdujo un método indirecto antes de que se invalidara el puntero del programa.
Aunque este enfoque no solucionará todos los desbordamientos del búfer, sí evitará la mayoría de los ataques de desbordamiento del búfer. Luego, en IV.5, se analizan las ventajas de compatibilidad y rendimiento de este método de protección.
Cuatro. 1 Búfer no ejecutable
Al hacer que el espacio de direcciones del segmento de datos del programa atacado no sea ejecutable, es imposible que el atacante ejecute el código implantado en el búfer de entrada del programa atacado. Esta técnica se denomina almacenamiento en búfer de no ejecución. En el diseño inicial de los sistemas Unix, solo se permitía ejecutar código de programa en el segmento de código. Sin embargo, en los sistemas Unix y MSWindows recientes, para lograr un mejor rendimiento y funcionalidad, el código ejecutable a menudo se coloca dinámicamente en el segmento de datos, que también es la fuente del desbordamiento del búfer. Para mantener la compatibilidad del programa, es imposible hacer que el segmento de datos de todos los programas no sea ejecutable.
Sin embargo, el segmento de datos de la pila se puede configurar como no ejecutable, lo que puede garantizar la compatibilidad del programa. Tanto Linux como Solaris han lanzado parches para el kernel a este respecto. Debido a que casi ningún programa legal almacena código en la pila, este enfoque rara vez causa problemas de compatibilidad, excepto en dos casos especiales en Linux, donde el código ejecutable debe colocarse en la pila:
(1) Transmisión de señal:
Linux envía señales de Unix al proceso liberando el código en la pila del proceso y luego activando una interrupción para ejecutar el código en la pila. Un parche para buffers no ejecutables permite que el buffer sea ejecutable al enviar señales.
(2) Reutilización en línea 2) GCC:
Se descubrió que gcc coloca el código ejecutable en el área de la pila para su reutilización en línea. Sin embargo, desactivar esta función no causa ningún problema, sólo que algunas funciones no parecen funcionar.
La protección de la pila de no ejecución puede hacer frente eficazmente a ataques de desbordamiento de búfer que incrustan código en variables automáticas, pero no tiene ningún efecto sobre otras formas de ataques. Esta protección se puede eludir haciendo referencia a un puntero a un programa residente. Otros ataques pueden eludir la protección colocando código en el montón o en segmentos de datos estáticos.
IV.2 Escribir código correcto
Escribir código correcto es una tarea muy significativa, especialmente como escribir un programa de estilo libre y propenso a errores en lenguaje C. Es causado por el. tradición de perseguir el desempeño e ignorar la corrección. Aunque a la gente le llevó mucho tiempo descubrir cómo escribir programas seguros, todavía aparecían programas con vulnerabilidades de seguridad. Por lo tanto, se han desarrollado herramientas y técnicas para ayudar a los programadores sin experiencia a escribir programas seguros y correctos.
La forma más sencilla es utilizar grep para buscar en el código fuente llamadas a bibliotecas vulnerables, como llamadas a strcpy y sprintf, que no comprueban la longitud de los parámetros de entrada. De hecho, todas las versiones de la biblioteca estándar C tienen este problema.
Además, la gente también ha desarrollado algunas herramientas avanzadas de detección de errores, como la inyección de errores. El propósito de estas herramientas es descubrir vulnerabilidades de seguridad en el código generando de forma artificial y aleatoria algunos desbordamientos del búfer. También existen herramientas de análisis estático que pueden detectar la presencia de desbordamientos del búfer.
Aunque estas herramientas ayudan a los programadores a desarrollar programas más seguros, debido a las características del lenguaje C, es imposible que estas herramientas descubran todas las vulnerabilidades de desbordamiento del búfer. Por lo tanto, la tecnología de depuración sólo se puede utilizar para reducir la posibilidad de desbordamiento del búfer, pero no puede eliminar por completo su existencia.