stringtranslate.com

Protección contra desbordamiento del búfer

La protección contra desbordamiento de búfer es cualquiera de las diversas técnicas utilizadas durante el desarrollo de software para mejorar la seguridad de los programas ejecutables mediante la detección de desbordamientos de búfer en las variables asignadas a la pila y evitando que causen un mal comportamiento del programa o se conviertan en vulnerabilidades de seguridad graves . Un desbordamiento del búfer de pila ocurre cuando un programa escribe en una dirección de memoria en la pila de llamadas del programa fuera de la estructura de datos prevista, que generalmente es un búfer de longitud fija. Los errores de desbordamiento del 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 da como resultado la corrupción de los datos adyacentes en la pila, lo que podría provocar fallas del programa, operación incorrecta o problemas de seguridad.

Normalmente, la protección contra desbordamiento del búfer modifica la organización de los datos asignados a la pila para que incluya un valor canario que, cuando se destruye por un desbordamiento del búfer de la pila, muestra que un búfer que lo precede en la memoria se ha desbordado. Al verificar el valor canary, se puede finalizar la ejecución del programa afectado, evitando que se comporte mal o permitiendo que un atacante tome el control sobre él. Otras técnicas de protección contra desbordamiento del búfer incluyen la verificación de límites , que verifica los accesos a cada bloque de memoria asignado para que no puedan ir más allá del espacio realmente asignado, y el etiquetado , que garantiza que la memoria asignada para almacenar datos no pueda contener código ejecutable.

Es más probable que llenar en exceso un búfer asignado en la pila influya en la ejecución del programa que llenar en exceso un búfer en el montón porque 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 aquellas para GNU Compiler Collection , LLVM , Microsoft Visual Studio y otros compiladores.

Descripción general

Un desbordamiento del búfer de pila ocurre cuando un programa escribe en una dirección de memoria en la pila de llamadas del programa fuera de la estructura de datos prevista, que generalmente es un búfer de longitud fija. Los errores de desbordamiento del 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 da como resultado la corrupción de los datos adyacentes en la pila y, en los casos en que el desbordamiento se activó por error, a menudo provocará que el programa falle o funcione incorrectamente. El desbordamiento del búfer de pila es un tipo de mal funcionamiento de programación más general conocido como desbordamiento del búfer (o desbordamiento del búfer). Es más probable que llenar demasiado un búfer en la pila descarrile la ejecución del programa que llenar demasiado 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 producirse deliberadamente como parte de un ataque conocido como destrucción de pila . Si el programa afectado se ejecuta con privilegios especiales, o si acepta datos de hosts de red que no son de confianza (por ejemplo, un servidor web público ), entonces el error es una posible vulnerabilidad de seguridad que permite a un atacante inyectar código ejecutable en el programa en ejecución y tomar control del proceso. Este es uno de los métodos más antiguos y confiables para que los atacantes obtengan acceso no autorizado a una computadora. [2]

Normalmente, la protección contra desbordamiento del búfer modifica la organización de los datos en el marco de la pila de una llamada de función para incluir un valor "canario" que, cuando se destruye, muestra que un búfer que lo precede en la memoria se ha desbordado. Esto proporciona el beneficio 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 la destrucción de pilas no puede proteger contra ciertas formas de ataque. Por ejemplo, no puede proteger contra desbordamientos del búfer en el montón. No existe una manera sensata de alterar el diseño de los datos dentro de una estructura ; Se espera que las estructuras sean las mismas entre módulos, especialmente con bibliotecas compartidas. Cualquier dato en una estructura después de un búfer es imposible de proteger con canarios; por tanto, los programadores deben tener mucho cuidado con la forma en que organizan sus variables y utilizan sus estructuras.

Canarias

Los canarios o palabras canarias o cookies de pila son valores conocidos que se colocan entre un búfer y los datos de control en la pila para monitorear los desbordamientos del búfer. Cuando el búfer se desborda, los primeros datos que se corrompen normalmente serán los canarios y, por lo tanto, una verificación fallida de los datos canarios alertará de un desbordamiento, que luego se puede manejar, por ejemplo, invalidando los datos corruptos. Un valor canario no debe confundirse con un valor centinela .

