Linux Kernel ROP - Ritornare in userland dal contesto del kernel?

5

Ho un modulo vulnerabile del kernel di Linux (32-bit), che posso sfruttare con successo, e ho ottenuto privilegi da esso. Fondamentalmente, il mio exploit utilizza una catena ROP per disabilitare SMEP e salta direttamente al mio shellcode mappato su userland. Il mio codice shell in userland effettua una chiamata a commit_creds(prepare_kernel_creds(0)); e prova a tornare al mio codice userland.

Ora non capisco come tornare alla modalità utente dalla modalità kernel. Diversi articoli sottolineano che dovrei usare iret istruzioni di assemblaggio per tornare alla modalità utente. Ho inserito un iret dopo lo shellcode, ma non sembra funzionare.

Scrivo su un file del dispositivo e dalla traccia della chiamata:

? vfs_write
? SyS_write
? do_fast_syscall_32
? entry_SYSENTER_32

Prendo atto che si tratta di una chiamata di sistema veloce e che deve ritornare attraverso l'istruzione sysexit .

Ora, come posso tornare su userland senza mettere nel panico il kernel? Ho bisogno di sapere quale chiamata devo eseguire ( iret / sysexit ) e come eseguirla in modo pulito.

(Ho dato un'occhiata ai manuali di Intel e ad un sacco di altre risorse, ma nulla mi ha aiutato molto fino ad ora.)

    
posta Mukesh Sai Kumar 11.01.2018 - 13:27
fonte

2 risposte

4

Ho finito per scrivere il mio shellcode in un modo diverso. Dato che non riuscivo a capire come tornare, lasciai che il kernel facesse il lavoro pesante per me, tornando negli Stati Uniti. L'idea era di eseguire il mio bit di escalation dei privilegi e tornare al punto in cui la funzione vulnerabile doveva tornare, con i registri e lo stack riparati.

Non appena il kernel è tornato dalla funzione vulnerabile (quando non era in overflow), ho notato qualcosa tramite gdb . (Gli indirizzi sono immaginari, ma comunque spiega 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, immediatamente dopo il ritorno, 0x40 byte di stack non usati e svanirebbe semplicemente con l'istruzione add esp . Così, sfruttando questo fatto, ho costruito una catena ROP (l'avevo già costruita mentre scrivevo questa domanda, il suo compito era disabilitare SMEP e passare al mio shellcode userland), che era lungo 24 byte. 4 byte sovrascriverebbero l'EIP al momento del ritorno, e il restante 20 ( 0x14 ) lo seguirà a destra nello stack inutilizzato. Questo ci lascia ancora con 0x2c byte di stack inutilizzato.

Ma se tornassimo a 0xadd2 , rischieremmo di perdere altri 0x14 byte di preziose informazioni di registro dallo stack e di riempire i registri con dati non validi. Potremmo add 0x2c a esp nel nostro codice shell userland e passare direttamente a 0xadd3 , saltando l'effettiva add dell'istruzione.

Notando anche dalla sessione di debug, tutto tranne eax e ebx sono stati ripristinati correttamente. Dato che il mio overflow li aveva eliminati entrambi, dovevo ripristinarli con valori simili ai casi in cui la funzione rendeva un ritorno pulito. (Facendo questo è stato semplice: ho impostato un breakpoint a 0xadd2 e ho estratto i valori da info reg )

Quindi, il mio shellcode userland finale era questo:

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

Facendo questo, il percorso del codice è tornato perfettamente pulito e il kernel ha fatto il salto indietro in modalità utente per me.

    
risposta data 22.01.2018 - 17:44
fonte
-1

Leggete su call_usermodehelper_setup () e call_usermodehelper_exec (). Usando queste chiamate puoi eseguire il codice direttamente dal kernel.

Esempio:

link

    
risposta data 11.01.2018 - 19:57
fonte

Leggi altre domande sui tag