Tengo un problema para desbordar el búfer en un programa c simple que recibe información de la línea de comandos, este es el código main.c:
#include <stdio.h>
#include <string.h>
void func(char *name)
{
char buf[10];
strcpy(buf, name);
}
void chgflow(){
printf("changed flow!!\n");
}
void main(int argc, char *argv[])
{
func(argv[1]);
printf("i should not be viewed if flow is changed\n");
chgflow();
}
esta es la versión de ensamblaje tomada de objdump -d ./main:
<main>:
5a3: 8d 4c 24 04 lea 0x4(%esp),%ecx
5a7: 83 e4 f0 and $0xfffffff0,%esp
5aa: ff 71 fc pushl -0x4(%ecx)
5ad: 55 push %ebp
5ae: 89 e5 mov %esp,%ebp
5b0: 53 push %ebx
5b1: 51 push %ecx
5b2: e8 99 fe ff ff call 450 <__x86.get_pc_thunk.bx>
5b7: 81 c3 49 1a 00 00 add $0x1a49,%ebx
5bd: 89 c8 mov %ecx,%eax
5bf: 8b 40 04 mov 0x4(%eax),%eax
5c2: 83 c0 04 add $0x4,%eax
5c5: 8b 00 mov (%eax),%eax
5c7: 83 ec 0c sub $0xc,%esp
5ca: 50 push %eax
5cb: e8 7d ff ff ff call 54d <func>
5d0: 83 c4 10 add $0x10,%esp
5d3: 83 ec 0c sub $0xc,%esp
5d6: 8d 83 90 e6 ff ff lea -0x1970(%ebx),%eax
5dc: 50 push %eax
5dd: e8 fe fd ff ff call 3e0 <puts@plt>
5e2: 83 c4 10 add $0x10,%esp
5e5: e8 8e ff ff ff call 578 <chgflow>
5ea: 90 nop
5eb: 8d 65 f8 lea -0x8(%ebp),%esp
5ee: 59 pop %ecx
5ef: 5b pop %ebx
5f0: 5d pop %ebp
5f1: 8d 61 fc lea -0x4(%ecx),%esp
5f4: c3 ret
<func>:
54d: 55 push %ebp
54e: 89 e5 mov %esp,%ebp
550: 53 push %ebx
551: 83 ec 14 sub $0x14,%esp
554: e8 9c 00 00 00 call 5f5 <__x86.get_pc_thunk.ax>
559: 05 a7 1a 00 00 add $0x1aa7,%eax
55e: 83 ec 08 sub $0x8,%esp
561: ff 75 08 pushl 0x8(%ebp)
564: 8d 55 ee lea -0x12(%ebp),%edx
567: 52 push %edx
568: 89 c3 mov %eax,%ebx
56a: e8 61 fe ff ff call 3d0 <strcpy@plt>
56f: 83 c4 10 add $0x10,%esp
572: 90 nop
573: 8b 5d fc mov -0x4(%ebp),%ebx
576: c9 leave
577: c3 ret
<chgflow>:
578: 55 push %ebp
579: 89 e5 mov %esp,%ebp
57b: 53 push %ebx
57c: 83 ec 04 sub $0x4,%esp
57f: e8 71 00 00 00 call 5f5 <__x86.get_pc_thunk.ax>
584: 05 7c 1a 00 00 add $0x1a7c,%eax
589: 83 ec 0c sub $0xc,%esp
58c: 8d 90 80 e6 ff ff lea -0x1980(%eax),%edx
592: 52 push %edx
593: 89 c3 mov %eax,%ebx
595: e8 46 fe ff ff call 3e0 <puts@plt>
59a: 83 c4 10 add $0x10,%esp
59d: 90 nop
59e: 8b 5d fc mov -0x4(%ebp),%ebx
5a1: c9 leave
5a2: c3 ret
primero que todo lo ejecuté:
echo 0 > /proc/sys/kernel/randomize_va_space
luego compila main.c:
gcc -m32 -g main.c -o main -fno-stack-protector
cuando la función func
termina, quiero sobrescribir la dirección de ret normal, y apuntando a la función chgflow
, por lo tanto, omitiendo la siguiente instrucción regular:
printf("i should not be viewed if flow is changed\n");
para depurar el main.c e inspeccionar qué direcciones de memoria están en su lugar que ejecuté:
gdb ./main
go
disas main
disas chgflow
y esto es lo que encontré para disas main:
0x565555cb <+40>: call 0x5655554d <func>
0x565555d0 <+45>: add $0x10,%esp
y para chgflow:
Dump of assembler code for function chgflow:
0x56555578 <+0>: push %ebp
Así que puedo entender que:
0x565555d0 <+45>: add $0x10,%esp
es la dirección de retención regular (y la siguiente instrucción) después de que func
termina, y 0x56555578
es la primera instrucción de la función chgflow
. Ahora tengo que inspeccionar el ensamblaje de func
para comprender la cantidad de caracteres A (digamos) que necesito para rellenar la pila; desde esta línea:
564: 8d 55 ee lea -0x12(%ebp),%edx
entiendo que necesito 18Byte + 4 bytes de relleno A para llegar a la dirección Ret. Para confirmar esto lo ejecuté de nuevo:
gdb ./main
break 7
run AAAAAAAAAAAAAAAAAAAAAA
("A" repitió 22 veces)
(gdb) x/s $ebp-18
0xffffd2a6: 'A' <repeats 22 times>
(gdb) x/s $ebp
0xffffd2b8: "AAAA"
(gdb) x/x $ebp+4
0xffffd2bc: 0x00
mi prueba terminó aquí porque no puedo entender por qué (gdb) x/x $ebp+4
que debería ser la dirección Ret, muestra 0x00
como resultado. Esperaba que la dirección de retransmisión no cambiara desde el 0x565555d0
regular. ¡Pero hey! 0x00
debería ser el terminador, ¿no? Así que continué y realicé otra prueba con 21 rellenos "A" y el resultado es correcto esta vez:
(gdb) x/x $ebp+4
0xffffd2bc: 0x565555d0
Mi última necesidad ahora es sobrescribir la dirección de retorno con 0x56555578, que es la dirección de la primera instrucción de la función chgflow
. Realicé la prueba anterior con este reemplazado:
run AAAAAAAAAAAAAAAAAAAAA\x78\x55\x55\x56
("A" se repite 21 veces) pero gdb me dio:
Punto de interrupción 1, func (nombre = 0x35357835) en main.c: 7
y esto es lo que puedo ver en la memoria:
(gdb) x/x $ebp+4
0xffffd2ac: 0x37
(gdb) x/s $ebp+4
0xffffd2ac: "78x55x55x56"
finalmente no pude saltar a chgflow
¿Alguien me puede ayudar con esto? Realmente lo apreciaría. Saludos a Marco