Desbordamientos de pila - Derrotar a Canaries, ASLR, DEP, NX

74

Para evitar los desbordamientos de búfer, hay varias protecciones disponibles, como el uso de valores de Canary, ASLR, DEP, NX. Pero, donde hay una voluntad, hay un camino. Estoy investigando sobre los diversos métodos que un atacante podría evitar estos esquemas de protección. Parece que no hay un lugar donde se proporcione información clara. Estos son algunos de mis pensamientos.

Canario : un atacante podría averiguar el valor del canario y usarlo en su inyección de búfer para engañar a la guardia de la pila de detectar un exploit

DEP, NX : si hay llamadas a VirtualAlloc(), VirtualProtect() , el atacante podría intentar redirigir el código a estas funciones y deshabilitar DEP, NX en las páginas en las que desea inyectar un código arbitrario.

ASLR : no hay pista. ¿Cómo funcionan ASLR y DEP?

    
pregunta sudhacker 21.09.2012 - 15:09
fuente

3 respuestas

85

Canarias
Los canarios de la pila funcionan modificando las regiones de prólogo y epílogo de cada función para colocar y verificar un valor en la pila respectivamente. Como tal, si se sobrescribe un búfer de pila durante una operación de copia de memoria, se advierte el error antes que la ejecución vuelve de la función de copia. Cuando esto sucede, se genera una excepción, que pasa de nuevo a la jerarquía del controlador de excepciones hasta que finalmente alcanza el controlador de excepciones predeterminado del sistema operativo. Si puede sobrescribir una estructura de manejador de excepciones existente en la pila, puede hacer que apunte a su propio código. Este es un exploit de Manejo de Excepciones Estructuradas (SEH, por sus siglas en inglés), y te permite omitir completamente el control canario.

DEP / NX
DEP y NX esencialmente marcan las estructuras importantes en la memoria como no ejecutables, y fuerzan las excepciones a nivel de hardware si intenta ejecutar esas regiones de memoria. Esto hace que los desbordamientos normales del búfer de la pila en los que establezca eip a esp+offset e inmediatamente ejecute su shellcode sea imposible, ya que la pila no es ejecutable. La omisión de DEP y NX requiere un truco genial llamado Programación orientada al retorno .

ROP esencialmente implica encontrar fragmentos de código existentes del programa (llamados gadgets) y saltar a ellos, de modo que produzca un resultado deseado. Dado que el código es parte de la memoria ejecutable legítima, DEP y NX no importan. Estos dispositivos se encadenan a través de la pila, que contiene su carga útil de explotación. Cada entrada en la pila corresponde a la dirección del siguiente gadget ROP. Cada gadget está en la forma de instr1; instr2; instr3; ... instrN; ret , de modo que ret saltará a la siguiente dirección en la pila después de ejecutar las instrucciones, encadenando los gadgets. A menudo, se deben colocar valores adicionales en la pila para completar con éxito una cadena, debido a las instrucciones que de otro modo se interpondrían.

El truco consiste en encadenar estos ROP para llamar a una función de protección de memoria como VirtualProtect , que luego se usa para hacer que la pila sea ejecutable, de modo que su código de shell pueda ejecutarse, a través de un jmp esp o un gadget equivalente. Se pueden usar herramientas como mona.py para generar estas cadenas de gadgets ROP, o encontrar gadgets ROP en general.

ASLR
Hay algunas formas de omitir ASLR:

  • Sobrescritura directa de RET: a menudo, los procesos con ASLR todavía cargarán módulos que no sean de ASLR, lo que le permitirá ejecutar su código de shell a través de un jmp esp .
  • Sobrescritura parcial de EIP: sobrescriba solo parte de EIP, o use una divulgación de información confiable en la pila para encontrar lo que debería ser el EIP real, luego úselo para calcular su objetivo. Sin embargo, todavía necesitamos un módulo que no sea ASLR para esto.
  • Aerosol NOP: crea un gran bloque de NOP para aumentar las posibilidades de que el salto salte en memoria legítima. Difícil, pero posible incluso cuando todos los módulos están habilitados para ASLR. Sin embargo, no funcionará si DEP está activado.
  • Bruteforce: si puedes probar una vulnerabilidad con una vulnerabilidad que no hace que el programa se bloquee, puedes usar Bruteforce en 256 direcciones de destino diferentes hasta que funcione.

Lectura recomendada:

respondido por el Polynomial 21.09.2012 - 17:06
fuente
25

Los canarios y otros volátiles no evitan el desbordamiento ; solo tratan de hacer frente a las consecuencias de un desbordamiento que ha sucedido . El canario intenta detectar el caso de un desbordamiento que sobrescribió la dirección de retorno en un marco de pila. DEP es un paso más allá, asume que la dirección de retorno se ha sobrescrito y seguido , y restringe las áreas donde la ejecución podría saltar. ASLR es todavía un paso más allá: "baraja" las áreas donde se permite la ejecución .

