Articulo de referencia

Protección contra desbordamiento de búfer

La protección contra desbordamientos de búfer es un conjunto de técnicas utilizadas durante el desarrollo de software para mejorar la seguridad de los programas ejecutables, det...

La protección contra desbordamientos de búfer es un conjunto de técnicas utilizadas durante el desarrollo de software para mejorar la seguridad de los programas ejecutables, detectando desbordamientos de búfer en variables asignadas en la pila y evitando que provoquen un comportamiento erróneo del programa o se conviertan en graves vulnerabilidades de seguridad . Un desbordamiento de búfer en la pila ocurre cuando un programa escribe en una dirección de memoria de la pila de llamadas fuera de la estructura de datos prevista, que suele ser un búfer de longitud fija. Los errores de desbordamiento de búfer en la pila se producen cuando un programa escribe más datos en un búfer de la pila de los que están asignados para dicho búfer. Esto casi siempre provoca la corrupción de datos adyacentes en la pila, lo que podría causar fallos en el programa, un funcionamiento incorrecto o problemas de seguridad.

Normalmente, la protección contra desbordamiento de búfer modifica la organización de los datos asignados en la pila para incluir un valor de alerta que, al ser destruido por un desbordamiento de búfer en la pila, indica que un búfer anterior en la memoria se ha desbordado. Al verificar este valor, se puede terminar la ejecución del programa afectado, evitando así que se comporte de forma incorrecta o que un atacante tome el control del mismo. Otras técnicas de protección contra desbordamiento de búfer incluyen la comprobación de límites , que verifica los accesos a cada bloque de memoria asignado para que no puedan exceder el espacio asignado, y el etiquetado , que garantiza que la memoria asignada para almacenar datos no pueda contener código ejecutable.

Es más probable que el desbordamiento de un búfer asignado en la pila afecte la ejecución del programa que el desbordamiento de un búfer en el montón , ya que la pila contiene las direcciones de retorno de todas las llamadas a funciones activas. Sin embargo, también existen protecciones similares, específicas de la implementación, contra los desbordamientos basados ​​en el montón.

Existen varias implementaciones de protección contra desbordamiento de búfer, incluidas las de GNU Compiler Collection , LLVM , Microsoft Visual Studio y otros compiladores.

Descripción general

Un desbordamiento de búfer de pila ocurre cuando un programa escribe en una dirección de memoria de la pila de llamadas fuera de la estructura de datos prevista, que suele ser un búfer de longitud fija. Los errores de desbordamiento de búfer de pila se producen cuando un programa escribe más datos en un búfer ubicado en la pila de los que realmente están asignados para ese búfer. Esto casi siempre provoca la corrupción de datos adyacentes en la pila y, en los casos en que el desbordamiento se activa por error, a menudo provoca que el programa falle o funcione incorrectamente. El desbordamiento de búfer de pila es un tipo de fallo de programación más general conocido como desbordamiento de búfer (o sobrecarga de búfer). Es más probable que sobrellenar un búfer en la pila descarrile la ejecución del programa que sobrellenar un búfer en el montón, porque la pila contiene las direcciones de retorno de todas las llamadas a funciones activas. [ 1 ]

El desbordamiento del búfer de pila puede provocarse deliberadamente como parte de un ataque conocido como " stack smashing" . Si el programa afectado se ejecuta con privilegios especiales o si acepta datos de hosts de red no confiables (por ejemplo, un servidor web público ), entonces el error constituye una vulnerabilidad de seguridad potencial que permite a un atacante inyectar código ejecutable en el programa en ejecución y tomar el control del proceso. Este es uno de los métodos más antiguos y fiables que utilizan los atacantes para obtener acceso no autorizado a un ordenador. [ 2 ]

Por lo general, la protección contra desbordamiento de búfer modifica la organización de los datos en el marco de pila de una llamada a función para incluir un valor "canario" que, al ser destruido, indica que se ha producido un desbordamiento del búfer que lo precede en la memoria. Esto ofrece la ventaja de prevenir toda una clase de ataques. Según algunos investigadores, [ 3 ] el impacto de estas técnicas en el rendimiento es insignificante.

La protección contra ataques de desbordamiento de pila no puede proteger contra ciertas formas de ataque. Por ejemplo, no puede proteger contra desbordamientos de búfer en el montón. No existe una forma sensata de alterar la disposición de los datos dentro de una estructura ; se espera que las estructuras sean idénticas entre módulos, especialmente con bibliotecas compartidas. Es imposible proteger con canaries cualquier dato dentro de una estructura que se encuentre después de un búfer; por lo tanto, los programadores deben tener mucho cuidado con la forma en que organizan sus variables y utilizan sus estructuras.

