Desbordamiento de búfer

La versión actual de la página aún no ha sido revisada por colaboradores experimentados y puede diferir significativamente de la versión revisada el 6 de enero de 2017; las comprobaciones requieren 22 ediciones .

Un  desbordamiento de búfer es un fenómeno que ocurre cuando un programa de computadora escribe datos fuera de un búfer asignado en la memoria .

Los desbordamientos de búfer generalmente resultan del manejo inadecuado de los datos y la memoria recibidos externamente, en ausencia de fuertes protecciones del subsistema de programación ( compilador o intérprete ) y el sistema operativo . Como resultado de un desbordamiento, los datos ubicados después del búfer (o antes) [1] pueden corromperse .

El desbordamiento de búfer es una de las formas más populares de piratear sistemas informáticos [2] , ya que la mayoría de los lenguajes de alto nivel utilizan tecnología de marco de pila  : colocan datos en la pila de procesos , mezclan datos de programa con datos de control (incluida la dirección de inicio del marco de pila y la dirección de retorno de la función ejecutable).

Un desbordamiento de búfer puede hacer que un programa se bloquee o se cuelgue, lo que lleva a una denegación de servicio ( DoS). Ciertos tipos de desbordamientos, como un desbordamiento de marco de pila, permiten que un atacante cargue y ejecute código de máquina arbitrario en nombre del programa y con los derechos de la cuenta desde la que se ejecuta [3] .

Se conocen ejemplos en los que los programas del sistema utilizan deliberadamente desbordamientos de búfer para eludir las limitaciones del software o firmware existente. Por ejemplo, el sistema operativo iS-DOS (para computadoras ZX Spectrum ) usó la función de desbordamiento de búfer del TR-DOS incorporado para iniciar su cargador de arranque en códigos de máquina (lo que es imposible de hacer con las herramientas estándar de TR-DOS).

Seguridad

Un programa que utiliza una vulnerabilidad para romper la protección de otro programa se denomina explotación . Los más peligrosos son los exploits diseñados para obtener acceso al nivel de superusuario o, en otras palabras, la escalada de privilegios . El exploit de desbordamiento de búfer logra esto al pasar una entrada especialmente diseñada al programa. Dichos datos desbordan el búfer asignado y cambian los datos que siguen a ese búfer en la memoria . [cuatro]

Imagine un programa hipotético de administración del sistema que se ejecuta con privilegios de superusuario, por ejemplo, cambiar las contraseñas de los usuarios . Si el programa no verifica la longitud de la nueva contraseña ingresada, cualquier dato que exceda el tamaño del búfer asignado para su almacenamiento simplemente se escribirá sobre lo que estaba después del búfer. Un atacante puede insertar instrucciones en lenguaje de máquina en esta área de memoria , por ejemplo, shellcode , realizando cualquier acción con privilegios de superusuario: agregar y eliminar cuentas de usuario, cambiar contraseñas, cambiar o eliminar archivos , etc. Si se ejecuta en esta área de memoria permitida, y en en el futuro, el programa le transferirá el control, el sistema ejecutará el código de máquina del atacante que se encuentra allí.

Los programas bien escritos deben verificar la longitud de los datos de entrada para asegurarse de que no sea más grande que el búfer de datos asignado. Sin embargo, los programadores a menudo se olvidan de ello. Si el búfer está ubicado en la pila y la pila "crece hacia abajo" (por ejemplo, en la arquitectura x86 ), entonces, al usar un desbordamiento de búfer, puede cambiar la dirección de retorno de la función ejecutada , ya que la dirección de retorno se encuentra después de la búfer asignado por la función ejecutada. Por lo tanto, es posible ejecutar una sección arbitraria de código de máquina en el espacio de direcciones del proceso. Es posible utilizar un desbordamiento de búfer para corromper la dirección de retorno incluso si la pila "crece" (en cuyo caso, la dirección de retorno suele estar antes que el búfer). [5]

Incluso a los programadores experimentados les resulta difícil determinar si un desbordamiento de búfer dado podría ser una vulnerabilidad. Esto requiere un conocimiento profundo de la arquitectura de la computadora y el programa de destino. Se ha demostrado que incluso pequeños desbordamientos como escribir un solo byte fuera del búfer pueden representar vulnerabilidades. [6]

