La idea de usar más espacio del que te dieron y, por lo tanto, extenderse a un campo diferente es lo suficientemente simple como para visualizarlo. Pero probablemente no esté claro cómo esto puede llevar a que un tipo malo ejecute su propio código.
Esto es bastante simple de explicar si lo entiendes lo suficientemente bien. Sólo asegúrese de golpear en el fondo importante. Más o menos en este orden:
-
La "pila" es un lugar donde puede almacenar información temporal. El "puntero de pila" determina dónde está el final de la pila. Cuando se ejecuta una función, mueve el puntero de la pila para darse memoria para trabajar, y cuando termina, mueve el puntero hacia atrás donde lo encontró.
-
La pila crece hacia atrás. Así que para darte 100 bytes en la pila, debes restar 100 del puntero de pila en lugar de agregarlo. Si la pila de la función anterior comenzó en 1000 y quiero 100 bytes, entonces mi pila comienza en 900.
-
Esto significa que si usa más espacio del que se dio a sí mismo, no solo continuará escribiendo en el espacio vacío, en realidad comenzará a sobrescribir los valores de pila anteriores.
-
Cuando mi función comienza, el valor más alto que me queda en la pila por la función anterior es la dirección de retorno a la que debo ir cuando termine mi función.
-
Esto significa que si mi función supera su pila, la primera cosa que se va a sobrescribir es la dirección de retorno. Si el atacante tiene cuidado con lo que llena la pila, puede especificar la dirección de retorno que desee.
-
Cuando existe mi función, el código que se encuentre en esa dirección de devolución es el que se ejecutará a continuación.
Ejemplo simple
En Smashing the Stack for Fun and Profit , donde esta técnica se describió originalmente, la más simple y directa Se introdujo la técnica. Imagina que la función lee tu nombre y luego regresa. Así que tu pila se ve así:
Stack Pointer Prev. Stack Ptr
+----------------------------------+--------------+................
| Your Name Here | Return Addr | Old stack ...
+----------------------------------+--------------+................
Pero el chico malo hace que su nombre sea lo suficientemente largo como para desbordar el espacio. Y no solo eso, en lugar de escribir un nombre real, escribe algunos códigos de maldad, algunos rellenos y la dirección de ese código de maldad.
+----------------------------------+--------------+................
| [ Evil Code ]xxxxxxxxxxxxxxxxxxxxxxEvil Address | Old stack ...
+----------------------------------+--------------+................
▲──────────────────────────────────┘
Ahora, en lugar de volver al interlocutor anterior, salta directamente al [Evil Code]
. Ahora estás ejecutando su código en lugar de tu programa. A partir de ahí es casi un juego terminado.
Mitigación y otras técnicas
Dos de las técnicas utilizadas para reducir la efectividad de aplastar pilas son DEP y ASLR.
DEP ("Prevención de ejecución de datos") funciona marcando la pila como no ejecutable. Esto significa que el [Evil Code]
en la pila no se ejecutará, porque ya no se permite ejecutar el código en la pila. Para evitar esto, el atacante encuentra trozos de código existente que hará fragmentos de lo que quiere. Y en lugar de solo sobrescribir su propia dirección de retorno, crea una cadena de direcciones de retorno a través de la pila para todas las funciones que quiere ejecutar por turno. Lo llaman "Programación Orientada al Retorno", o ROP. La cadena de devoluciones se llama "ROP Chain". Esto es muy difícil de hacer. Pero hay herramientas para ayudar.
ASLR ("Asignación aleatoria del diseño del espacio de direcciones") funciona al asignar al azar las ubicaciones de todas las funciones interesantes. Ahora, crear una cadena ROP no es tan fácil: cada vez que se ejecuta el programa, todas las direcciones están en diferentes lugares. Entonces, cuando el atacante sobrescribe la dirección de retorno con su propia Dirección del Mal, no sabrá qué números usar porque el código siempre está en diferentes lugares.
Ni el DEP ni el ASLR por sí solos ofrecen mucha protección, pero los dos juntos hacen que la explotación exitosa sea muy difícil. Aunque a veces existen algunas circunferencias, no hay una solución que funcione en todas partes . Si puede moverse por DEP + ASLR, es un éxito único.