Quella vista nell’attacco di questo livello è una iniezione di libreria (library injection). Nel mondo Windows è conosciuta con il nome di DDL Injection. Le DLL Injection sono alla base di quasi tutti i meccanismi di esecuzione fraudolenta di codice arbitrario (spesso nascondendosi dietro binari innocenti).
Analizzando il codice sorgente del binario /home/flag13/flag13 si può notare che:
FAKEUID (1000) si esce con un messaggio di erroreflag13È anche possibile capirlo dal solo output del binario, che segnala che l’id dell’utente che ha eseguito al binario è diverso da 1000 (eccessiva verbosità output).
Possiamo dedurre quindi che si tratta di un debolissimo meccanismo di autenticazione, per due ragioni:
In questo modo un attaccante conosce il fattore e può facilmente provare ad impersonificare l’utente con lo user ID richiesto per autenticarsi.
Si tratta di un’iniezione, ma molto ben nascosta.
Si studia il sistema, partendo dalle variabili d’ambiente:
man environ
Dall’introduzione si scopre che:
<aside> 📑
LD_LIBRARY_PATH, LD_PRELOAD and other LD_ variables influence the behavior of the dynamic loader/linker.*
</aside>
In breve, alcune variabili d’ambiente possono influenzare il comportamento del linker dinamico.
Nella sezione BUGS è anche abbozzato un possibile attacco mediante sfruttamento proprio della variabile d’ambiente LD_LIBRARY_PATH.
Ma cos’è questo linker dinamico? Si interroga il manuale UNIX con la parola chiave linker.
apropos linker
Si ottengono alcune pagine proprio riguardanti dynamic linker/loader, che sono: ld-linux, ld-linux.so, ld.so, tutte nella sezione 8. (Che in realtà puntano tutti alla stessa pagina di manuale).
Si analizza la pagina di manuale:
man ld.so
Nella lista ENVIRON troviamo la spiegazione delle due variabili d’ambiente viste prima LD_LIBRARY_PATH e LD_PRELOAD. La seconda in particolare, contiene una lista di librerie condivise ELF separate da spazio, definite dall’utente, che saranno collegate prima di tutte le altre. Lo scopo è quello di fare override dinamicamente di funzioni in altre shared libraries, senza dover ricompilare i sorgenti.
<aside> 📑
LD_PRELOAD A whitespace-separated list of additional, user-specified, ELF shared libraries to be loaded before all others. This can be used to selectively override functions in other shared libraries.
</aside>
Può essere definita per un singolo comando o per una sessione di terminale:
LD_PRELOAD=/path/to/lib.so <command>
export LD_PRELOAD=/path/to/lib.so
L’idea è quella di usare la variabile LD_PRELOAD per caricare in anticipo una libreria condivisa che implementa la funzione di controllo degli accessi del programma flag13 → getuid() (la libreria condivisa va scritta da zero e compilata).
Si scrive un programma getuid.c. L’idea è quella di fare ritornare sempre 1000. Molto semplice.
#include <unistd.h>
#include <sys/types.h>
uid_t getuid(void) {
return 1000;
}
Per generare la libreria condivisa si usa gcc con le opzioni:
gcc -shared -fPIC -o getuid.so getuid.c
Si lancia di nuovo il binario precaricando la libreria getuid.so:
LD_PRELOAD=./getuid.so /home/flag13/flag13
L’attacco non va a buon fine. Cosa non ha funzionato?
Si studia più approfonditamente la pagine di manuale relativa a ld.so. Si scopre che per i binari SETUID/SETGID, solo le librerie nelle standard search directories che sono anche SETGID **saranno caricate.
<aside> 📑
LD_PRELOAD For setuid/setgid ELF binaries, only libraries in the standard search directories that are also setgid will be loaded.
</aside>
Quindi, se l’eseguibile è SETUID deve esserlo anche la libreria condivisa.
Dunque l’iniezione di una libreria funziona solo se il binario e la libreria condivisa hanno lo stesso tipo di privilegi:
Cosa si può fare:
cp /home/flag13/flag13 /home/level13
ls -l /home/level13
Il binario non ha più il bit SETUID.
Si esegue di nuovo il binario precaricando la libreria:
LD_PRELOAD=./getuid.so ./flag13
Si ottiene così il token dell’utente → Attacco riuscito.