Zoom Icon

Intercettare con LD PRELOAD

From UIC


This page has been translated to English Image:Flag uk.gif.

Intercettare con LD_PRELOAD

Contents


Infos
Author: Bender0
Email: Image:Mips-email.png
Website: http://mips42.altervista.org/
Date: 10/08/2007 (dd/mm/yyyy)
Level: Some skills are required
Language: Italian Image:Flag_Italian.gif
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:

$ man ls.so
[...]
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ì:

$ ./target

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:

$ VARIABILE=valore ./target

Se infine vogliamo usare LD_PRELOAD per far caricare la nostra libreria libfake.so, sempre contenuta nella cartella corrente, daremo il seguente comando:

$ LD_PRELOAD=./libfake.so ./target

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:

// target.c
&#35;include <stdio.h>
&#35;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:

$ ./target
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:

// libfake.c

int getuid() {
return 0;
}

Come vedete, ancora tutto molto semplice. Compiliamo questo sorgente come libreria condivisa, in questo modo:

$ gcc -shared libfake.c -o libfake.so

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:

$ LD_PRELOAD=./libfake.so ./target
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 malevoli 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.