Canarios

Los valores de alerta ( o "canarios ", también conocidos como palabras de alerta o cookies de pila) se colocan entre un búfer y los datos de control en la pila para monitorizar los desbordamientos del búfer. Cuando se produce un desbordamiento, los primeros datos que suelen corromperse son los de alerta, y una verificación fallida de estos datos alertará sobre el desbordamiento, que puede gestionarse, por ejemplo, invalidando los datos corruptos. Un valor de alerta no debe confundirse con un valor centinela .

La terminología hace referencia a la práctica histórica de usar canarios en las minas de carbón , ya que estos se veían afectados por los gases tóxicos antes que los mineros, proporcionando así un sistema de alerta biológica. Los canarios también se conocen como " galletas de pila ", término que evoca la imagen de una "galleta rota" cuando su valor está corrompido.

Existen tres tipos de canarios en uso: terminador , aleatorio y XOR aleatorio . Las versiones actuales de StackGuard admiten los tres, mientras que ProPolice admite canarios terminador y aleatorio .

Canarios Terminator

Los canarios de terminación se basan en la observación de que la mayoría de los ataques de desbordamiento de búfer se fundamentan en ciertas operaciones de cadena que terminan en terminadores de cadena. La respuesta a esta observación es que los canarios se construyen con terminadores nulos , CR , LF y FF . Como resultado, el atacante debe escribir un carácter nulo antes de escribir la dirección de retorno para evitar alterar el canario. Esto previene ataques que utilizan strcpy()otros métodos que devuelven un valor al copiar un carácter nulo, aunque el resultado indeseado es que el canario es conocido. Incluso con esta protección, un atacante podría potencialmente sobrescribir el canario con su valor conocido e información de control con valores que no coinciden, eludiendo así el código de verificación del canario, que se ejecuta poco antes de la instrucción de retorno de llamada del procesador específico.

canarios aleatorios

Los valores aleatorios de tipo canario se generan aleatoriamente, generalmente mediante un demonio que recopila entropía , para evitar que un atacante conozca su valor. Normalmente, no es lógicamente posible ni plausible leer el valor del canario para explotarlo; se trata de un valor seguro conocido únicamente por quienes necesitan conocerlo : en este caso, el código de protección contra desbordamiento de búfer.

Normalmente, se genera un canario aleatorio al inicializar el programa y se almacena en una variable global . Esta variable suele rellenarse con páginas no mapeadas, de modo que cualquier intento de leerla mediante técnicas que exploten vulnerabilidades para acceder a la RAM provoca un fallo de segmentación y la finalización del programa. Aun así, podría ser posible leer el canario si el atacante conoce su ubicación o consigue que el programa lea desde la pila.

Canarios XOR aleatorios

Los valores aleatorios XOR son valores aleatorios que se modifican mediante la operación XOR utilizando la totalidad o parte de los datos de control. De esta forma, si el valor o los datos de control se ven alterados, el valor resultante es incorrecto.

Los canarios XOR aleatorios presentan las mismas vulnerabilidades que los canarios aleatorios, con la diferencia de que el método de "lectura de la pila" para obtener el canario es algo más complejo. El atacante debe obtener el canario, el algoritmo y los datos de control para regenerar el canario original necesario para burlar la protección.

Además, los canarios XOR aleatorios pueden proteger contra un tipo específico de ataque que consiste en desbordar un búfer en una estructura hacia un puntero para modificarlo y que apunte a un dato de control. Debido a la codificación XOR, el canario fallará si se modifican los datos de control o el valor de retorno. Gracias al puntero, los datos de control o el valor de retorno pueden modificarse sin desbordar el canario.

Si bien estos mecanismos de seguridad protegen los datos de control para que no sean alterados por punteros modificados, no protegen ningún otro dato ni los propios punteros. Los punteros a funciones, en particular, representan un problema, ya que pueden desbordarse y ejecutar código malicioso al ser llamados.

Comprobación de límites

La comprobación de límites es una técnica basada en el compilador que añade información de límites en tiempo de ejecución para cada bloque de memoria asignado y compara todos los punteros con los límites en tiempo de ejecución. Para C y C++, la comprobación de límites puede realizarse en el momento del cálculo del puntero [ 4 ] o en el momento de la desreferenciación . [ 5 ] [ 6 ] [ 7 ]

Las implementaciones de este enfoque utilizan un repositorio central, que describe cada bloque de memoria asignado, [ 4 ] [ 5 ] [ 6 ] o punteros gordos , [ 7 ] que contienen tanto el puntero como datos adicionales, que describen la región a la que apuntan.

