Tema destacado: Recuerda que debes registrarte en el foro para poder participar (preguntar y responder)
Autor
|
Tema: Segmentation fault al cambiar dirección de retorno (Leído 1,769 veces)
|
Nork
Desconectado
Mensajes: 195
|
Buenas!, Pues tengo un problema al intentar cambiar la dirección de retorno de la pila en un buffer overflow. El código que tengo es éste: void function(int a, int b, int c) { char buffer1[5]; char buffer2[10]; int *ret; ret = buffer1 + 12; (*ret) += 7; } void main() { int x; x = 0; function(1,2,3); x = 1; printf("%d\n", x); }Por si a alguien le suena es del artículo smashing the stack for fun and profit. El código que muestra el gdb en ASM es el siguiente: Dump of assembler code for function main: 0x080483e2 <main+0>: lea 0x4(%esp),%ecx 0x080483e6 <main+4>: and $0xfffffff0,%esp 0x080483e9 <main+7>: pushl -0x4(%ecx) 0x080483ec <main+10>: push %ebp 0x080483ed <main+11>: mov %esp,%ebp 0x080483ef <main+13>: push %ecx 0x080483f0 <main+14>: sub $0x24,%esp 0x080483f3 <main+17>: movl $0x0,-0x8(%ebp) 0x080483fa <main+24>: movl $0x3,0x8(%esp) 0x08048402 <main+32>: movl $0x2,0x4(%esp) 0x0804840a <main+40>: movl $0x1,(%esp) 0x08048411 <main+47>: call 0x80483c4 <function> 0x08048416 <main+52>: movl $0x1,-0x8(%ebp) 0x0804841d <main+59>: mov -0x8(%ebp),%eax 0x08048420 <main+62>: mov %eax,0x4(%esp) 0x08048424 <main+66>: movl $0x8048500,(%esp) 0x0804842b <main+73>: call 0x80482f8 <printf@plt> 0x08048430 <main+78>: add $0x24,%esp 0x08048433 <main+81>: pop %ecx 0x08048434 <main+82>: pop %ebp 0x08048435 <main+83>: lea -0x4(%ecx),%esp 0x08048438 <main+86>: ret End of assembler dump. Lo que quiero conseguir es que se muestre el valor de la variable x como 0, es decir, que se salte la línea de código donde le asigna a la x el 1. Bien, se por el código que ret tiene que apuntar a buffer1 más 12 ya que son los 8 bytes de buffer1 + 4bytes del anterior EBP. El problema viene cuando le sumo al valor de retorno la cantidad oportuna para que me salte a 0x0804841d y no a 0x08048416. Si no me equivoco el incremento (o diferencia) sería 7, pero dejándolo así me salta el segmentation fault... por lo que el + 12 estaría bien (consigo modificar el valor de retorno) pero no consigo saber cuanto le tengo que sumar =/ Alguien tiene alguna idea?? P.D: Compilo con el parámetro -fno-stack-protector para deshabilitar la protección. Gracias! 
|
|
|
|
|
En línea
|
|
|
|
E.P.I.
Desconectado
Mensajes: 346
elprogramadorinformatico [E.P.I.]
|
Eso no tiene que ir en programación... ?
|
|
|
|
|
En línea
|
La verdad nos hará libres
|
|
|
Nork
Desconectado
Mensajes: 195
|
Eso no tiene que ir en programación... ?
Hombre no es una cuestión de programación... en todo caso en bugs y exploits. No sé la verdad es que no lo tenía claro y me decidí en postearlo aquí. Si eso que lo cambien no hay problema.
|
|
|
|
|
En línea
|
|
|
|
AlbertoBSD
Estudiante y
Colaborador
 