La terminología es una referencia a la práctica histórica de utilizar canarios en las minas de carbón , ya que serían afectados por gases tóxicos antes que los mineros, proporcionando así un sistema de alerta biológica. Los canarios también se conocen como cookies de pila , cuyo objetivo es evocar la imagen de una "cookie rota" cuando el valor está dañado.

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

canarios terminador

Los canarios Terminator utilizan la observación de que la mayoría de los ataques de desbordamiento de búfer se basan en ciertas operaciones de cadena que terminan en terminadores de cadena. La reacción a esta observación es que los canarios están construidos con terminadores nulos , CR , LF y FF . Como resultado, el atacante debe escribir un carácter nulo antes de escribir la dirección del remitente para evitar alterar el canario. Esto evita el uso de ataques strcpy()y otros métodos que regresan al copiar un carácter nulo, mientras que el resultado no deseado es que se conoce el canario. Incluso con la protección, un atacante podría sobrescribir el canario con su valor conocido y controlar la información con valores no coincidentes, pasando 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 al azar

Los canarios aleatorios se generan aleatoriamente, generalmente a partir de un demonio de recolección de entropía , para evitar que un atacante conozca su valor. Por lo general, no es lógicamente posible o plausible leer el canario para explotarlo; el canario es un valor seguro conocido sólo por aquellos que necesitan conocerlo: en este caso, el código de protección contra desbordamiento del búfer.

Normalmente, se genera un canario aleatorio durante la inicialización del programa y se almacena en una variable global. Esta variable suele estar rellena con páginas no asignadas, de modo que intentar leerla utilizando cualquier tipo de truco que aproveche los errores para leer la RAM provoque un error de segmentación que finalice el programa. Es posible que aún sea posible leer el canario si el atacante sabe dónde está o puede hacer que el programa lea desde la pila.

Canarios XOR aleatorios

Los canarios XOR aleatorios son canarios aleatorios que se codifican mediante XOR utilizando todos o parte de los datos de control. De esta manera, una vez que el canario o los datos de control son golpeados, el valor canario es incorrecto.

Los canarios XOR aleatorios tienen las mismas vulnerabilidades que los canarios aleatorios, excepto que el método de "lectura de la pila" para obtener el canario es un poco más complicado. El atacante debe obtener el canario, el algoritmo y los datos de control para volver a generar el canario original necesario para falsificar la protección.

Además, los canarios XOR aleatorios pueden proteger contra cierto tipo de ataque que implica el desbordamiento de un búfer en una estructura en un puntero para cambiar el puntero para que apunte a un dato de control. Debido a la codificación XOR, el canario será incorrecto si se cambian los datos de control o el valor de retorno. Gracias al puntero, los datos de control o el valor de retorno se pueden cambiar sin desbordar el canario.

Aunque estos canarios protegen los datos de control para que no sean alterados por punteros golpeados, no protegen ningún otro dato ni los propios punteros. Los punteros de función son especialmente un problema aquí, ya que pueden desbordarse y ejecutar shellcode cuando se les llama.

Comprobación de límites

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