Los desbordamientos de búfer son comunes en programas escritos en lenguajes de programación de nivel relativamente bajo , como lenguaje ensamblador , C y C++ , que requieren que el programador controle el tamaño de la memoria asignada. La solución de problemas de desbordamiento de búfer sigue siendo un proceso mal automatizado. Los sistemas formales de verificación de programas no son muy eficientes con los lenguajes de programación modernos. [7]

Muchos lenguajes de programación, como Perl , Python , Java y Ada , administran la asignación de memoria automáticamente, lo que hace que los errores de desbordamiento del búfer sean poco probables o imposibles. [8] Perl proporciona un cambio de tamaño automático de matrices para evitar desbordamientos de búfer . Sin embargo, los sistemas de tiempo de ejecución y las bibliotecas para dichos lenguajes aún pueden ser susceptibles a desbordamientos de búfer debido a posibles errores internos en la implementación de estos sistemas de validación. Hay varias soluciones de software y firmware disponibles en Windows que evitan que el código se ejecute fuera de un búfer de desbordamiento si ocurre tal desbordamiento. Estas soluciones incluyen DEP en Windows XP SP2 , [9] OSsurance y Anti-Execute .

En la arquitectura de Harvard , el código ejecutable se mantiene separado de los datos, lo que hace que tales ataques sean casi imposibles. [diez]

Breve resumen técnico

Ejemplo

Considere un ejemplo de un programa C vulnerable :

#incluir <cadena.h> int principal ( int argc , char * argv []) { charbuf [ 100 ] ; strcpy ( buf , argv [ 1 ]); devolver 0 ; }

Utiliza la función strcpy insegura , que le permite escribir más datos de los que caben en la matriz asignada para ellos. Si ejecuta este programa en un sistema Windows con un argumento de más de 100 bytes, lo más probable es que el programa se bloquee y el usuario reciba un mensaje de error.

El siguiente programa no se ve afectado por esta vulnerabilidad:

#incluir <cadena.h> int principal ( int argc , char * argv []) { charbuf [ 100 ] ; strncpy ( buf , argv [ 1 ], tamaño de ( buf )); devolver 0 ; }

Aquí, strcpy se reemplazó con strncpy , donde el número máximo de caracteres que se copiarán está limitado por el tamaño del búfer. [once]

Descripción

Los diagramas siguientes muestran cómo un programa vulnerable puede dañar la estructura de la pila .

Ilustración de escribir varios datos en un búfer asignado en la pila

En la arquitectura x86 , la pila crece de direcciones más grandes a más pequeñas, es decir, los datos nuevos se colocan antes que los que ya están en la pila.

Al escribir datos en el búfer, puede escribir más allá de sus límites y cambiar los datos allí, en particular, cambiar la dirección de retorno .

Si el programa tiene privilegios especiales (como ejecutarse como root ), un atacante puede cambiar la dirección de retorno a una dirección de shellcode , lo que le permite ejecutar comandos en el sistema de destino con privilegios elevados . [12]

Explotación

Las técnicas de desbordamiento de búfer varían según la arquitectura, el sistema operativo y el área de memoria. Por ejemplo, el caso de un desbordamiento de búfer en el montón (utilizado para la asignación de memoria dinámica) es significativamente diferente al de la pila de llamadas .

Explotación de pila

También conocido como aplastamiento de pilas . Un usuario experto en tecnología puede usar un desbordamiento de búfer de pila para manipular el programa a su favor de las siguientes maneras:

  • sobrescribiendo una variable local ubicada en la memoria al lado del búfer, cambiando el comportamiento del programa a su favor.
  • sobrescribiendo la dirección de retorno en el marco de la pila . Tan pronto como finaliza la función, el control se transfiere a la dirección especificada por el atacante, generalmente al área de memoria a la que tuvo acceso para modificar.
  • sobrescribiendo un puntero de función [13] o un controlador de excepciones que luego tomará el control.
  • sobrescribiendo el parámetro de otro marco de pila, o una dirección no local apuntada en el contexto actual. [catorce]