Desconectado
Mensajes: 1.955
Anonymous & Paranoid
|
Si debería de ir en bugs y exploits, sin embargo sigo sin entender lo que quieres hacer.
De las 3 variables que se le mandan a la función, ninguna interviene en el código de la misma función, ademas el buffer al momende de ejecucion debe de tener basura sin inicializar.
Parece que tienes una idea algo confusa de lo que quieres hacer.
El ret debería de apuntar al ultimo EBP Salvado + 4 bytes
Deja lo pruebo y ahorita te digo que es lo que debes de modificar.
Mover el tema a bugs y exploits
|
|
|
|
|
En línea
|
|
|
|
|
ghastlyX
|
Con el código que has puesto a mi también me da un Segmentation fault. Sin embargo, si coges el código y lo compilas con: gcc -S -o code.s code.c Te generará code.s. Si ahora miras el código de la función en code.s, verás algo como esto: ghastlyx@Ahtec:~$ gcc -S -o code.s code.c code.c: In function ‘f’: code.c:6: warning: assignment from incompatible pointer type code.c: In function ‘main’: code.c:15: warning: incompatible implicit declaration of built-in function ‘printf’ code.c:10: warning: return type of ‘main’ is not ‘int’ ghastlyx@Ahtec:~$ head code.s .file "code.c" .text .globl f .type f, @function f: pushl %ebp movl %esp, %ebp subl $32, %esp leal -9(%ebp), %eax addl $12, %eax
En el leal puedes ver que la dirección de buffer1 es -9(%ebp), de forma que el incremento será 9 + 4. Ahora, compilando normal y abriendo el gdb sale lo siguiente: ghastlyx@Ahtec:~$ gcc code.c code.c: In function ‘f’: code.c:6: warning: assignment from incompatible pointer type code.c: In function ‘main’: code.c:15: warning: incompatible implicit declaration of built-in function ‘printf’ code.c:10: warning: return type of ‘main’ is not ‘int’ ghastlyx@Ahtec:~$ gdb a.out GNU gdb 6.8-debian Copyright (C) 2008 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "i486-linux-gnu"... (gdb) disas main Dump of assembler code for function main: 0x080483c2 <main+0>: lea 0x4(%esp),%ecx 0x080483c6 <main+4>: and $0xfffffff0,%esp 0x080483c9 <main+7>: pushl -0x4(%ecx) 0x080483cc <main+10>: push %ebp 0x080483cd <main+11>: mov %esp,%ebp 0x080483cf <main+13>: push %ecx 0x080483d0 <main+14>: sub $0x24,%esp 0x080483d3 <main+17>: movl $0x0,-0x8(%ebp) 0x080483da <main+24>: movl $0x3,0x8(%esp) 0x080483e2 <main+32>: movl $0x2,0x4(%esp) 0x080483ea <main+40>: movl $0x1,(%esp) 0x080483f1 <main+47>: call 0x80483a4 <f> 0x080483f6 <main+52>: movl $0x1,-0x8(%ebp) 0x080483fd <main+59>: mov -0x8(%ebp),%eax 0x08048400 <main+62>: mov %eax,0x4(%esp) 0x08048404 <main+66>: movl $0x80484e0,(%esp) 0x0804840b <main+73>: call 0x80482d8 <printf@plt> 0x08048410 <main+78>: add $0x24,%esp 0x08048413 <main+81>: pop %ecx 0x08048414 <main+82>: pop %ebp 0x08048415 <main+83>: lea -0x4(%ecx),%esp 0x08048418 <main+86>: ret Se puede ver que main+52 es donde retorna en caso normal y como queremos ir hasta después del x = 1, en este caso hay que ir a main+59, por lo que el segundo incremento es 7. Editando el código y compilando: ghastlyx@Ahtec:~$ cat code.c void f(int a, int b, int c) { char buffer1[5]; char buffer2[10]; int *ret; ret = buffer1 + 13; (*ret) += 7; } void main() { int x; x = 0; f(1,2,3); x = 1; printf("%d\n", x); }
ghastlyx@Ahtec:~$ gcc code.c code.c: In function ‘f’: code.c:6: warning: assignment from incompatible pointer type code.c: In function ‘main’: code.c:15: warning: incompatible implicit declaration of built-in function ‘printf’ code.c:10: warning: return type of ‘main’ is not ‘int’ ghastlyx@Ahtec:~$ ./a.out 0
Un saludo de ghastlyX  PD: He renombrado la función a f como se puede ver en el código.
|
|
|
|
|
En línea
|
|
|
|
Nork
Desconectado
Mensajes: 195
|
De las 3 variables que se le mandan a la función, ninguna interviene en el código de la misma función, ademas el buffer al momende de ejecucion debe de tener basura sin inicializar.
Parece que tienes una idea algo confusa de lo que quieres hacer.
El código no es mio es de un artículo que comenté arriba. Igualmente es un código que es simplemente como prueba de concepto más que nada. @ghastlyX Gracias! Se me había pasado crear el archivo .s y mirar el código ahí... Lo que hacía era de memoria sumar las variables. Esto es algo que no entiendo, si tenemos esto: 12 bytes [buffer2] 8 bytes [buffer1] 4 bytes [@EBPret] Si el puntero ret apunta a buffer1 viéndolo de esta manera serían 12bytes y no 13, no?? De donde sale el byte que falta? O talvez no se puede calcular de esta manera? Otra cuestión: subl $32, %esp Entiéndo que el 32 sale de los 4 parámetros que se le pasa a la funcion (4x3) + los 20 bytes de los buffers, no? De ser así el puntero int ret, no ocupa memoria? Gracias! 
|
|
|
|
|
En línea
|
|
|
|
|
ghastlyX
|
Gracias! Se me había pasado crear el archivo .s y mirar el código ahí... Lo que hacía era de memoria sumar las variables. Esto es algo que no entiendo, si tenemos esto:
12 bytes [buffer2] 8 bytes [buffer1] 4 bytes [@EBPret]
Si el puntero ret apunta a buffer1 viéndolo de esta manera serían 12bytes y no 13, no?? De donde sale el byte que falta? O talvez no se puede calcular de esta manera?
Otra cuestión:
Citar subl $32, %esp
Entiéndo que el 32 sale de los 4 parámetros que se le pasa a la funcion (4x3) + los 20 bytes de los buffers, no? De ser así el puntero int ret, no ocupa memoria? Mira, si cambias un poco la función y la dejas así: void f(int a, int b, int c) { char buffer1[5]; char buffer2[10]; int *ret; ret = buffer2; ret = buffer1 + 13; a = 5; b = 7; c = 9; (*ret) += 7; }
El .s queda de la siguiente forma: f: pushl %ebp movl %esp, %ebp subl $32, %esp leal -19(%ebp), %eax movl %eax, -4(%ebp) leal -9(%ebp), %eax addl $13, %eax movl %eax, -4(%ebp) movl $5, 8(%ebp) movl $7, 12(%ebp) movl $9, 16(%ebp) movl -4(%ebp), %eax movl (%eax), %eax leal 7(%eax), %edx movl -4(%ebp), %eax movl %edx, (%eax) leave ret
Aquí puedes ver como queda exactamente el bloque de activación de la función. Tenemos | buffer2 | -19(%EBP) | buffer1 | -9(%EBP) | ret | -4(%EBP) | EBP ant| %EBP | @Ret | 4(%EBP) | a | 8(%EBP) | b | 12(%EBP) | c | 16(%EBP) Un saludo de ghastlyX 
|
|
|
|
|
En línea
|
|
|
|
|
|
|
|