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

Canaries or canary words or stack cookies are known values that are placed between a buffer and control data on the stack to monitor buffer overflows. When the buffer overflows, the first data to be corrupted will usually be the canary, and a failed verification of the canary data will therefore alert of an overflow, which can then be handled, for example, by invalidating the corrupted data. A canary value should not be confused with a sentinel value.

The terminology is a reference to the historic practice of using canaries in coal mines, since they would be affected by toxic gases earlier than the miners, thus providing a biological warning system. Canaries are alternately known as stack cookies, which is meant to evoke the image of a "broken cookie" when the value is corrupted.

There are three types of canaries in use: terminator, random, and random XOR. Current versions of StackGuard support all three, while ProPolice supports terminator and random canaries.

Terminator canaries

Terminator canaries use the observation that most buffer overflow attacks are based on certain string operations which end at string terminators. The reaction to this observation is that the canaries are built of null terminators, CR, LF, and FF. As a result, the attacker must write a null character before writing the return address to avoid altering the canary. This prevents attacks using strcpy() and other methods that return upon copying a null character, while the undesirable result is that the canary is known. Even with the protection, an attacker could potentially overwrite the canary with its known value and control information with mismatched values, thus passing the canary check code, which is executed soon before the specific processor's return-from-call instruction.

Random canaries

Random canaries are randomly generated, usually from an entropy-gathering daemon, in order to prevent an attacker from knowing their value. Usually, it is not logically possible or plausible to read the canary for exploiting; the canary is a secure value known only by those who need to know itthe buffer overflow protection code in this case.

Normally, a random canary is generated at program initialization, and stored in a global variable. This variable is usually padded by unmapped pages so that attempting to read it using any kinds of tricks that exploit bugs to read off RAM cause a segmentation fault, terminating the program. It may still be possible to read the canary if the attacker knows where it is or can get the program to read from the stack.

Random XOR canaries

Random XOR canaries are random canaries that are XOR-scrambled using all or part of the control data. In this way, once the canary or the control data is clobbered, the canary value is wrong.

Random XOR canaries have the same vulnerabilities as random canaries, except that the "read from stack" method of getting the canary is a bit more complicated. The attacker must get the canary, the algorithm, and the control data in order to re-generate the original canary needed to spoof the protection.

In addition, random XOR canaries can protect against a certain type of attack involving overflowing a buffer in a structure into a pointer to change the pointer to point at a piece of control data. Because of the XOR encoding, the canary will be wrong if the control data or return value is changed. Because of the pointer, the control data or return value can be changed without overflowing over the canary.

Although these canaries protect the control data from being altered by clobbered pointers, they do not protect any other data or the pointers themselves. Function pointers especially are a problem here, as they can be overflowed into and can execute shellcode when called.

Bounds checking

Bounds checking is a compiler-based technique that adds run-time bounds information for each allocated block of memory, and checks all pointers against those at run-time. For C and C++, bounds checking can be performed at pointer calculation time[4] or at dereference time.[5][6][7]

Implementations of this approach use either a central repository, which describes each allocated block of memory,[4][5][6] or fat pointers,[7] which contain both the pointer and additional data, describing the region that they point to.

Tagging

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