Ayuda de ejercicios de ataque de pila de desbordamiento de búfer

1

Así que estoy tratando de completar un ejercicio de desbordamiento de búfer. El código que estoy tratando de explotar está abajo. Lo que quiero poder hacer es insertar mi propia declaración de impresión a través del ataque de desbordamiento. Lo que me gustaría hacer es ejecutar el ataque a través de $ cat file | código.c

#include <stdio.h>
#include <string.h>
#define INPUT_BUFFER 256 /* maximum name size */
/*
* read input, copy into s
*/
void getl(char *s)
{
    int c;
    while ((c=getchar()) != EOF)
        *s++ = c;
        *s = '
   0x0000000000400673 <+0>:     push   %rbp
   0x0000000000400674 <+1>:     mov    %rsp,%rbp
   0x0000000000400677 <+4>:     sub    $0x100,%rsp
=> 0x000000000040067e <+11>:    lea    -0x100(%rbp),%rax
   0x0000000000400685 <+18>:    mov    %rax,%rdi
   0x0000000000400688 <+21>:    callq  0x4005ed <getline>
   0x000000000040068d <+26>:    lea    -0x100(%rbp),%rax
   0x0000000000400694 <+33>:    mov    %rax,%rdi
   0x0000000000400697 <+36>:    callq  0x4004b0 <strlen@plt>
   0x000000000040069c <+41>:    cmp    $0xff,%rax
   0x00000000004006a2 <+47>:    ja     0x4006cc <main+89>
   0x00000000004006a4 <+49>:    lea    -0x100(%rbp),%rax
   0x00000000004006ab <+56>:    mov    %rax,%rdi
   0x00000000004006ae <+59>:    callq  0x400623 <removenewlines>
   0x00000000004006b3 <+64>:    lea    -0x100(%rbp),%rax
   0x00000000004006ba <+71>:    mov    %rax,%rsi
   0x00000000004006bd <+74>:    mov    $0x400764,%edi
   0x00000000004006c2 <+79>:    mov    $0x0,%eax
   0x00000000004006c7 <+84>:    callq  0x4004c0 <printf@plt>
   0x00000000004006cc <+89>:    mov    $0x0,%eax
   0x00000000004006d1 <+94>:    leaveq 
   0x00000000004006d2 <+95>:    retq  
'; } void removenl(char *s) { int l; l = strlen(s); while (l--) if (s[l] == '\n') s[l] = '
0x7fffffffded0: 0xf7ffe1c8      0x00007fff      0xf7de4961      0x00007fff
0x7fffffffdee0: 0x00000000      0x00000000      0xf7ff7a10      0x00007fff
0x7fffffffdef0: 0x00000001      0x00000000      0x00000000      0x00000000
0x7fffffffdf00: 0x00000001      0x00007fff      0xf7ffe1c8      0x00007fff
0x7fffffffdf10: 0x00000000      0x00000000      0x00000000      0x00000000
0x7fffffffdf20: 0x00000000      0x00000000      0x00000000      0x00000000
0x7fffffffdf30: 0x00000000      0x00000000      0xf7ffe520      0x00007fff
0x7fffffffdf40: 0xffffdf70      0x00007fff      0xffffdf60      0x00007fff
0x7fffffffdf50: 0xf63d4e2e      0x00000000      0x00400391      0x00000000
0x7fffffffdf60: 0xffffffff      0x00000000      0xffffe0c8      0x00007fff
0x7fffffffdf70: 0xf7a251f8      0x00007fff      0xf7ff74c0      0x00007fff
0x7fffffffdf80: 0xf7ffe1c8      0x00007fff      0x00000000      0x00000000
0x7fffffffdf90: 0x00000001      0x00000000      0x0040072d      0x00000000
0x7fffffffdfa0: 0xffffdfd0      0x00007fff      0x00000000      0x00000000
0x7fffffffdfb0: 0x004006e0      0x00000000      0x00400500      0x00000000
0x7fffffffdfc0: 0xffffe0b0      0x00007fff      0x00000000      0x00000000
0x7fffffffdfd0: 0x00000000      0x00000000      0xf7a36f45      0x00007fff
0x7fffffffdfe0: 0x00000000      0x00000000      0xffffe0b8      0x00007fff
0x7fffffffdff0: 0x00000000      0x00000001      0x00400673      0x00000000
0x7fffffffe000: 0x00000000      0x00000000      0x5f571179      0x81bce2d3
0x7fffffffe010: 0x00400500      0x00000000      0xffffe0b0      0x00007fff
'; } int main() { char target[INPUT_BUFFER]; getl(target); if (strlen(target) < INPUT_BUFFER) { removenl(victim); printf("%s is the target\n", target); } return 0; }

Sé que el ataque ocurriría en el "objetivo de char [INPUT_BUFFER];" punto. Si ponemos por ejemplo 257 'a' se generaría un BOF.

El desmontaje en el momento actual se ve así.

0x7fffffffded0: 0x61616161      0x61616161      0x61616161      0x61616161
0x7fffffffdee0: 0x61616161      0x61616161      0x61616161      0x61616161
0x7fffffffdef0: 0x61616161      0x61616161      0x61616161      0x61616161
0x7fffffffdf00: 0x61616161      0x61616161      0x61616161      0x61616161
0x7fffffffdf10: 0x61616161      0x61616161      0x61616161      0x61616161
0x7fffffffdf20: 0x61616161      0x61616161      0x61616161      0x61616161
0x7fffffffdf30: 0x61616161      0x61616161      0x61616161      0x61616161
0x7fffffffdf40: 0x61616161      0x61616161      0x61616161      0x61616161
0x7fffffffdf50: 0x61616161      0x61616161      0x61616161      0x61616161
0x7fffffffdf60: 0x61616161      0x61616161      0x61616161      0x61616161
0x7fffffffdf70: 0x61616161      0x61616161      0x61616161      0x61616161
0x7fffffffdf80: 0x61616161      0x61616161      0x61616161      0x61616161
0x7fffffffdf90: 0x61616161      0x61616161      0x61616161      0x61616161
0x7fffffffdfa0: 0x61616161      0x61616161      0x61616161      0x61616161
0x7fffffffdfb0: 0x61616161      0x61616161      0x61616161      0x61616161
0x7fffffffdfc0: 0x61616161      0x61616161      0x61616161      0x37636161
0x7fffffffdfd0: 0x30343630      0x00003030      0xf7a36f45      0x00007fff
0x7fffffffdfe0: 0x00000000      0x00000000      0xffffe0b8      0x00007fff
0x7fffffffdff0: 0x00000000      0x00000001      0x00400673      0x00000000
0x7fffffffe000: 0x00000000      0x00000000      0x5f571179      0x81bce2d3
0x7fffffffe010: 0x00400500      0x00000000      0xffffe0b0      0x00007fff

La pila sin el búfer lleno se ve así.

#include <stdio.h>
void main() {
    printf("Now i've pwn your computer");
    return 0;
}



\xff\x25\x12\x0c\x20\x00\x68\x00\x00\x00\x00\xe9\xe0\xff\xff\xff\x55\x48\x89\xe5\xbf\xa4\x05\x40\x00\xb8\x00\x00\x00\x00\xe8\xe6\xfe\xff\xff\x90\x5d\xc3\x0f\x1f\x00

Con el búfer lleno, se ve así.

#include <stdio.h>
#include <string.h>
#define INPUT_BUFFER 256 /* maximum name size */
/*
* read input, copy into s
*/
void getl(char *s)
{
    int c;
    while ((c=getchar()) != EOF)
        *s++ = c;
        *s = '
   0x0000000000400673 <+0>:     push   %rbp
   0x0000000000400674 <+1>:     mov    %rsp,%rbp
   0x0000000000400677 <+4>:     sub    $0x100,%rsp
=> 0x000000000040067e <+11>:    lea    -0x100(%rbp),%rax
   0x0000000000400685 <+18>:    mov    %rax,%rdi
   0x0000000000400688 <+21>:    callq  0x4005ed <getline>
   0x000000000040068d <+26>:    lea    -0x100(%rbp),%rax
   0x0000000000400694 <+33>:    mov    %rax,%rdi
   0x0000000000400697 <+36>:    callq  0x4004b0 <strlen@plt>
   0x000000000040069c <+41>:    cmp    $0xff,%rax
   0x00000000004006a2 <+47>:    ja     0x4006cc <main+89>
   0x00000000004006a4 <+49>:    lea    -0x100(%rbp),%rax
   0x00000000004006ab <+56>:    mov    %rax,%rdi
   0x00000000004006ae <+59>:    callq  0x400623 <removenewlines>
   0x00000000004006b3 <+64>:    lea    -0x100(%rbp),%rax
   0x00000000004006ba <+71>:    mov    %rax,%rsi
   0x00000000004006bd <+74>:    mov    $0x400764,%edi
   0x00000000004006c2 <+79>:    mov    $0x0,%eax
   0x00000000004006c7 <+84>:    callq  0x4004c0 <printf@plt>
   0x00000000004006cc <+89>:    mov    $0x0,%eax
   0x00000000004006d1 <+94>:    leaveq 
   0x00000000004006d2 <+95>:    retq  
'; } void removenl(char *s) { int l; l = strlen(s); while (l--) if (s[l] == '\n') s[l] = '
0x7fffffffded0: 0xf7ffe1c8      0x00007fff      0xf7de4961      0x00007fff
0x7fffffffdee0: 0x00000000      0x00000000      0xf7ff7a10      0x00007fff
0x7fffffffdef0: 0x00000001      0x00000000      0x00000000      0x00000000
0x7fffffffdf00: 0x00000001      0x00007fff      0xf7ffe1c8      0x00007fff
0x7fffffffdf10: 0x00000000      0x00000000      0x00000000      0x00000000
0x7fffffffdf20: 0x00000000      0x00000000      0x00000000      0x00000000
0x7fffffffdf30: 0x00000000      0x00000000      0xf7ffe520      0x00007fff
0x7fffffffdf40: 0xffffdf70      0x00007fff      0xffffdf60      0x00007fff
0x7fffffffdf50: 0xf63d4e2e      0x00000000      0x00400391      0x00000000
0x7fffffffdf60: 0xffffffff      0x00000000      0xffffe0c8      0x00007fff
0x7fffffffdf70: 0xf7a251f8      0x00007fff      0xf7ff74c0      0x00007fff
0x7fffffffdf80: 0xf7ffe1c8      0x00007fff      0x00000000      0x00000000
0x7fffffffdf90: 0x00000001      0x00000000      0x0040072d      0x00000000
0x7fffffffdfa0: 0xffffdfd0      0x00007fff      0x00000000      0x00000000
0x7fffffffdfb0: 0x004006e0      0x00000000      0x00400500      0x00000000
0x7fffffffdfc0: 0xffffe0b0      0x00007fff      0x00000000      0x00000000
0x7fffffffdfd0: 0x00000000      0x00000000      0xf7a36f45      0x00007fff
0x7fffffffdfe0: 0x00000000      0x00000000      0xffffe0b8      0x00007fff
0x7fffffffdff0: 0x00000000      0x00000001      0x00400673      0x00000000
0x7fffffffe000: 0x00000000      0x00000000      0x5f571179      0x81bce2d3
0x7fffffffe010: 0x00400500      0x00000000      0xffffe0b0      0x00007fff
'; } int main() { char target[INPUT_BUFFER]; getl(target); if (strlen(target) < INPUT_BUFFER) { removenl(victim); printf("%s is the target\n", target); } return 0; }

Sé que para hacer que este ataque funcione, necesito trabajar para sobrescribir una dirección de retorno, y luego poner mi propio código de shell allí.

He puesto lo que creo que sería la carga útil de shellcode en GDB y obtuve una representación de shellcode de la misma.

0x7fffffffded0: 0x61616161      0x61616161      0x61616161      0x61616161
0x7fffffffdee0: 0x61616161      0x61616161      0x61616161      0x61616161
0x7fffffffdef0: 0x61616161      0x61616161      0x61616161      0x61616161
0x7fffffffdf00: 0x61616161      0x61616161      0x61616161      0x61616161
0x7fffffffdf10: 0x61616161      0x61616161      0x61616161      0x61616161
0x7fffffffdf20: 0x61616161      0x61616161      0x61616161      0x61616161
0x7fffffffdf30: 0x61616161      0x61616161      0x61616161      0x61616161
0x7fffffffdf40: 0x61616161      0x61616161      0x61616161      0x61616161
0x7fffffffdf50: 0x61616161      0x61616161      0x61616161      0x61616161
0x7fffffffdf60: 0x61616161      0x61616161      0x61616161      0x61616161
0x7fffffffdf70: 0x61616161      0x61616161      0x61616161      0x61616161
0x7fffffffdf80: 0x61616161      0x61616161      0x61616161      0x61616161
0x7fffffffdf90: 0x61616161      0x61616161      0x61616161      0x61616161
0x7fffffffdfa0: 0x61616161      0x61616161      0x61616161      0x61616161
0x7fffffffdfb0: 0x61616161      0x61616161      0x61616161      0x61616161
0x7fffffffdfc0: 0x61616161      0x61616161      0x61616161      0x37636161
0x7fffffffdfd0: 0x30343630      0x00003030      0xf7a36f45      0x00007fff
0x7fffffffdfe0: 0x00000000      0x00000000      0xffffe0b8      0x00007fff
0x7fffffffdff0: 0x00000000      0x00000001      0x00400673      0x00000000
0x7fffffffe000: 0x00000000      0x00000000      0x5f571179      0x81bce2d3
0x7fffffffe010: 0x00400500      0x00000000      0xffffe0b0      0x00007fff

¿Cómo tomo este código de shell y lo convierto en un exploit? Creo que estoy confundido sobre dónde ingresarlo y cómo hacer que el programa lo ejecute naturalmente. Avíseme si ve algo o si puede darme algunos consejos útiles en la dirección correcta.

Gracias.

    
pregunta Joe Hopper 28.04.2018 - 21:05
fuente

2 respuestas

0

Aunque esta es generalmente una pregunta bastante amplia, intentaré responder con un enfoque general:

Si inhabilitas a los sospechosos habituales (pila de canarios, ASLR, no-exec-bit, ...), el enfoque general es el siguiente:

Comprueba cuánto espacio tiene que llenar antes de que el búfer se sobrecargue y rellene ese espacio con información arbitraria (personalmente prefiero que los NOP creen una diapositiva NOP, por si acaso).

Asegúrese de tener su carga útil al final de la diapositiva de NOP y antes de sobrescribir la dirección de devolución.

Por ejemplo, si la dirección de retorno son los últimos 4 bytes de 1000 bytes y su carga útil es de 100 bytes, coloca 896 NOP seguidos por su carga útil, seguidos por una dirección dentro de la diapositiva NOP.

Puedes buscar el valor hexadecimal de la arquitectura que estás utilizando en línea.

Personalmente me gusta:

  • use python para generar la entrada requerida o
  • escriba los valores hexadecimales manualmente en un archivo de texto y genere un binario que se pueda ingresar como entrada, como lo describió usando cat y un pipe.

Para usar la segunda opción como solicitó, puede generar el archivo binario necesario usando

xxd -r -p textfile > file

Donde textfile es su archivo que contiene una cadena de valores hexadecimales como

 aaaaaaaaaaaaaaaff25…
    
respondido por el Tobi Nary 28.04.2018 - 21:44
fuente
0

Siempre que esté pensando en ejecutar un desbordamiento de búfer, primero debe pensar en cómo controlar el puntero de ejecución (EIP / RIP).

El puntero de ejecución se guarda en el marco de la pila cada vez que se ejecuta una función. Cuando la función regresa, recupera el puntero de ejecución de la pila y reanuda la ejecución (hay más, pero estoy simplificando demasiado para que pueda obtener la idea general)

No puedes mirar la pila solo. Debe mirar en los registros: puntero de pila, puntero de base y puntero de instrucciones. Esto le dirá si anuló con éxito el EIP y con los valores esperados.

Además, debe anular EIP con la dirección de su carga útil, pero para hacer eso necesita saber dónde está su carga útil. En este caso, ya que se trata de un simple desbordamiento de búfer, está en la pila. Sin embargo, debe saber de antemano la dirección de la pila O BIEN buscar una instrucción JMP ESP en el código y señalar el EIP allí.

Así que en resumen:

  • Control EIP
  • Haga que el punto EIP se apile
  • Agregar la carga útil restante a la pila
respondido por el Filipe Rodrigues 29.04.2018 - 09:22
fuente

Lea otras preguntas en las etiquetas