Una de las vulnerabilidades de seguridad más comunes y antiguas en el software son las vulnerabilidades de desbordamiento del buffer.
Las vulnerabilidades de desbordamiento del buffer se producen en todo tipo de software, desde sistemas operativos hasta aplicaciones cliente / servidor y software de escritorio. Esto sucede a menudo debido a una mala programación y la falta de validación de entrada o deficiente en el lado de la aplicación.
En este artículo veremos qué es exactamente un desbordamiento de buffer, cómo funcionan y cómo pueden convertirse en vulnerabilidades de seguridad graves. También veremos qué sucede cuando se produce un desbordamiento del buffer y las técnicas de mitigación para minimizar sus efectos nocivos.
Indice
¿Qué es un desbordamiento de buffer?
Un desbordamiento del buffer es una situación en la que un programa en ejecución intenta escribir datos fuera del buffer de memoria que no está destinado a almacenar estos datos. Cuando esto sucede, estamos hablando de un desbordamiento del buffer.
Un buffer de memoria es un área en la memoria de la computadora (RAM) destinada a almacenar datos temporalmente. Este tipo de buffers se puede encontrar en todos los programas y se utilizan para almacenar datos para entrada, salida y procesamiento.
Un ejemplo de datos almacenados en buffers son las credenciales de inicio de sesión o el nombre de host para un servidor FTP. Además, otros datos almacenados temporalmente antes del procesamiento pueden almacenarse en buffers. Esto literalmente podría ser cualquier cosa, desde campos de entrada del usuario, como los campos de nombre de usuario y contraseña, hasta los archivos de entrada utilizados para importar ciertos archivos de configuración.
Cuando la cantidad de datos escritos en el buffer excede la cantidad esperada de datos, el buffer de memoria se desborda.
Esto sucede, por ejemplo, cuando se espera un nombre de usuario con un máximo de 8 bytes y se da un nombre de usuario de 10 bytes y se escribe en el buffer. En este caso, el buffer se supera en 2 bytes y se producirá un desbordamiento cuando no se evite que ocurra. Esto sucede a menudo debido a una mala programación y la falta de desinfección de entrada.
Tipos
Hay varios ataques de desbordamiento de buffer diferentes que emplean diferentes estrategias y apuntan a diferentes piezas de código. A continuación se presentan algunos de los más conocidos.
- Ataque de desbordamiento de pila: este es el tipo más común de ataque de desbordamiento de buffer e implica desbordar un buffer en la pila de llamadas.
- Ataque de desbordamiento de montón: este tipo de ataque apunta a datos en el grupo de memoria abierta conocido como el montón.
- Desbordamiento de enteros: en un desbordamiento de enteros, una operación aritmética da como resultado un entero (número entero) que es demasiado grande para el tipo de entero destinado a almacenarlo. Esto puede provocar un desbordamiento del buffer.
- Desbordamiento Unicode: un desbordamiento Unicode crea un desbordamiento de buffer insertando caracteres Unicode en una entrada que espera caracteres ASCII. ASCII y Unicode son estándares de codificación que permiten que las computadoras representen texto. Por ejemplo, la letra ‘a’ está representada por el número 97 en ASCII. Mientras que los códigos ASCII solo cubren caracteres de idiomas occidentales, Unicode puede crear caracteres para casi todos los idiomas escritos en la tierra debido a que hay muchos más caracteres disponibles, muchos caracteres Unicode son más grandes que el carácter ASCII más grande.
Lenguajes de programación más vulnerables
Ciertos lenguajes de codificación son más susceptibles al desbordamiento del buffer que otros. C y C ++ son dos lenguajes populares con alta vulnerabilidad, ya que no contienen protecciones integradas contra el acceso o la sobrescritura de datos en su memoria. Windows, Mac OSX y Linux contienen código escrito en uno o en ambos idiomas.
Los lenguajes más modernos como Java, PERL y C # tienen características integradas que ayudan a reducir las posibilidades de desbordamiento del buffer, pero no pueden evitarlo por completo.
¿Qué sucede cuando se produce?
Cuando se produce un desbordamiento del buffer de memoria y los datos se escriben fuera del buffer, el programa en ejecución puede volverse inestable, bloquearse o devolver información corrupta.
Las partes sobrescritas de la memoria pueden haber contenido otros datos importantes para la aplicación en ejecución que ahora se sobrescribe y ya no está disponible para el programa. Los desbordamientos del buffer pueden incluso ejecutar otros programas o comandos (maliciosos) y provocar la ejecución de código arbitrario.
Ejecución de código arbitrario y escalada de privilegios
Cuando se utiliza una vulnerabilidad de desbordamiento de buffer para escribir datos maliciosos en la memoria y el atacante puede tomar el control del flujo de ejecución de un programa, estamos lidiando con una grave vulnerabilidad de seguridad.
Los desbordamientos del buffer pueden convertirse en serios problemas de seguridad. Los piratas informáticos pueden explotar estos problemas de seguridad para tomar el control (remoto) de un host, escalar privilegios o muchas cosas más malas como resultado de la ejecución de código arbitrario. La ejecución de código arbitrario es el proceso de inyectar código en el buffer y hacer que se ejecute.
La escalada de privilegios se realiza mediante la explotación de una vulnerabilidad de desbordamiento de buffer para ejecutar código arbitrario en un programa que se ejecuta con privilegios del sistema.
El código ejecutado puede ser shellcode que le da al atacante un shell de SO con privilegios administrativos, por ejemplo, o incluso agregar un nuevo usuario (administrador) al sistema.
También con desbordamientos de buffer, el código ejecutado ocurre en el contexto de la aplicación en ejecución. Esto significa que cuando la aplicación explotada se ejecuta con privilegios administrativos, el código malicioso también se ejecutará con privilegios administrativos.
Denegación de servicio (DoS)
No todas las vulnerabilidades de desbordamiento del buffer se pueden explotar para obtener la ejecución de código arbitrario.
También se pueden realizar ataques de denegación de servicio (remotos) cuando solo bloquean el programa en ejecución.
Como los desbordamientos del buffer pueden ocurrir vulnerabilidades en cualquier software, los ataques DoS no se limitan solo a los servicios y las computadoras. También se pueden seleccionar enrutadores, firewalls, dispositivos IoT y cualquier otra cosa que ejecute un sistema operativo.
Un ejemplo de esta situación es el reciente Cisco ASA IKEv1 e IKEv2 Buffer Overflow exploits. Algunos de estos exploits remotos solo se bloquean y fuerzan el reinicio del firewall, lo que genera un par de minutos de inactividad.
Cómo evitar un desbordamiento de buffer
Los desbordamientos de buffer en el software se pueden prevenir o mitigar de varias maneras.
La mitigación es el proceso de minimizar el impacto de una amenaza antes o después de que ocurra la amenaza. Esto es exactamente lo que debemos hacer cuando se trata de desbordamientos de buffer. Se puede evitar que sucedan antes de que ocurran (proactivo).
Pero, dado que los desbordamientos del buffer continúan ocurriendo, a pesar de las acciones proactivas para evitarlos, también necesitamos mecanismos para minimizar el impacto cuando ocurren (contramedidas reactivas).
Echemos un vistazo a cómo funciona la prevención y mitigación del desbordamiento del buffer.
Prevención
La solución mejor y más efectiva es evitar que ocurran condiciones de desbordamiento del buffer en el código.
Por ejemplo, cuando se espera un máximo de 8 bytes como datos de entrada, la cantidad de datos que se puede escribir en el buffer se limitará a 8 bytes en cualquier momento.
Además, los programadores deben usar las funciones de guardar, probar el código y corregir los errores en consecuencia. Los métodos proactivos para la prevención de desbordamiento del buffer como estos deben usarse siempre que sea posible para limitar las vulnerabilidades de desbordamiento del buffer.
Afortunadamente, los sistemas operativos modernos tienen protecciones de tiempo de ejecución que ayudan a mitigar los ataques de desbordamiento del buffer.
Exploremos 2 protecciones comunes que ayudan a mitigar el riesgo de explotación:
- Dirección espacio de aleatorización: Aleatoriamente reordena los lugares de espacio de direcciones de áreas de datos clave de un proceso. Los ataques de desbordamiento de buffer generalmente dependen de conocer la ubicación exacta del código ejecutable importante, la aleatorización de los espacios de direcciones lo hace casi imposible.
- Prevención de ejecución de datos: marca ciertas áreas de la memoria ejecutables o no ejecutables, evitando que un exploit ejecute el código encontrado en un área no ejecutable.
Los desarrolladores de software también pueden tomar precauciones contra las vulnerabilidades de desbordamiento del buffer escribiendo en idiomas que tengan protecciones incorporadas o utilizando procedimientos especiales de seguridad en su código.
A pesar de las precauciones, los desarrolladores continúan descubriendo nuevas vulnerabilidades de desbordamiento del buffer, a veces a raíz de una explotación exitosa. Cuando se descubren nuevas vulnerabilidades, los ingenieros deben parchear el software afectado y garantizar que los usuarios del software tengan acceso al parche.
Mitigación
Otra forma de proteger los desbordamientos del buffer es detectarlos a medida que ocurren y mitigar la situación. Este es un enfoque reactivo y se centra en minimizar el impacto nocivo.
Un ejemplo de mitigación efectiva es un sistema operativo moderno que protege ciertas áreas de la memoria contra escritura o ejecución. Esto evitará que un atacante escriba código arbitrario en la memoria cuando se produce un desbordamiento del buffer.
Las implementaciones como DEP, ASLR, SEHOP y el espacio ejecutable y la protección del puntero intentan minimizar el impacto negativo de un desbordamiento del buffer. Esto no evita que este se produzca, pero minimiza el impacto.
Otra forma de detección pasiva de desbordamiento del buffer es usar sistemas de detección de intrusos (IDS) para analizar el tráfico de red. Un IDS es capaz de detectar firmas en el tráfico de red que se sabe que explotan las vulnerabilidades de desbordamiento del buffer. El IDS puede mitigar el ataque y evitar que la carga útil se ejecute en el sistema de destino.
Conclusión
Los fallos por corrupción de memoria, al igual que otro tipo de debilidades, son causados por errores humanos que pueden existir en cualquier etapa del proceso de desarrollo de los sistemas
computacionales.
Es importante concienciar a los ingenieros de los requerimientos no funcionales y las buenas prácticas de programación que ayudan a disminuir el riesgo de experimentar vulnerabilidades en los sistemas. Al desarrollar las aplicaciones es importante tener en cuenta la primera línea de defensa.
El análisis de requerimientos de seguridad, las buenas prácticas de diseño e implementación y un adecuado control de calidad con un conjunto de pruebas adecuado, es fundamental para reducir el riesgo de experimentar este tipo de fallos.
Aunque este sistema de protección tendría que ser suficiente para evitar los ataques, es preferible realizar un enfoque de protección en distintas capas. Para ayudar a mitigar los riesgos, los sistemas operativos han incluido diferentes mecanismos de protección.
Dos de los mecanismos más representativos son:
- hacer aleatorio el espacio virtual de direcciones y
- los privilegios de ejecución en las regiones de memoria.
Sin embargo, estos mecanismos no evitan que la vulnerabilidad exista. Pero sí consiguen que sea más difícil el proceso de un atacante para aprovechar una vulnerabilidad.
Debemos saber que estos sistemas de protección no son perfectos y que los atacantes han creado técnicas para eludir su funcionamiento. Pero esto no significa que las medidas de protección sean inefectivas u obsoletas; simplemente, es una demostración de la teoría del riesgo residual.