Etiquetado

El etiquetado [ 8 ] es una técnica basada en el compilador o en el hardware (que requiere una arquitectura etiquetada ) para etiquetar el tipo de un dato en memoria, utilizada principalmente para la verificación de tipos. Al marcar ciertas áreas de memoria como no ejecutables, se evita que la memoria asignada para almacenar datos contenga código ejecutable. Además, ciertas áreas de memoria pueden marcarse como no asignadas, lo que previene desbordamientos de búfer.

Históricamente, el etiquetado se ha utilizado para implementar lenguajes de programación de alto nivel; [ 9 ] con el soporte adecuado del sistema operativo , el etiquetado también puede utilizarse para detectar desbordamientos de búfer. [ 10 ] Un ejemplo es la función de hardware del bit NX , compatible con los procesadores Intel , AMD y ARM .

Implementaciones

Colección de compiladores GNU (GCC)

La protección contra el desbordamiento de pila fue implementada por primera vez por StackGuard en 1997 y publicada en el Simposio de Seguridad USENIX de 1998. [ 11 ] StackGuard se introdujo como un conjunto de parches para el backend Intel x86 de GCC 2.7. StackGuard se mantuvo para la distribución Immunix Linux desde 1998 hasta 2003, y se amplió con implementaciones para canarios de terminador, aleatorios y XOR aleatorios. Se sugirió la inclusión de StackGuard en GCC 3.x en las Actas de la Cumbre GCC 2003, [ 12 ] pero esto nunca se logró.

Entre 2001 y 2005, IBM desarrolló parches para GCC que protegían contra el desbordamiento de pila, conocidos como ProPolice . [ 13 ] Esta modificación mejoró la idea de StackGuard colocando búferes después de los punteros locales y los argumentos de las funciones en el marco de pila. Esto ayudó a evitar la corrupción de punteros, impidiendo el acceso a ubicaciones de memoria arbitrarias.

Los ingenieros de Red Hat identificaron problemas con ProPolice y, en 2005, reimplementaron la protección contra el desbordamiento de pila para su inclusión en GCC 4.1. [ 14 ] [ 15 ] Este trabajo introdujo la -fstack-protectorbandera, que protege solo algunas funciones vulnerables, y la -fstack-protector-allbandera, que protege todas las funciones, independientemente de si lo necesitan o no. [ 16 ]

En 2012, los ingenieros de Google implementaron la -fstack-protector-strongbandera para lograr un mejor equilibrio entre seguridad y rendimiento. [ 17 ] Esta bandera protege más tipos de funciones vulnerables que -fstack-protector, pero no todas las funciones, proporcionando un mejor rendimiento que -fstack-protector-all. Está disponible en GCC desde su versión 4.9. [ 18 ]

Todos los paquetes de Fedora se compilan con -fstack-protectordesde Fedora Core 5 y -fstack-protector-strongdesde Fedora 20. [ 19 ] [ 20 ] La mayoría de los paquetes en Ubuntu se compilan con -fstack-protectordesde 6.10. [ 21 ] Todos los paquetes de Arch Linux se compilan con -fstack-protectordesde 2011. [ 22 ] Todos los paquetes de Arch Linux compilados desde el 4 de mayo de 2014 usan -fstack-protector-strong. [ 23 ] La protección de pila solo se usa para algunos paquetes en Debian , [ 24 ] y solo para el sistema base de FreeBSD desde 8.0. [ 25 ] La protección de pila es estándar en ciertos sistemas operativos, incluidos OpenBSD , [ 26 ] Hardened Gentoo [ 27 ] y DragonFly BSD .

StackGuard y ProPolice no pueden proteger contra desbordamientos en estructuras asignadas automáticamente que desbordan en punteros a funciones. ProPolice, al menos, reorganizará el orden de asignación para que dichas estructuras se asignen antes que los punteros a funciones. En PointGuard [ 28 ] se propuso un mecanismo independiente para la protección de punteros , disponible en Microsoft Windows [ 29 ] .

Microsoft Visual Studio

El conjunto de compiladores de Microsoft implementa la protección contra desbordamiento de búfer desde la versión 2003 a través del modificador de línea de comandos /GS , que está habilitado de forma predeterminada desde la versión 2005. [ 30 ] El uso de /GS- desactiva la protección.

Compilador IBM

La protección contra el desbordamiento de pila se puede activar mediante la bandera del compilador -qstackprotect. [ 31 ]

Clang/ LLVM