Si se desconoce la dirección de los datos del usuario, pero se almacena en un registro, se puede utilizar   el método de trampolín  : la dirección de retorno se puede sobrescribir con la dirección del código de operación , que transferirá el control al área de memoria con los datos del usuario. Si la dirección está almacenada en el registro R, saltar a un comando que transfiere el control a esa dirección (por ejemplo, llamar a R) hará que se ejecute el código especificado por el usuario. Las direcciones de los códigos de operación o bytes de memoria adecuados se pueden encontrar en la DLL o en el propio ejecutable. Sin embargo, las direcciones generalmente no pueden contener caracteres nulos, y las ubicaciones de estos códigos de operación varían según la aplicación y el sistema operativo. El Proyecto Metasploit , por ejemplo, mantuvo una base de datos de códigos de operación adecuados para sistemas Windows (que actualmente no está disponible). [quince]

Un desbordamiento de búfer en la pila no debe confundirse con un desbordamiento de pila .

También vale la pena señalar que tales vulnerabilidades generalmente se encuentran utilizando la técnica de prueba fuzzing .

Explotación de montones

Un desbordamiento de búfer en un área de datos de almacenamiento dinámico se denomina desbordamiento de almacenamiento dinámico y se explota de forma diferente a un desbordamiento de búfer en la pila. La memoria del montón es asignada dinámicamente por una aplicación en tiempo de ejecución y generalmente contiene datos del programa. La explotación se realiza corrompiendo estos datos de formas especiales para obligar a la aplicación a sobrescribir estructuras internas, como punteros en listas vinculadas. Una técnica de explotación común para los desbordamientos del búfer de montón es sobrescribir las referencias de memoria dinámica ( como los metadatos de la función malloc ) y usar el puntero modificado resultante para sobrescribir el puntero de la función del programa.

Una vulnerabilidad en el producto GDI+ de Microsoft en el manejo de imágenes JPEG  es un ejemplo del peligro que puede representar un desbordamiento del búfer de almacenamiento dinámico. [dieciséis]

Dificultades en la operación

Manipular el búfer antes de leerlo o ejecutarlo puede impedir la explotación exitosa de la vulnerabilidad. Pueden reducir la amenaza de un ataque exitoso, pero no eliminarlo por completo. Las acciones pueden incluir convertir una cadena a mayúsculas o minúsculas, eliminar caracteres especiales o filtrar todos los caracteres excepto los alfanuméricos. Sin embargo, existen trucos para eludir estas medidas: shellcodes alfanuméricos, [17] códigos polimórficos , [ 18 ] códigos que cambian automáticamente y el ataque de retorno de la biblioteca . [19] Las mismas técnicas se pueden utilizar para ocultarse de los sistemas de detección de intrusos . En algunos casos, incluidos los casos de conversión de caracteres a Unicode , la vulnerabilidad se confunde con permitir un ataque DoS , cuando en realidad es posible la ejecución remota de código arbitrario. [veinte]

Prevención

Se utilizan varios trucos para hacer que los desbordamientos de búfer sean menos probables.

Sistemas de detección de intrusos

Los sistemas de detección de intrusos ( IDS) pueden detectar y prevenir intentos de explotar de forma remota los desbordamientos de búfer. Dado que en la mayoría de los casos los datos destinados a un desbordamiento de búfer contienen matrices largas de instrucciones Sin operación ( NOPo ) NOOP, el IDS simplemente bloquea todos los paquetes entrantes que contienen una gran cantidad de NOP consecutivos. Este método es generalmente ineficaz, ya que dichas matrices se pueden escribir usando una variedad de instrucciones en lenguaje ensamblador . Más recientemente, los piratas informáticos han comenzado a utilizar shellcodes con cifrado , código automodificable , código polimórfico y código alfanumérico , así como ataques alternativos a la biblioteca estándar para penetrar en IDS. [21]

Protección contra corrupción de pila

La protección contra corrupción de pila se utiliza para detectar los errores de desbordamiento de búfer más comunes. Esto verifica que la pila de llamadas no se haya modificado antes de regresar de la función. Si se ha cambiado, entonces el programa termina con una falla de segmentación .

Hay dos sistemas, StackGuard y Stack-Smashing Protector (anteriormente ProPolice), ambos extensiones del compilador gcc . Desde gcc-4.1-stage2, SSP se ha integrado en la distribución principal del compilador . Gentoo Linux y OpenBSD incluyen SSP con sus distribuciones gcc. [22]

