Buffer Overflow Stack Attack Guida in linea

1

Quindi sto cercando di completare un esercizio di overflow del buffer. Il codice che sto cercando di sfruttare è sotto. Quello che voglio essere in grado di fare è inserire la mia dichiarazione di stampa attraverso l'attacco di overflow. Quello che mi piacerebbe fare è eseguire l'attacco con $ cat file | code.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; }

So che l'attacco sarebbe avvenuto nel "target char [INPUT_BUFFER];" punto. Se mettiamo per esempio 257 'a' genererebbe un BOF.

Lo smontaggio al momento attuale è simile a questo.

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

Lo stack senza il buffer riempito assomiglia a questo.

#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 il buffer riempito, sembra così.

#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; }

So che questo attacco funziona, ho bisogno di lavorare per sovrascrivere un indirizzo di ritorno, e poi inserire il mio codice shell qui.

Ho messo quello che penso sarebbe il carico utile del codice shell in GDB e ho ottenuto una rappresentazione dello shellcode di esso.

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

Come faccio a prendere questo shellcode e renderlo un exploit? Immagino di essere confuso su dove inserirlo e come farlo funzionare naturalmente. Fammi sapere se vedi qualcosa, o se puoi darmi qualche suggerimento utile nella giusta direzione.

Grazie.

    
posta Joe Hopper 28.04.2018 - 21:05
fonte

2 risposte

0

Mentre questa è generalmente una domanda piuttosto ampia, proverò a rispondere in un approccio generale:

Se hai disattivato i soliti sospetti (stack canaries, ASLR, no-exec-bit, ...), l'approccio generale è il seguente:

Controlla lo spazio che devi riempire prima che il buffer superi e riempia quello spazio con input arbitrari (personalmente preferisco i NOP per creare una diapositiva NOP, per ogni evenienza).

Assicurati di avere il tuo carico utile alla fine di quella diapositiva NOP e prima di sovrascrivere l'indirizzo di ritorno.

Ad esempio, se l'indirizzo di ritorno è l'ultimo 4 byte di 1000 byte e il payload è 100 byte, si inseriscono 896 NOP seguiti dal payload, seguito da un indirizzo all'interno della diapositiva NOP.

Puoi cercare il valore esadecimale per l'architettura che stai utilizzando online.

Personalmente mi piace:

  • usa python per generare l'input richiesto o
  • scrivi manualmente i valori esadecimali in un file di testo e genera un binario che può essere alimentato come input come hai descritto usando cat e pipe.

Per utilizzare la seconda opzione come richiesto, puoi generare il file binario necessario usando

xxd -r -p textfile > file

Dove textfile è il tuo file contenente una stringa di valori esadecimali come

 aaaaaaaaaaaaaaaff25…
    
risposta data 28.04.2018 - 21:44
fonte
0

Ogni volta che stai pensando di eseguire un overflow del buffer, devi prima pensare a controllare il puntatore di esecuzione (EIP / RIP).

Il puntatore dell'esecuzione viene salvato nello stack frame ogni volta che viene eseguita una funzione. Quando la funzione ritorna, recupera il puntatore di esecuzione dallo stack e riprende l'esecuzione (ce ne sono di più, ma sto semplificando eccessivamente in modo da poter ottenere l'idea generale)

Non puoi guardare nello stack da solo. È necessario esaminare i registri: puntatore dello stack, puntatore di base e puntatore di istruzioni. Questo ti dirà se hai superato con successo EIP e con i valori attesi.

Inoltre, è necessario sovrascrivere EIP con l'indirizzo del payload, ma per farlo è necessario sapere dove si trova il proprio carico utile. In questo caso, poiché è un semplice overflow del buffer, è in pila. Tuttavia, è necessario conoscere in anticipo l'indirizzo dello stack OPPURE cercare un'istruzione ESP JMP nel codice e puntare a EIP lì.

Quindi in sintesi:

  • Controllo EIP
  • Fai in modo che il punto EIP impili
  • Aggiungi il carico utile rimanente allo stack
risposta data 29.04.2018 - 09:22
fonte

Leggi altre domande sui tag