Clang admite las mismas -fstack-protectoropciones que GCC [ 32 ] y un sistema de "pila segura" más robusto ( -fsanitize=safe-stack ) con un impacto en el rendimiento igualmente bajo. [ 33 ] Clang también tiene tres detectores de desbordamiento de búfer, a saber, AddressSanitizer ( ), [ 6 ] UBSan ( ), [ 34 ] y el no oficial SafeCode (última actualización para LLVM 3.0). [ 35 ]-fsanitize=address-fsanitize=bounds

Estos sistemas presentan diferentes ventajas y desventajas en términos de penalización de rendimiento, sobrecarga de memoria y clases de errores detectados. La protección de pila es estándar en ciertos sistemas operativos, incluido OpenBSD . [ 36 ]

Compilador Intel

El compilador de C y C++ de Intel admite protección contra el desbordamiento de pila con opciones similares a las proporcionadas por GCC y Microsoft Visual Studio. [ 37 ]

A prueba de fallos C

Fail-Safe C [ 7 ] es un compilador ANSI C de código abierto con seguridad de memoria que realiza comprobaciones de límites basadas en punteros gordos y acceso a memoria orientado a objetos. [ 38 ]

StackGhost (basado en hardware)

Inventado por Mike Frantzen , StackGhost es una simple modificación de las rutinas de desbordamiento y llenado de la ventana de registros que dificulta enormemente la explotación de desbordamientos de búfer. Utiliza una característica de hardware única de la arquitectura SPARC de Sun Microsystems —desbordamiento y llenado de la ventana de registros diferido , en pila y dentro del marco— para detectar de forma transparente las modificaciones de los punteros de retorno (una forma común de que un exploit secuestre las rutas de ejecución), protegiendo automáticamente todas las aplicaciones sin necesidad de modificar sus archivos ejecutables o de código fuente. El impacto en el rendimiento es mínimo: menos del uno por ciento. Los problemas de gdb resultantes fueron resueltos por Mark Kettenis dos años después, lo que permitió habilitar la función. Tras este evento, el código de StackGhost se integró (y optimizó) en la versión SPARC del sistema operativo OpenBSD .

Véase también