Históricamente, los desbordamientos de búfer fueron explotados para sobrescribir la dirección de retorno en la pila, para que la ejecución salte a los mismos datos que se han utilizado para desbordar el búfer. El canario intenta detectar eso antes de saltar, y DEP se usa para hacer que el espacio de pila no sea ejecutable. DEP también funciona cuando se desbordan los búferes en el montón (el canario es de alguna utilidad solo para desbordamientos de búfer de pila, pero el montón puede contener búferes y también datos confidenciales para sobrescribir, como punteros a funciones, especialmente en el contexto de OOP lenguajes como C ++). Para evitar el DEP y el canario, los atacantes han comenzado a buscar desbordamientos que permiten sobrescribir los punteros para que funcionen, a fin de hacer que la ejecución salte al código de biblioteca estándar , que es necesariamente "allí" y también necesariamente ejecutable. . Es por eso que se inventó ASLR: para hacer más difíciles tales juegos. ASLR aún puede ser derrotado siendo afortunado: dado que ASLR debe mantener la alineación de la página (4 kB en x86), dentro de un espacio de direcciones no muy grande (generalmente menos de 2 GB en 32 bits x86), no hay tantos lugares donde puede estar el código objetivo (como máximo medio millón). Dependiendo del contexto del ataque y de la frecuencia con la que el script del atacante puede intentarlo, esto puede ser demasiado bajo para su comodidad.

El tema importante aquí es que los canarios, DEP y ASLR no vencen a los desbordamientos en sí mismos, sino que apuntan a los métodos de explotación de desbordamiento genéricos que tradicionalmente se han empleado. En cualquier aplicación, un desbordamiento que sobrescribe los datos no punteros puede ser tan mortal como un exploit de shell remoto (por ejemplo, imagine un desbordamiento que modifique un campo de cadena llamado " authenticated_user_name "). La carrera armamentística entre los atacantes y los defensores se está volviendo demasiado especializada y, en mi opinión, cada vez pierde más el punto. En general, es mucho mejor nunca permitir que se produzca el desbordamiento, es decir, bloquear / eliminar el proceso / subproceso ofensivo antes de escribir bytes fuera del búfer de destino. Eso es lo que sucede con casi cualquier lenguaje de programación decente (Java, C #, VB.NET, Python, Ruby, Node.js, OCaml, PHP ... la elección es grande).

    
respondido por el Thomas Pornin 21.09.2012 - 16:49
fuente
13

El nivel básico de protección es ASLR + DEP.

Si no usas ambos, entonces hay muchas técnicas poderosas para explotar una saturación de búfer (por ejemplo, computación orientada al retorno, rociado de pilas, adivinación repetida). Por ejemplo, DEP solo puede ser derrotado usando computación orientada al retorno; y ASLR solo puede ser derrotado usando rociadura de pilas e intentos repetidos.

Sin embargo, si el objetivo utiliza ambos ASLR + DEP, la explotación se vuelve mucho más difícil. Las técnicas mencionadas anteriormente no son suficientes para derrotar a ASLR + DEP. Los ASLR + DEP son como un golpe doble que hace que la vida del atacante sea mucho más difícil. Derrotar la combinación de ASLR + DEP no es imposible, pero requiere mucha más inteligencia.

Mi ejemplo favorito de métodos para derrotar a ASLR + DEP se explica en la diapositiva, Explotación del intérprete: Inferencia de puntero y pulverización JIT . Allí, el autor describe cómo explotó un error de seguridad de memoria en Flash. Explotó las propiedades del Flash JIT para organizar la memoria de una manera que le permite montar un ataque de inyección de código, a pesar de la presencia de ASLR + DEP. Recuerde que un JIT es un compilador justo a tiempo; compila los bytecodes de Flash al código nativo. El código nativo se almacenará en algún lugar de la memoria, y el JIT de Flash lo marca como ejecutable (a pesar de DEP). El autor encontró una forma de generar códigos de bytes Flash que, cuando se compilaban, generaría una secuencia de bytes que incrustaba su código de shell malicioso (compensado por un byte). Luego utilizó técnicas de pulverización en pilas para asegurarse de que había muchas copias de esto en la memoria. Finalmente, explotó el error de seguridad de la memoria para hacer que el programa salte a otra dirección; debido a ASLR, esto fue como saltar a una dirección aleatoria, pero las muchas copias aseguraron que con alta probabilidad saltaría a su código de shell. De esta manera, eludió tanto a ASLR como a DEP, una hazaña ingeniosa.

Una última nota: vale la pena mencionar que ASLR es mucho más efectivo en arquitecturas de 64 bits. En las arquitecturas de 32 bits, ASLR a menudo puede ser derrotado simplemente haciendo múltiples intentos. Simplemente, no hay suficientes grados de libertad en las plataformas de 32 bits para introducir suficiente aleatoriedad, por lo que las posibilidades de que el atacante tenga éxito con la mala suerte siguen siendo demasiado altas, en las plataformas de 32 bits. Para la defensa más fuerte, use una plataforma de 64 bits.

    
respondido por el D.W. 23.09.2012 - 02:47
fuente

Lea otras preguntas en las etiquetas