GNU/Linux >> Linux Esercitazione >  >> Linux

Linux Kernel ROP - Ritorno a userland dal contesto del kernel?

Ho finito per scrivere il mio shellcode in un modo diverso. Poiché non riuscivo a capire come tornare, ho lasciato che il kernel facesse il lavoro pesante per me, tornando in userland. L'idea era di eseguire il mio bit di escalation dei privilegi e tornare al punto in cui la funzione vulnerabile avrebbe dovuto tornare, con i registri e lo stack sistemati.

Non appena il kernel è tornato dalla funzione vulnerabile (quando non era in overflow), ho notato qualcosa tramite gdb . (Gli indirizzi sono immaginari, ma spiegano comunque il concetto.)

(gdb) x/i $eip
0xadd1: ret
(gdb) x/xw $esp
0xadd1: 0xadd2
(gdb) x/6i 0xadd2
0xadd2: add esp,0x40
0xadd3: pop ...
0xadd4: pop ...
0xadd5: pop ...
0xadd6: pop ...
0xadd7: ret

Quindi, subito dopo la restituzione, 0x40 byte di stack non vengono utilizzati e svanirebbe semplicemente con il add esp istruzione. Così, approfittando di questo fatto, ho costruito una catena ROP (l'avevo già costruita mentre scrivevo questa domanda, il suo compito era disabilitare SMEP e saltare al mio shellcode userland), che era lunga 24 byte. 4 byte sovrascriverebbero l'EIP al momento della restituzione e i restanti 20 (0x14 ) lo seguirebbe direttamente nello stack inutilizzato. Questo ci lascia con 0x2c byte di stack inutilizzati ancora.

Ma se tornassimo a 0xadd2 , rischieremmo di perdere un ulteriore 0x14 byte di preziose informazioni sui registri dallo stack e riempiendo i registri con dati non validi. Potremmo add 0x2c a esp nel nostro shellcode userland, e salta direttamente a 0xadd3 , saltando l'attuale add istruzioni.

Notando anche dalla sessione di debug, tutto tranne eax e ebx venivano restaurati correttamente. Poiché il mio overflow li aveva cestinati entrambi, ho dovuto ripristinarli con valori simili ai casi in cui la funzione ha restituito un risultato pulito. (Fare questo è stato semplice:ho impostato un punto di interruzione a 0xadd2 , ed ho estratto i valori da info reg )

Quindi, il mio shellcode finale per l'utente era questo:

Execute privesc payload -> add esp,0x2c -> register fixup -> jump to 0xadd3

In questo modo, il percorso del codice è tornato perfettamente pulito e il kernel ha svolto il compito di tornare alla modalità utente per me.


Linux
  1. La mia storia di Linux:dall'appassionato di 8 bit all'amministratore di sistema Unix

  2. Risolvere il problema dell'anno 2038 nel kernel Linux

  3. Driver del dispositivo del kernel Linux a DMA da un dispositivo nella memoria dello spazio utente

  4. Come caricare i moduli del kernel Linux dal codice C?

  5. Perché proteggere il kernel Linux dall'utente root?

Come costruire il kernel Linux da zero {Guida passo passo}

Kernel Linux vs. Kernel Mac

Da un sogno alla realtà:come Linux ha cambiato la mia vita

Lavorare con Microsoft Exchange dal desktop Linux

Come costruire il kernel Linux da zero

Come compilare il kernel Linux dal sorgente per creare un kernel personalizzato