Referencias

  1. Fithen, William L.; Seacord, Robert (27 de marzo de 2007). "VT-MB. Violación de los límites de la memoria" . US CERT .
  2. Levy, Elias (1996-11-08). "Destrozando la pila por diversión y beneficio" . Phrack . 7 (49): 14.
  3. "Desbordamientos de búfer: ataques y defensas para la vulnerabilidad de la década*" (PDF) . Archivado del original (PDF) el 9 de marzo de 2013.
  4. 1 2 "Comprobación de límites para C" . Doc.ic.ac.uk. Archivado del original el 26-03-2016 . Recuperado el 27-04-2014 .
  5. 1 2 "SAFECode: Arquitectura virtual segura" . Sva.cs.illinois.edu. 12 de agosto de 2009. Consultado el 27 de abril de 2014 .
  6. 1 2 3 "google/sanitizers" . 19 de junio de 2021.
  7. 1 2 3 "Fail-Safe C: Página principal" . Staff.aist.go.jp. 2013-05-07. Archivado del original el 2016-07-07 . Recuperado el 2014-04-27 .
  8. "Martes, 5 de abril de 2005" (PDF) . Feustel.us . Archivado del original (PDF) el 23 de junio de 2016. Consultado el 17 de septiembre de 2016 .
  9. Steenkiste, Peter; Hennessy, John (1987). "Etiquetas y comprobación de tipos en LISP: enfoques de hardware y software" . ACM SIGOPS Operating Systems Review . 21 (4). ACM: 50– 59. doi : 10.1145/36204.36183 .
  10. "Descripción general de la seguridad de ClearPath Enterprise Servers MCP" (PDF) . Public.support.unisys.com. Archivado del original (PDF) el 24/01/2013 . Consultado el 27/04/2014 .
  11. "Documentos - 7º Simposio de Seguridad de USENIX, 1998" . Usenix.org. 12 de abril de 2002. Consultado el 27 de abril de 2014 .
  12. "Actas de la Cumbre de Desarrolladores del GCC" (PDF) . Mayo de 2003. Archivado del original el 15 de julio de 2004. Consultado el 17 de septiembre de 2016 .{{cite web}}: CS1 maint: bot: estado de la URL original desconocido ( enlace )
  13. "Extensión de GCC para proteger las aplicaciones de ataques de desbordamiento de pila" . Research.ibm.com . Consultado el 27 de abril de 2014 .
  14. "Serie de lanzamientos de GCC 4.1: cambios, nuevas características y correcciones - Proyecto GNU - Fundación del Software Libre (FSF)" . Gcc.gnu.org . Consultado el 27 de abril de 2014 .
  15. "Richard Henderson - [ rfc ] reimplementación del protector de desbordamiento de pila de ibm" . Gcc.gnu.org . Consultado el 27 de abril de 2014 .
  16. "Optimizar opciones - Uso de la colección de compiladores GNU (GCC)" . Gcc.gnu.org . Consultado el 27 de abril de 2014 .
  17. "Han Shen(ææ) - [ PARCHE ] Agregar una nueva opción "-fstack-protector-strong" (parche / documentación dentro)" . Gcc.gnu.org. 2012-06-14 . Recuperado 2014-04-27 .
  18. Edge, Jake (5 de febrero de 2014) .Protección de pila "fuerte" para GCC . Linux Weekly News . Consultado el 28 de noviembre de 2014. Se ha incorporado a GCC 4.9.
  19. "Funciones de seguridad" . FedoraProject. 11 de diciembre de 2013. Consultado el 27 de abril de 2014 .
  20. "#1128 (cambio de "-fstack-protector" a "-fstack-protector-strong" en Fedora 20) – FESCo" . Fedorahosted.org . Consultado el 27 de abril de 2014 .
  21. "Seguridad/Características - Wiki de Ubuntu" . Wiki.ubuntu.com . Consultado el 27 de abril de 2014 .
  22. "FS#18864 : Considerar habilitar la protección contra desbordamiento de pila de GCC (ProPolice, SSP) para todos los paquetes" . Bugs.archlinux.org . Consultado el 27 de abril de 2014 . 
  23. "svntogit/packages.git - Clonación de Git del repositorio 'packages'" .{{cite web}}: CS1 maint: servicio de archivado obsoleto ( enlace )
  24. "Estadísticas de endurecimiento de seguridad de Debian" . Outflux.net. Archivado del original el 28 de abril de 2014. Consultado el 27 de abril de 2014 .
  25. "Notas de la versión FreeBSD 8.0-RELEASE" . Freebsd.org. 13 de noviembre de 2013. Consultado el 27 de abril de 2014 .
  26. "Página del manual gcc-local(1) de OpenBSD" . gcc viene con la extensión de protección de pila ProPolice , que está habilitada por defecto.
  27. "Hardened/Toolchain - Gentoo Wiki" . 31/07/2016. El GCC reforzado de Gentoo activa el protector de pila por defecto a menos que se solicite explícitamente lo contrario.
  28. "12º Simposio de Seguridad de USENIX — Documento Técnico" .
  29. "Blogs de MSDN: Obtenga la información, los análisis, los anuncios y las noticias más recientes de los expertos y desarrolladores de Microsoft en los blogs de MSDN" . 6 de agosto de 2021.
  30. "/GS (Buffer Security Check) (C++)" . msdn.microsoft.com . Consultado el 27 de abril de 2014 .
  31. "qstackprotect" . Publib.boulder.ibm.com . Consultado el 27 de abril de 2014 .
  32. "Lista de correo de Clang" . Clang.llvm.org. 28 de abril de 2017. Consultado el 16 de noviembre de 2022 .
  33. "SafeStack — Documentación de Clang 17.0.0git" . clang.llvm.org .
  34. "Manual del usuario del compilador Clang — Documentación de Clang 3.5" . Clang.llvm.org . Consultado el 27 de abril de 2014 .
  35. "SAFECode" . Safecode.cs.illinois.edu . Consultado el 27 de abril de 2014 .
  36. "Página del manual clang-local(1) de OpenBSD" . Clang viene con la protección de pila habilitada por defecto, equivalente a la opción -fstack-protector-strong en otros sistemas.
  37. "Guía del usuario y de referencia para el compilador Intel C++ 15.0: fstack-security-check, GS" . software.intel.com . Consultado el 13 de febrero de 2015 .
  38. "thesis.dvi" (PDF) . Staff.aist.go.jp . Consultado el 17 de septiembre de 2016 .
  • Actas de la Cumbre del CCG de 2003 (PDF)
  • Destrozando la pila por diversión y beneficio por Aleph One
  • Página oficial de ProPolice
  • Página principal de Immunix StackGuard
  • Artículo original de StackGuard en USENIX Security 1998
  • StackGhost: Protección de pila facilitada por hardware
  • Implementación de Propolice en FreeBSD 5.4 y 6.2
  • Cuatro trucos diferentes para eludir la protección de StackShield y StackGuard.
  • Protector contra destrucción de pilas