Desbordamiento de búfer: Consejos para explotar

0
int play() {

    int a;
    int b;
    char buffer[010];
    a = 0x41414141;
    b = 0x42424242;

    if (write(STDOUT_FILENO, "For a moment, nothing happened. Then, after a second or so, nothing continued to happen.\n> ", 91) < 0) {
        perror("write");
    }

    if (read(STDIN_FILENO, &buffer, 0xC) < 0) {                                              
        perror("read");                                                                   
    }

    if (a == 31337) {
        system(buffer);
    }

    else if (b == 1337) {
        readfile("flag.0");
    }

    else if (b == 42) {
        readfile("vuln1.txt");
    }

    else {
        write(STDOUT_FILENO, "So long and thanks for all the fish.\n", 37);
    }

}


int main(int argc, char *argv[]){
    play();
    exit(EXIT_SUCCESS);
}

Creo que lo que está sucediendo es que con un búfer si el tamaño es de 11, ¿está intentando agregarle 12 bytes? ¿Está eso cerca?

Soy un novato que da miedo y me disculpo si este no es el lugar adecuado para este tipo de pregunta. Cualquier punto de apoyo en qué hacer sería muy apreciado.

Lo he compilado y lo he ejecutado con GDB pero no he llegado a ningún lado rápido

    
pregunta pee2pee 10.01.2017 - 01:11
fuente

2 respuestas

3

Los 0x414141 y 0x424242 que se colocan en libros con fines educativos porque son simplemente las cadenas "AAAAAAAA" y "BBBBBBB" en notación hexadecimal. Asignarlos a enteros no tiene nada que ver con los desbordamientos de búfer.

Se puede obtener un ejemplo mucho mejor utilizando un programa completo y una llamada a la función que nos permitirá saber cuándo ocurre el desbordamiento. Por ejemplo, alteremos el programa para:

#include <stdio.h>
#include <unistd.h>

void
fun(void)
{
    char buffer[10];

    if (read(STDIN_FILENO, &buffer, 60) < 0) {
        perror("read");
    }
    write(STDOUT_FILENO, "So long and thanks for all the fish.\n", 37);
    return;
}

int
main(void)
{
    fun();
    write(STDOUT_FILENO, "WILL NOT PRINT.\n", 16);
    return 0;
}

Ya que estás usando read y write estamos asumiendo un sistema UNIX, así que vamos a compilarlo y ejecutarlo un par de veces. Suponiendo que la fuente del programa está en buf.c :

[~]$ gcc -g -o prog buf.c
[~]$ perl -e 'print "A"x10' | ./prog
So long and thanks for all the fish.
WILL NOT PRINT.
[~]$ perl -e 'print "A"x20' | ./prog
So long and thanks for all the fish.
WILL NOT PRINT.

Perl es útil porque podemos controlar exactamente la cantidad de bytes que le damos al programa. Como STDIN está conectado a una tubería, podemos proporcionar una cantidad variable de bytes, hasta los 60 bytes codificados en la fuente del programa.

La primera ejecución da lo que esperábamos, 10 bytes son lugares en el búfer de 10 bytes de longitud. En la segunda ejecución, el búfer de 10 bytes debe tener un desbordamiento con 20 bytes de entrada. Pero nada parece suceder. Bueno, el búfer se desbordó, pero no se desbordó lo suficiente como para dificultar la ejecución del proceso. Vamos a hacer más:

[grochmal@haps tmp]$ perl -e 'print "A"x30' | ./prog
So long and thanks for all the fish.
Segmentation fault (core dumped)

Bien, eso es lo que esperamos ver de un desbordamiento. Ahora que tenemos una buena información, la guardamos y vemos cómo funciona el programa en GDB:

[grochmal@haps tmp]$ perl -e 'print "A"x30' > input
[grochmal@haps tmp]$ gdb -q prog
Reading symbols from prog...done.
(gdb) list
5   fun(void)
6   {
7       char buffer[10];
8   
9       if (read(STDIN_FILENO, &buffer, 30) < 0) {
10          perror("read");
11      }
12      write(STDOUT_FILENO, "So long and thanks for all the fish.\n", 37);
13      return;
14  }
(gdb) list
15  
16  int
17  main(void)
18  {
19      fun();
20      write(STDOUT_FILENO, "WILL NOT PRINT.\n", 16);
21      return 0;
22  }
23  
(gdb) break 9
Breakpoint 1 at 0x40058e: file buf.c, line 9.
(gdb) break 12
Breakpoint 2 at 0x4005b3: file buf.c, line 12.

Como agregamos -g a la línea del compilador, tenemos todos los símbolos de depuración (por ejemplo, el código del programa) que podamos desear. Esto hace que sea muy fácil configurar los puntos de ruptura donde ocurre la parte interesante de la ejecución. Ejecutamos el programa con la entrada que acabamos de guardar y verificamos el aspecto del búfer:

(gdb) run <input
Starting program: /home/grochmal/tmp/prog <input

Breakpoint 1, fun () at buf.c:9
9       if (read(STDIN_FILENO, &buffer, 30) < 0) {
(gdb) p &buffer
$1 = (char (*)[10]) 0x7fffffffe800
(gdb) x/15wx 0x7fffffffe800
0x7fffffffe800: 0x004005f0  0x00000000  0x00400490  0x00000000
0x7fffffffe810: 0xffffe820  0x00007fff  0x004005d3  0x00000000
0x7fffffffe820: 0x004005f0  0x00000000  0xf7a5c291  0x00007fff
0x7fffffffe830: 0xf7dd0798  0x00007fff  0xffffe908

El búfer tiene solo 10 bytes de longitud, e imprimimos 60 bytes. Pero eso regala 0xffffe820 , que es la ubicación a la que el programa debe regresar (en main) desde la llamada fun() . Cuando el búfer se desborda, los bytes sobrescriben eso. Vamos a verlo al continuar con la llamada read .

(gdb) cont
Continuing.

Breakpoint 2, fun () at buf.c:12
12      write(STDOUT_FILENO, "So long and thanks for all the fish.\n", 37);
(gdb) x/15wx 0x7fffffffe800
0x7fffffffe800: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffe810: 0x41414141  0x41414141  0x41414141  0x00004141
0x7fffffffe820: 0x004005f0  0x00000000  0xf7a5c291  0x00007fff
0x7fffffffe830: 0xf7dd0798  0x00007fff  0xffffe908

Y ahora el programa intentará volver a 0x41414141 , lo que provocará la falta de seguridad.

(gdb) cont
Continuing.
So long and thanks for all the fish.

Program received signal SIGSEGV, Segmentation fault.
0x0000414141414141 in ?? ()

Y lo hizo! Como bono, tenemos la cadena 0x41414141 que está utilizando como una asignación int en su programa, y ahora puede deducir de dónde viene.

La implicación de seguridad de esto es que sé exactamente qué parte de la entrada sobrescribe ese valor de retorno en la pila. Y, gracias a eso, puedo dirigir el programa a cualquier instrucción dentro de su asignación de memoria.

(En la práctica, eso es mucho más difícil hoy en día porque existen varias medidas para evitar que esos desbordamientos encuentren lugares útiles a los que volver. Pero el concepto es el mismo.)

    
respondido por el grochmal 10.01.2017 - 05:41
fuente
0

Al usar el programa @grochmal, pude obtener el error de segmentación en mi máquina local. Aún no pudiendo resolver el problema principal.

Como no se ha mencionado explícitamente en la pregunta original, esto es parte de un desafío donde el archivo vuln1.txt debe leerse provocando un desbordamiento a través de un puerto abierto de forma remota donde se está ejecutando el programa anterior.

Estoy tratando de averiguar cómo establecer el valor de B = 42. Cualquier ayuda es muy apreciada.

    
respondido por el Amit K 14.01.2017 - 02:51
fuente

Lea otras preguntas en las etiquetas