Si la pila crece hacia abajo, ¿cómo puede un desbordamiento del búfer sobrescribir el contenido sobre la variable?

7

Me doy cuenta de cómo funciona un desbordamiento de búfer, pero tengo un problema para entender la dirección en la que se dirige el desbordamiento. Así que si la pila crece hacia abajo , eso significa que la dirección de retorno está arriba del espacio reservado de la variable. Cuando esa variable ahora está desbordada, ¿no debería sobrescribir la memoria a continuación en lugar de arriba?

tl; dr: Si la pila crece hacia abajo, ¿cómo puede un desbordamiento de búfer sobrescribir el contenido sobre la variable?

    
pregunta AdHominem 03.09.2016 - 10:45
fuente

4 respuestas

6

Si la pila crece hacia abajo, las funciones que se llaman más adelante obtienen marcos de pila en direcciones de memoria inferiores. Además, la dirección de retorno se inserta en la pila antes de que se reserve el espacio para las variables locales, por lo que la dirección de retorno obtiene una dirección más alta que las variables locales. Pero las matrices y los buffers aún se indexan hacia arriba en la memoria, por lo que escribir más allá del final de la matriz pegará muy bien en la siguiente dirección de la pila.

Ejemplo, con arte ASCII obligatorio:

Considere la función trivial que toma información de una fuente no confiable y la copia en un búfer local:

void foo(char *s)
{
    char buf[8];
    strcpy(buf, s);
    return;
}

La pila se parece un poco a esto:

   <---- stack grows to the left
    memory addresses increase to the right -->
  0x8000                        0x8010
  +--------+----------+---------++------------
  + buf[8] | ret addr | char *s ||   ....... 
  +--------+----------+---------++--------------
   <--------- foo() ----------->  <---- caller --

La pila se llena de derecha a izquierda, comenzando con los argumentos de la función, luego la dirección de retorno y luego los locales de la función. Es fácil ver que un simple desbordamiento de buf hacia el aumento de direcciones llegará a la dirección de retorno muy bien.

Entonces, ¿qué pasa si la pila está invertida y crece hacia arriba? Luego, el desbordamiento de un búfer se ejecutará de la misma manera que crece la pila, hacia la parte vacía de la pila.

Suena bien, pero no ayuda si foo() llama a otra función para hacer la copia. Lo que no es inusual, solo lo hice con strcpy . Ahora la pila se ve así:

    stack grows to the right -->
    memory addresses increase to the right -->
            0x8000                          0x8010
------------++---------+----------+---------++-----------+-------------+
  ....      || char *s | ret addr | buf[8]  || ret addr  | locals  ... |
------------++---------+----------+---------++-----------+-------------+
 caller --->  <-------- foo() ------------->  <---- strcpy() ---------->

Ahora, sobrepasar (a la derecha) el búfer en el marco de pila de foo() sobrescribirá muy bien la dirección de retorno de strcpy() , no foo() . Sin embargo, no importa, seguimos saltando a una ubicación establecida por los datos controlados por el atacante y desbordados.

    
respondido por el ilkkachu 03.09.2016 - 18:16
fuente
3

Hay una diferencia entre el desbordamiento de búfer y el desbordamiento de pila. Los buffers asignados no pueden usar la pila, sino el montón. Esto depende de la forma en que se asignan y de lo que el compilador sería mejor / más rápido / etc.

Un desbordamiento de pila de hecho anula la memoria siguiente, que puede haber sido asignada a otra llamada (anterior) o, en última instancia, al montón. El montón crece hacia arriba y en algún momento pueden chocar. Este es un buen momento para que el sistema operativo genere un fallo de segmentación, detenga el programa o envíe señales. El problema con los desbordamientos de pila es que pueden entrar en contacto con otros subprocesos del mismo proceso. Ahora, la imagen de un subproceso que tiene un búfer grande para el envío / recepción de red, el contenido de otra pila de subprocesos podría anular esta área de memoria y causar pérdidas de memoria en la red.

Los desbordamientos de búfer son más comunes y van más allá de los límites de su propia memoria. Mientras la memoria a la que se accede aún esté dentro de la región de almacenamiento dinámico, no hay problema (desde la perspectiva del sistema operativo). Se vuelve más peligroso cuando el montón es demasiado pequeño y es necesario asignar datos adicionales. En este punto no se puede decir qué pasaría cuando se alcanzan los límites. Cuando se intenta acceder a un byte más allá del límite del montón, el sistema operativo debería detener el proceso con un SIGSEGV.

    
respondido por el Yorick de Wid 03.09.2016 - 11:43
fuente
3

La pila solo crece hacia abajo cuando se le asigna algo. Por otro lado, leer el final de una matriz significa leer hacia arriba en la memoria.

Digamos que el puntero de pila dice 0x1002. En esta dirección hay un indicador de retorno que le interesa. Si asigna, digamos, una matriz de 2 bytes, la pila crece hacia abajo: el puntero de pila se cambia a 0x1000, y la dirección de la matriz se establece en ese nuevo valor. Escribir el primer byte a la matriz usa la dirección 0x1000, y escribir el segundo usa 0x1001. Al descartar el uso final se usa 0x1002 y se sobrescribe lo que importa.

Puedes ver esto en las imágenes que publicaste, ya que el cuadro gris que representa el búfer B crece hacia arriba a medida que se escribe más allá de sus límites.

    
respondido por el Reid Rankin 03.09.2016 - 14:54
fuente
2

Una pila crece hacia abajo por las instrucciones push, pero escribe y lee hacia arriba. por ejemplo, si su pila ocupa la dirección 10 a 5, que es una longitud de 6 direcciones utilizables, cuando tenga una instrucción de inserción, la pila bajará y agregará una memoria adicional que hará que su pila ocupe la dirección 10 - 4 que es 7 direcciones utilizables. pero cuando escribe en la pila y el indicador de instrucción está en 4, escribirá desde 4 hasta 10 y cuando pase la dirección 10, tendrá un desbordamiento de búfer

    
respondido por el moski1122 08.02.2018 - 00:56
fuente

Lea otras preguntas en las etiquetas