Colocar la dirección de retorno en la pila de datos facilita la implementación de un desbordamiento de búfer que conduce a la ejecución de código arbitrario. En teoría, se podrían realizar cambios en gcc para permitir que la dirección se coloque en una pila de retorno especial que esté completamente separada de la pila de datos, de forma similar a cómo se implementa en el lenguaje Forth . Sin embargo, esta no es una solución completa al problema del desbordamiento del búfer, ya que también es necesario proteger otros datos de la pila.

Protección del espacio de código para sistemas similares a UNIX

La protección del espacio del código ejecutable puede mitigar los efectos de los desbordamientos del búfer, lo que imposibilita la mayoría de las acciones maliciosas. Esto se logra mediante la aleatorización del espacio de direcciones ( ASLR ) y/o la prohibición del acceso simultáneo a la memoria para escritura y ejecución. La pila no ejecutable previene la mayoría de las vulnerabilidades del código shell .

Hay dos parches del kernel de Linux que brindan esta protección: PaX y exec-shield . Ninguno de estos está aún incluido en la distribución principal del núcleo. OpenBSD desde la versión 3.3 ha incluido un sistema llamado W^X que también proporciona control de tiempo de ejecución.

Tenga en cuenta que este método de protección no evita la corrupción de la pila. Sin embargo, a menudo evita que la "carga útil" del exploit se ejecute con éxito. El programa no podrá insertar código de shell en la memoria protegida contra escritura, como segmentos existentes de código ejecutable. Tampoco será posible ejecutar instrucciones en la memoria no ejecutable, como la pila o el montón .

ASLR dificulta que un atacante determine las direcciones de funciones en el código de un programa con las que podría llevar a cabo un ataque exitoso, y hace que ataques como ret2libc sean muy difíciles, aunque todavía son posibles en un entorno controlado, o si el atacante correctamente adivina la dirección correcta.

Algunos procesadores , como Sparc de Sun , Efficeon de Transmeta y los últimos procesadores de 64 bits de AMD e Intel, impiden la ejecución de código ubicado en áreas de memoria marcadas con el bit especial NX . AMD llama a su solución NX (del inglés  No eXecute ), e Intel llama a su XD (del inglés  eXecute Disabled ). [23]

Protección de espacio de código en tiempo de ejecución para Windows

Ahora hay varias soluciones diferentes disponibles para proteger el código ejecutable en los sistemas Windows , tanto de Microsoft como de terceros.

Microsoft ofreció su solución, llamada DEP (del inglés  Data Execution Prevention  - “prevención de ejecución de datos”), incluyéndola en los service packs para Windows XP y Windows Server 2003 . DEP aprovecha los nuevos procesadores Intel y AMD que fueron diseñados para superar el límite de memoria direccionable de 4 GB de los procesadores de 32 bits. A estos efectos, se han ampliado algunas estructuras de servicios. Estas estructuras ahora contienen el bit NX reservado. DEP usa este bit para evitar ataques que impliquen cambiar la dirección de un controlador de excepciones (el llamado SEH exploit ). DEP solo brinda protección contra el exploit SEH , no protege las páginas de memoria con código ejecutable. [9]

Además, Microsoft ha desarrollado un mecanismo de protección de pila diseñado para Windows Server. La pila se marca con la ayuda de los llamados "informantes" ( inglés  canario ), cuya integridad luego se verifica. Si se ha cambiado el "informador", la pila está dañada. [24]

También existen soluciones de terceros que impiden la ejecución de código ubicado en áreas de memoria destinadas a datos o implementando el mecanismo ASLR.

Uso de bibliotecas seguras

El problema de los desbordamientos de búfer es común a los lenguajes de programación C y C++ porque no ocultan los detalles de la representación de bajo nivel de los búferes como contenedores para tipos de datos . Por lo tanto, para evitar desbordamientos de búfer, se debe mantener un alto nivel de control sobre la creación y modificación del código que administra los búferes. El uso de bibliotecas de tipos de datos abstractos que realizan una gestión de búfer automática centralizada e incluyen la verificación de desbordamiento es un enfoque de ingeniería para la prevención de desbordamiento de búfer. [25]

