¿Cómo puedo invocar el desbordamiento del búfer?
pointers stack-trace (5)
Obtuve una tarea que me pedía que invocara una función sin llamarla explícitamente, utilizando el desbordamiento del búfer. El código es básicamente esto:
#include <stdio.h>
#include <stdlib.h>
void g()
{
printf("now inside g()!/n");
}
void f()
{
printf("now inside f()!/n");
// can only modify this section
// cant call g(), maybe use g (pointer to function)
}
int main (int argc, char *argv[])
{
f();
return 0;
}
Aunque no estoy seguro de cómo proceder. Pensé en cambiar la dirección de retorno del contador del programa para que proceda directamente a la dirección de g (), pero no estoy seguro de cómo acceder a ella. De todos modos, los consejos serán geniales.
Dado que esto es tarea, me gustaría hacer eco de la sugerencia de codeaddict de entender cómo funciona un desbordamiento de búfer.
Aprendí la técnica leyendo el artículo / tutorial excelente (aunque un poco anticuado) sobre la explotación de vulnerabilidades de desbordamiento del búfer. Rompiendo la pila para divertirse y obtener ganancias .
Eso depende del compilador, por lo que no se puede dar una sola respuesta.
El siguiente código hará lo que quieras para gcc 4.4.1. Compilar con optimizaciones desactivadas (¡importante!)
#include <stdio.h>
#include <stdlib.h>
void g()
{
printf("now inside g()!/n");
}
void f()
{
int i;
void * buffer[1];
printf("now inside f()!/n");
// can only modify this section
// cant call g(), maybe use g (pointer to function)
// place the address of g all over the stack:
for (i=0; i<10; i++)
buffer[i] = (void*) g;
// and goodbye..
}
int main (int argc, char *argv[])
{
f();
return 0;
}
Salida:
nils@doofnase:~$ gcc overflow.c
nils@doofnase:~$ ./a.out
now inside f()!
now inside g()!
now inside g()!
now inside g()!
now inside g()!
now inside g()!
now inside g()!
Segmentation fault
La idea básica es alterar la dirección de retorno de la función para que cuando la función retorna continúe ejecutándose en una nueva dirección pirateada. Como lo hizo Nils en una de las respuestas, puede declarar una porción de memoria (normalmente una matriz) y desbordarla de tal forma que la dirección de retorno también se sobrescriba.
Le sugiero que no tome ciegamente ninguno de los programas que se dan aquí sin entender realmente cómo funcionan. Este artículo está muy bien escrito y lo encontrarás muy útil:
Un paso a paso en la vulnerabilidad de desbordamiento de búfer
Prueba este:
void f()
{
void *x[1];
printf("now inside f()!/n");
// can only modify this section
// cant call g(), maybe use g (pointer to function)
x[-1]=&g;
}
o este:
void f()
{
void *x[1];
printf("now inside f()!/n");
// can only modify this section
// cant call g(), maybe use g (pointer to function)
x[1]=&g;
}
Si bien esta solución no utiliza una técnica de desbordamiento para sobrescribir la dirección de retorno de la función en la pila, aún hace que g()
se llame desde f()
en su camino de regreso a main()
modificando f()
y no llamando g()
directamente.
El epílogo de función como ensamblaje en línea se agrega a f()
para modificar el valor de la dirección de retorno en la pila para que f()
regrese a través de g()
.
#include <stdio.h>
void g()
{
printf("now inside g()!/n");
}
void f()
{
printf("now inside f()!/n");
// can only modify this section
// cant call g(), maybe use g (pointer to function)
/* x86 function epilogue-like inline assembly */
/* Causes f() to return to g() on its way back to main() */
asm(
"mov %%ebp,%%esp;"
"pop %%ebp;"
"push %0;"
"ret"
: /* no output registers */
: "r" (&g)
: "%ebp", "%esp"
);
}
int main (int argc, char *argv[])
{
f();
return 0;
}
Comprender cómo funciona este código puede conducir a una mejor comprensión de cómo se configura el marco de pila de una función para una arquitectura particular que forma la base de las técnicas de desbordamiento del búfer.