Las implementaciones de este enfoque utilizan un repositorio central, que describe cada bloque de memoria asignado, [4] [5] [6] o punteros gruesos , [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 compilador o hardware (que requiere una arquitectura etiquetada ) para etiquetar el tipo de un dato en la memoria, utilizada principalmente para la verificación de tipos. Al marcar ciertas áreas de la memoria como no ejecutables, se evita efectivamente que la memoria asignada para almacenar datos contenga código ejecutable. Además, ciertas áreas de memoria se pueden marcar como no asignadas, lo que evita desbordamientos del 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 se puede utilizar para detectar desbordamientos del búfer. [10] Un ejemplo es la característica de hardware de bits NX , compatible con procesadores Intel , AMD y ARM .

Implementaciones

Colección de compiladores GNU (GCC)

La protección contra la destrucción de pilas 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 de 1998 a 2003 y se amplió con implementaciones para terminador, canarios aleatorios y XOR aleatorios. Se sugirió la inclusión de StackGuard en GCC 3.x en las Actas de la Cumbre de GCC 2003, [12] pero esto nunca se logró.

De 2001 a 2005, IBM desarrolló parches GCC para protección contra la destrucción de pilas, conocidos como ProPolice . [13] Mejoró la idea de StackGuard al colocar buffers después de punteros locales y argumentos de función en el marco de la pila. Esto ayudó a evitar la corrupción de los punteros, impidiendo el acceso a ubicaciones de memoria arbitrarias.

Sin embargo, los ingenieros de Red Hat identificaron problemas con ProPolice y en 2005 volvieron a implementar la protección contra la destrucción de pilas para incluirla 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, ya sea que las necesiten o no. [dieciséis]

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 -fstack-protectorque -fstack-protector-all. Está disponible en GCC desde su versión 4.9. [18]

Todos los paquetes de Fedora se compilan -fstack-protectordesde Fedora Core 5 y -fstack-protector-strongdesde Fedora 20. [19] [20] La mayoría de los paquetes en Ubuntu se compilan -fstack-protectordesde 6.10. [21] Todos los paquetes de Arch Linux se compilan -fstack-protectordesde 2011. [22] Todos los paquetes de Arch Linux creados desde el 4 de mayo de 2014 utilizan -fstack-protector-strong. [23] La protección de pila solo se usa para algunos paquetes en Debian , [24] y solo para el sistema base 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 . [ cita necesaria ]

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

Microsoft Visual Studio

El conjunto de compiladores de Microsoft implementa 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 la destrucción de pilas se puede activar mediante el indicador del compilador -qstackprotect. [31]

Sonido metálico/ LLVM

Clang admite las mismas -fstack-protectoropciones que GCC [32] y un sistema de "pila segura" más potente ( -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 tienen diferentes compensaciones 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 C y C++ de Intel admite protección contra destrucción de pilas con opciones similares a las proporcionadas por GCC y Microsoft Visual Studio. [37]

C a prueba de fallos

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

StackGhost (basado en hardware)

Inventado por Mike Frantzen, StackGhost es un simple ajuste de las rutinas de llenado/desbordamiento de la ventana de registro que hace que los desbordamientos del búfer sean mucho más difíciles de explotar. Utiliza una característica de hardware única de la arquitectura SPARC de Sun Microsystems (que es: derrame/relleno diferido de la ventana de registro en el marco de la pila) para detectar modificaciones de los punteros de retorno (una forma común para que un exploit se apodere de las rutas de ejecución) de forma transparente y automática. protegiendo todas las aplicaciones sin requerir modificaciones binarias o de código fuente. El impacto en el rendimiento es insignificante, menos del uno por ciento. Mark Kettenis resolvió los problemas resultantes de gdb dos años después, lo que permitió habilitar la función. Después de este evento, el código StackGhost se integró (y optimizó) en OpenBSD /SPARC.

Ver 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". CERT DE EE . UU .
  2. ^ Levy, Elías (8 de noviembre de 1996). "Rompiendo la pila por diversión y ganancias". Phrack . 7 (49): 14.
  3. ^ "Desbordamientos de búfer: ataques y defensas para la vulnerabilidad de la década*" (PDF) . Archivado desde el original (PDF) el 9 de marzo de 2013.
  4. ^ ab "Comprobación de límites para C". Doc.ic.ac.uk. Archivado desde el original el 26 de marzo de 2016 . Consultado el 27 de abril de 2014 .
  5. ^ ab "SAFECode: Arquitectura virtual segura". Sva.cs.illinois.edu. 2009-08-12 . Consultado el 27 de abril de 2014 .
  6. ^ abc "google/desinfectantes". 19 de junio de 2021.
  7. ^ abc "C a prueba de fallos: página principal". Staff.aist.go.jp. 2013-05-07. Archivado desde el original el 7 de julio de 2016 . Consultado el 27 de abril de 2014 .
  8. «Martes 05 de abril de 2005» (PDF) . Feustel.us . Archivado desde el original (PDF) el 23 de junio de 2016 . Consultado el 17 de septiembre de 2016 .
  9. ^ Steenkiste, Peter; Hennessy, John (1987). "Etiquetas y verificación de tipos en LISP: enfoques de hardware y software". Revisión de los sistemas operativos ACM Sigops . 21 (4). MCA: 50–59. doi : 10.1145/36204.36183 .
  10. ^ "Descripción general de seguridad de MCP de ClearPath Enterprise Servers" (PDF) . Public.support.unisys.com. Archivado desde el original (PDF) el 24 de enero de 2013 . Consultado el 27 de abril de 2014 .
  11. ^ "Artículos - Séptimo Simposio de seguridad de USENIX, 1998". Usenix.org. 2002-04-12 . Consultado el 27 de abril de 2014 .
  12. ^ "Actas de la Cumbre de Desarrolladores del CCG" (PDF) . Mayo de 2003. Archivado desde el original el 15 de julio de 2004 . Consultado el 17 de septiembre de 2016 .{{cite web}}: Mantenimiento CS1: bot: estado de la URL original desconocido ( enlace )
  13. ^ "Extensión GCC para proteger aplicaciones contra ataques devastadores". Investigación.ibm.com . Consultado el 27 de abril de 2014 .
  14. ^ "Serie de lanzamientos de GCC 4.1: cambios, nuevas funciones y correcciones - Proyecto GNU - Free Software Foundation (FSF)". Gcc.gnu.org . Consultado el 27 de abril de 2014 .
  15. ^ "Richard Henderson - [rfc] reimplementación del protector de destrucción de pilas 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] Agregue una nueva opción" -fstack-protector-strong "(parche/doc dentro)". Gcc.gnu.org. 2012-06-14 . Consultado el 27 de abril de 2014 .
  18. ^ Edge, Jake (5 de febrero de 2014). "Protección de pila "fuerte" para GCC". Noticias semanales de Linux . Consultado el 28 de noviembre de 2014 . Ha llegado a GCC 4.9
  19. ^ "Funciones de seguridad". Proyecto Fedora. 2013-12-11 . 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 - Ubuntu Wiki". Wiki.ubuntu.com . Consultado el 27 de abril de 2014 .
  22. ^ "FS#18864: Considere habilitar la protección contra destrucción de pilas de GCC (ProPolice, SSP) para todos los paquetes". Bugs.archlinux.org . Consultado el 27 de abril de 2014 .
  23. ^ "svntogit/packages.git: clon de Git del repositorio de 'paquetes'".[ enlace muerto permanente ]
  24. ^ "Estadísticas de refuerzo de seguridad de Debian". Outflux.net. Archivado desde el original el 28 de abril de 2014 . Consultado el 27 de abril de 2014 .
  25. ^ "Notas de la versión de FreeBSD 8.0-RELEASE". Freebsd.org. 2013-11-13 . Consultado el 27 de abril de 2014 .
  26. ^ "Página de manual gcc-local(1) de OpenBSD". gcc viene con la extensión de protección de pila ProPolice , que está habilitada de forma predeterminada.
  27. ^ "Cadena de herramientas/endurecida - Gentoo Wiki". 2016-07-31. El GCC reforzado de Gentoo activa el protector de pila de forma predeterminada a menos que se solicite explícitamente que no lo haga.
  28. ^ "12º Simposio de seguridad de USENIX: documento técnico".
  29. ^ "Blogs de MSDN: obtenga la información, conocimientos, anuncios y noticias más recientes de expertos y desarrolladores de Microsoft en los blogs de MSDN". 6 de agosto de 2021.
  30. ^ "/GS (comprobación de seguridad del búfer) (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. ^ "Código SEGURO". Safecode.cs.illinois.edu . Consultado el 27 de abril de 2014 .
  36. ^ "Página de manual clang-local(1) de OpenBSD". clang viene con la protección de pila habilitada de forma predeterminada, equivalente a la opción -fstack-protector-strong en otros sistemas.
  37. ^ "Guía de referencia y de usuario para el compilador Intel C++ 15.0: fstack-security-check, GS". software.intel.com . Consultado el 13 de febrero de 2015 .
  38. ^ "tesis.dvi" (PDF) . Staff.aist.go.jp . Consultado el 17 de septiembre de 2016 .

enlaces externos