¿Cómo detectan los compiladores el desbordamiento del búfer?

7

Acabo de comenzar a investigar sobre seguridad a nivel de sistemas y desafíos, especialmente con respecto a lenguajes de bajo nivel como C / C ++ y Objective-C. He entendido el desbordamiento de búfer y cómo funciona. Estaba jugando con eso en OS X y Ubuntu. Por supuesto, estos sistemas tienen ASLR y protecciones de pila implementadas, que podemos deshabilitar en el momento de la compilación. Así que tengo un par de preguntas con respecto a esto:

  1. ¿Cómo detecta un compilador un desbordamiento en el momento de la compilación? Entiendo que al compilarlo se agregará un canario y si alguna instrucción intenta sobrescribir esto, se generará un error. Pero, ¿cuál es el algoritmo exacto? Si alguien puede señalar las funciones del código gcc para esto, sería genial.

  2. ¿Desactivar la protección de pila y hacer que la pila / pila sea ejecutable en Ubuntu es suficiente? ¿O puede ASLR hacer que sea difícil de explotar?

  3. Si tengo un binario (sin código fuente) y sé que se bloquea debido al desbordamiento del búfer, ¿cómo lo detecto?

pregunta user775093 03.04.2015 - 05:37
fuente

2 respuestas

6

Los desbordamientos de búfer no se detectan en el momento de la compilación. Existen herramientas de análisis de código como Sparse o Lint ( cpplint , pc-lint ) que realizará un análisis adicional tanto en los archivos de código fuente como en los binarios compilados. Cada herramienta de análisis tiene sus propios algoritmos para determinar un desbordamiento de búfer, pero se trata de instrucciones comunes conocidas que conducen a desbordamientos de búfer.

También puede agregar Bounds Checking en la compilación que inserta información de límites para cada bloque de memoria asignado. Esta información de límites se verifica en tiempo de ejecución para garantizar que los buffers estén dentro de sus límites. Una implementación común es usar punteros "gruesos". Que contienen la dirección del puntero real a los datos y datos adicionales que describen la región en la que se encuentra. Creo que Firefox hace esto por sus asignaciones de memoria, pero podría estar equivocado.

Los canarios se insertan en tiempo de compilación para ayudar a detectar desbordamientos de búfer insertando un word de datos entre un búfer y los datos de control en la pila. En un cierto punto antes de la devolución de la función, se verifica que el canario esté intacto.

ASLR no tiene nada que ver con la protección de la pila. Aleatoriza la dirección que su programa ejecuta en la memoria. Esto significa que no puede confiar en que las funciones estén en la misma dirección cada vez que se ejecuta el programa. Esto evita la codificación de las direcciones de bibliotecas y funciones. Sin embargo, hacer que la pila o el montón (o cualquier parte de la memoria que estés intentando ejecutar) sea ejecutable es necesario, pero ASLR todavía te causará problemas. Si solo está experimentando y tratando de comprender el código de explotación, haría lo siguiente:

  1. Deshabilitar ASLR
  2. Deshabilitar las protecciones de pila
  3. Ataca cada problema individualmente y vuelve a habilitarlos uno por uno hasta que tu exploit pueda manejar ambos.

Si tiene un binario que se bloquea debido a ... bueno, cualquier cosa (no solo un desbordamiento de búfer) ejecuta el programa en un depurador. El depurador detectará el bloqueo en el punto exacto en que falla el programa. Probablemente debería darse cuenta de que esta podría no ser la ubicación exacta del desbordamiento, pero un seguimiento de la pila debería ayudar a determinar la causa raíz. Le sugeriría leer estas publicaciones si no está familiarizado con las herramientas de ingeniería inversa o la arquitectura de la computadora x86.

¿Por qué se ejecutan los desbordamientos de búfer en la dirección en que están?
Herramientas de ingeniería inversa

    
respondido por el RoraΖ 03.04.2015 - 13:50
fuente
1

Considera el siguiente código

void f1()
{
     char buf[20];
     strcpy(buf,"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); // The buffer overrun
} 

void f2() 
{
    ....
    f1(); 
    (address of this place will be pushed onto to the stack 
     as the return address before calling f1)
    ...
}

Cuando f2 llama a f1 , de manera predeterminada, la dirección de retorno (es decir, la dirección a la que debe regresar la llamada después de que f1 haya terminado de ejecutarse) se coloca en la pila.

Normalmente, cuando el búfer bufón se sobrepasa en f1 , se explota sobrescribiendo la dirección de retorno en la pila, de modo que cuando finaliza f1 el código regresa a algún lugar donde el atacante controla los datos que pueden ejecutar un Guión o algo que hace el exploit.

Los Compiladores de Microsoft implementan una protección de la siguiente manera.
Cuando la función se carga, coloca una cookie de seguridad (un valor aleatorio) entre el final del búfer y el lugar en la pila donde se almacena la dirección de retorno. El compilador también agrega algo de código al final de la función f1 para verificar si la cookie de seguridad es la misma que se colocó.
Así que digamos que hubo una saturación del búfer, y la saturación del búfer se usó para cambiar todas las cosas después del final del búfer, incluida la dirección de retorno. Esto significará que la cookie de seguridad también fue sobrescrita. Cuando la función f1 termina de ejecutarse, el código agregado al final de la función detectará esto y cerrará el programa, lo que significa que no se ejecutará el exploit (ejecución del código que el atacante quería que ocurriera).

Aquí hay una explicación más detallada

    
respondido por el user93353 03.04.2015 - 07:10
fuente

Lea otras preguntas en las etiquetas