Los dos principales tipos de datos que permiten desbordamientos de búfer en estos lenguajes son cadenas y matrices . Por lo tanto, el uso de bibliotecas para cadenas y estructuras de datos de lista que se han desarrollado para prevenir y/o detectar desbordamientos de búfer evita muchas vulnerabilidades. El precio de tales soluciones es una disminución del rendimiento debido a comprobaciones innecesarias y otras acciones realizadas por el código de la biblioteca, ya que está escrito "para todas las ocasiones", y en cada caso específico, algunas de las acciones que realiza pueden ser redundantes.

Historia

El desbordamiento del búfer se entendió y se documentó en parte ya en 1972 en el Estudio de planificación de tecnología de seguridad informática. [26] El primer uso malicioso documentado de un desbordamiento de búfer ocurrió en 1988. Se basó en uno de varios exploits utilizados por el gusano Morris para autopropagarse a través de Internet. El programa aprovechó una vulnerabilidad en el servicio finger de Unix . [27] Más tarde, en 1995, Thomas Lopatik redescubrió de forma independiente el desbordamiento del búfer y enumeró los hallazgos en la lista Bagtrak . [28] Un año después, Elias Levy publicó una introducción paso a paso sobre el uso de desbordamientos de búfer con la pila, Smashing the Stack for Fun and Profit, en la revista Phrack . [12]

Desde entonces, al menos dos gusanos de red conocidos han usado desbordamientos de búfer para infectar una gran cantidad de sistemas. En 2001, el gusano Code Red explotó esta vulnerabilidad en el producto Internet Information Services (IIS) 5.0 de Microsoft , [29] y en 2003 SQL Slammer infectó máquinas que ejecutaban Microsoft SQL Server 2000 . [treinta]

En 2003, la explotación de un desbordamiento de búfer presente en los juegos de Xbox con licencia permitió que el software sin licencia se ejecutara en la consola sin modificar el hardware utilizando los llamados modchips . [31] El Exploit de independencia de PS2 también usó un desbordamiento de búfer para lograr el mismo resultado para PlayStation 2 . Un exploit similar para Wii Twilight explotó esta vulnerabilidad en The Legend of Zelda: Twilight Princess .

Véase también

