Intercettare con LD PRELOAD
From UIC
Intercettare con LD_PRELOAD
Contents |
| Intercettare con LD PRELOAD | |
|---|---|
| Author: | Bender0 |
| Email: | |
| Website: | http://mips42.altervista.org/ |
| Date: | 10/08/2007 (dd/mm/yyyy) |
| Level: |
|
| Language: | Italian |
| Comments: | Semplice e utile. |
Introduction
Salve :)
In questo (breve) essay studiamo come fare ad intercettare/rimpiazzare chiamate a funzioni di libreria utilizzando la variabile d'ambiente LD_PRELOAD e la nostra libreria fatta ad arte. È una cosa molto semplice che però può tornare utile.
Attenti: so già quello che alcuni di voi staranno pensando, ebbene non si può usare questa tecnica con binari setuid o setgid, a meno che...
Inoltre, ma dovrebbe essere ovvio, questa tecnica si può applicare solo agli eseguibili linkati dinamicamente.
Tools
Useremo solo gcc, che dovrebbe essere presente in ogni distro linux che si rispetti. Se non ci dovesse essere scaricate i pacchetti necessari, o fate fare un bel volo fuori dalla finestra al cd/dvd della distro (non fatelo in aereo però!).
Link e Riferimenti
Se vi serve qualche informazione preliminare di contorno, troverete una piacevole lettura l'articolo di Wikipedia sulle librerie software.
Essay
Teoria
Per prima cosa diamo un'occhiata a cosa il manuale ha da dire in merito:
[...]
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.
[...]
Dice che è una lista di liberie condivise (shared libraries) che verranno caricate prima di tutte le altre, e che questo può essere usato per sostituire certe nostre funzioni a quelle di altre librerie. Detto in modo più semplice, quando un programma lanciato con LD_PRELOAD chiama una funzione X, se è presente una funzione di nome X nelle librerie che abbiamo specificato noi verrà chiamata quella, altrimenti verrà cercata nel solito modo.
Vediamo come si fa in pratica. Supponiamo di avere un programma nella cartella corrente che si chiama target. Normalmente lo eseguiremmo così:
Ma noi dobbiamo assegnare un certo valore a una variabile d'ambiente (in questo esempio assegnamo valore a VARIABILE), e ci interessa che questa variabile abbia quel valore solo durante l'esecuzione di target. Possiamo farlo in questo modo:
Se infine vogliamo usare LD_PRELOAD per far caricare la nostra libreria libfake.so, sempre contenuta nella cartella corrente, daremo il seguente comando:
Pratica
Anche se questo potrebbe bastare, facciamo un piccolo esempio per rendere il tutto molto più chiaro. Supponiamo che il nostro target sia stato compilato dinamicamente e che il suo codice sia il seguente:
#include <stdio.h>
#include <unistd.h>
int main() {
printf( "user id: %d\n", getuid() );
return 0;
}
Come vedete, tutto molto semplice. Il programma stampa l'user id dell'utente che lo ha eseguito. Se eseguo target sul mio sistema ottengo:
user id: 1000
1000 è un tipico user id da utente non privilegiato. Prefiggiamoci lo scopo di far sì che il programma stampi 0 come user id, come se fosse stato eseguito dall'utente root.
Per fare ciò creiamo una piccola libreria che implementa la funzione getuid() e che ritorna sempre 0:
int getuid() {
return 0;
}
Come vedete, ancora tutto molto semplice. Compiliamo questo sorgente come libreria condivisa, in questo modo:
A questo punto siamo pronti per assegnare a LD_PRELOAD la locazione dove si trova la nostra libreria libfake.so, se anch'essa si trova nella cartella corrente ecco come si esegue e cosa succede:
user id: 0
Beh, direi che ce l'abbiamo fatta, e che non è stato affatto difficile :)
Uh, avevo lasciato un "a meno che..." in sospeso. Beh, finiva così:
... la libreria da precaricare non si trovi nelle cartelle standard di ricerca (come /usr/lib) e abbia anch'essa il bit setuid.
Quindi, buon divertimento.
Se volete sapere come fare la stessa cosa anche con eseguibili linkati staticamente, credo vi interesserà questo essay.
Note Finali
Mi pare che questo sia il primo essay creato nella sezione linux. Speriamo non sia l'ultimo :)
Ringrazio tutta la gentaglia della UIC, come al solito :)
Ci vediamo al prossimo essay... bye.
Disclaimer
I documenti qui pubblicati sono da considerarsi pubblici e liberamente distribuibili, a patto che se ne citi la fonte di provenienza. Tutti i documenti presenti su queste pagine sono stati scritti esclusivamente a scopo di ricerca, nessuna di queste analisi è stata fatta per fini commerciali, o dietro alcun tipo di compenso. I documenti pubblicati presentano delle analisi puramente teoriche della struttura di un programma, in nessun caso il software è stato realmente disassemblato o modificato; ogni corrispondenza presente tra i documenti pubblicati e le istruzioni del software oggetto dell'analisi, è da ritenersi puramente casuale. Tutti i documenti vengono inviati in forma anonima ed automaticamente pubblicati, i diritti di tali opere appartengono esclusivamente al firmatario del documento (se presente), in nessun caso il gestore di questo sito, o del server su cui risiede, può essere ritenuto responsabile dei contenuti qui presenti, oltretutto il gestore del sito non è in grado di risalire all'identità del mittente dei documenti. Tutti i documenti ed i file di questo sito non presentano alcun tipo di garanzia, pertanto ne è sconsigliata a tutti la lettura o l'esecuzione, lo staff non si assume alcuna responsabilità per quanto riguarda l'uso improprio di tali documenti e/o file, è doveroso aggiungere che ogni riferimento a fatti cose o persone è da considerarsi PURAMENTE casuale. Tutti coloro che potrebbero ritenersi moralmente offesi dai contenuti di queste pagine, sono tenuti ad uscire immediatamente da questo sito.
Vogliamo inoltre ricordare che il Reverse Engineering è uno strumento tecnologico di grande potenza ed importanza, senza di esso non sarebbe possibile creare antivirus, scoprire funzioni malevole e non dichiarate all'interno di un programma di pubblico utilizzo. Non sarebbe possibile scoprire, in assenza di un sistema sicuro per il controllo dell'integrità, se il "tal" programma è realmente quello che l'utente ha scelto di installare ed eseguire, né sarebbe possibile continuare lo sviluppo di quei programmi (o l'utilizzo di quelle periferiche) ritenuti obsoleti e non più supportati dalle fonti ufficiali.