Notas

  1. Erickson, 2010 , Desbordamiento de búfer 0x320, pág. 139.
  2. Wheeler, 2004 , 6. Evite el desbordamiento del búfer, p. 71.
  3. Erickson, 2010 , Desbordamiento de búfer de pila 0x321, pág. 142.
  4. Erickson, 2010 , 0x300 Exploits, p. 135-139.
  5. ↑ "Desbordamientos de HP-UX (PA-RISC 1.1)" por Zhodiac  . Frack . Consultado el 8 de diciembre de 2014. Archivado desde el original el 3 de diciembre de 2014.
  6. ↑ "La sobrescritura del puntero de cuadro" por klog  . Frack . Consultado el 8 de diciembre de 2014. Archivado desde el original el 3 de diciembre de 2014.
  7. Rueda, 2004 , 6.1. Peligros en C/C++, pág. 71.
  8. Rueda, 2004 , 6.4. Otros idiomas, pág. 80.
  9. ↑ 1 2 Prevención de ejecución de datos (DEP  ) . vlaurie.com. Consultado el 8 de diciembre de 2014. Archivado desde el original el 18 de diciembre de 2008.
  10. Hackear Windows CE  . Frack . Fecha de acceso: 14 de diciembre de 2014. Archivado desde el original el 3 de diciembre de 2014.
  11. Desbordamiento de búfer de bricolaje n.º 2 . Revista Xakep. Fecha de acceso: 8 de diciembre de 2014. Archivado desde el original el 11 de diciembre de 2014.
  12. ↑ 1 2 "Rompiendo la pila por diversión y ganancias" por Aleph One  . Frack . Fecha de acceso: 8 de diciembre de 2014. Archivado desde el original el 6 de febrero de 2013.
  13. ↑ CORE-2007-0219: Desbordamiento del búfer del núcleo remoto IPv6 mbufs  de OpenBSD . enfoqueseguridad.com. Fecha de acceso: 8 de diciembre de 2014. Archivado desde el original el 12 de febrero de 2012.
  14. Objetivos de desbordamiento modernos  . Tormenta de paquetes. Consultado el 8 de diciembre de 2014. Archivado desde el original el 23 de octubre de 2016.
  15. La base de datos de códigos de operación de Metasploit  . Metasploit . Consultado el 15 de mayo de 2007. Archivado desde el original el 12 de mayo de 2007.
  16. Boletín de seguridad de Microsoft Technet MS04-028  (inglés)  (enlace no disponible) . microsoft _ Consultado el 8 de diciembre de 2014. Archivado desde el original el 4 de agosto de 2011.
  17. Escribir  shellcodes alfanuméricos ia32 . Frack . Consultado el 14 de diciembre de 2014. Archivado desde el original el 10 de marzo de 2014.
  18. Motor polimórfico Shellcode  . Frack . Fecha de acceso: 14 de diciembre de 2014. Archivado desde el original el 11 de diciembre de 2014.
  19. Exploits avanzados de return-into-lib(c)  . Frack . Fecha de acceso: 14 de diciembre de 2014. Archivado desde el original el 14 de diciembre de 2014.
  20. Creación de Shellcode arbitrario en cadenas expandidas Unicode  (inglés) (PDF). Ayuda Net Security. Consultado el 8 de diciembre de 2014. Archivado desde el original el 5 de enero de 2006.
  21. Día, DJ; Sch. de Computación., Univ. de Derby, Derby, Reino Unido; Zhengxu Zhao; Minhua Ma. Detección de ataques de desbordamiento de búfer de retorno a libc mediante sistemas de detección de intrusos en la red   // IEEE . - 2010. - P. 172-177 . - ISBN 978-1-4244-5805-9 . -doi : 10.1109/ ICDS.2010.37 .
  22. Rueda, 2004 , 6.3. Soluciones de compilación en C/C++, pág. 79.
  23. Características  ._ _ Ubuntu . Consultado el 9 de diciembre de 2014. Archivado desde el original el 8 de agosto de 2019.
  24. Perla, Oldani, 2011 , CAPÍTULO 6 Ventanas.
  25. Rueda, 2004 , 6.2. Soluciones de biblioteca en C/C++, pág. 73.
  26. Estudio de planificación de tecnología de seguridad informática  (inglés) (PDF)  (enlace no disponible) . Centro de recursos de seguridad informática (CSRC). Fecha de acceso: 8 de diciembre de 2014. Archivado desde el original el 21 de julio de 2011.
  27. "Un recorrido por The Worm" de Donn Seeley, Universidad de  Utah . mundo.std.com. Consultado el 3 de junio de 2007. Archivado desde el original el 20 de mayo de 2007.
  28. Archivo de la lista de correo de seguridad de  Bugtraq . www.seguridad-express.com. Consultado el 3 de junio de 2007. Archivado desde el original el 1 de septiembre de 2007.
  29. eEye Seguridad digital  . eEye Seguridad Digital. Consultado el 3 de junio de 2007. Archivado desde el original el 25 de junio de 2007.
  30. Boletín de seguridad de Microsoft Technet MS02-039  (inglés)  (enlace no disponible) . microsoft _ Consultado el 8 de diciembre de 2014. Archivado desde el original el 7 de marzo de 2008.
  31. Hacker rompe la protección de Xbox sin mod-  chip . juegosindustria.biz Consultado el 3 de junio de 2007. Archivado desde el original el 27 de septiembre de 2007.

Literatura

  • James Foster, Mike Price. Protección contra pirateo: sockets, exploits, shellcode = Sockets, Shellcode, Porting y Coding. - M. : Editorial DMK-press, 2006. - S. 35, 532. - 784 p. - ISBN 5-9706-0019-9 .
  • Juan Erickson. 0x320 Desbordamiento de búfer // Hacking : El arte de la explotación. — 2ª edición. - San Petersburgo. : Símbolo-Plus, 2010. - S.  139 . — 512 págs. — ISBN 978-5-93286-158-5 .
  • David A. Wheeler. Capítulo 6. Evite el desbordamiento del búfer // Programación segura para Linux y Unix COMO . - 2004. - pág. 71. - 188 pág.
  • Enrico Perla, Massimiliano Oldani. CAPÍTULO 6 Windows // Una guía para la explotación del kernel: atacar el núcleo. - 2011. - Pág. 334. - 442 p. — ISBN 978-1-59749-486-1 .

Enlaces

Bibliotecas y otras protecciones