Esecuzione di servizi in ambienti ristretti con OpenBSD


di Lorenzo Martignoni - lorenzo@security.dsi.unimi.it

L'obbiettivo di questo piccolo tutorial e` quello di illustrare la realizzazione di un ambiente "chroot" all'interno del quale è possibile eseguire servizi di rete, testare programmi pericolosi oppure realizzare jail.


Creazione del filesystem

Per prima cosa bisogna creare la root directory che ospiterà il nuovo filesystem.

# mkdir /usr/local/new_root
# ln -s /usr/local/new_root /

Bisogna ora identificare le directory ed i file vitali per il sistema, alcuni file sono strettamente necessari, di altri se ne può fare a meno. Ovviamente il contenuto del chroot varierà in base al tipo di servizio che dovrà essere eseguito al suo interno.

/dev/ questa directory contiene i devices del sistema, bastano quelli elementari
null null device
zero zero device
srandom strong random device
urandom random device

/etc/ contiene i principali file di configurazione del sistema:
passwd elenco degli utenti del sistema (insicuro)
passwd.conf formato del database degli utenti
group i gruppi di utenti
master.passwd elenco degli utenti con le rispettive password (sicuro)
pwd.db database degli account del sistema (insicuro)
spwd.db database degli account del sistema (sicuro)
hosts database degli host
resolv.conf configurazione del resolver degli indirizzi
shells database delle shell del sistema
services elenco delle porte associate ad ogni servizio
protocols elenco dei protocolli di rete supportati dal sistema
i file .db sono in formato binario, vanno quindi generati con un apposito programma
(piu` avanti verra` spiegato come fare)

/bin/ contine i binari necessari all'interno del chroot
false semplicissimo programmino che ritorna sempre 0, verrà usato come shell per gli utenti

/usr/lib/ le librerie dinamiche devo essere in questa directory (la parte di nome del file che segue l'estensione .so indica la versione della libreria e quindi puo` variare in base alla release del sistema)
libc.so.25.2 le libc, le librerie contenente il codice di tutte le chiamate ansi-C eventuali altre librerie richieste dal programma che dovrà essere eseguito nel chroot
/usr/libexec/
ld.so run-time linker, viene utilizzato per linkare gli "oggetti" condivisi all'interno dello spazio di un
processo.

/var/run/ contiene i process-id dei vari processi in esecuzione ed eventualmente il file ld.so.hints che viene
utilizzato per specificare il percorso alternativo delle librerie di sistema
/var/log/ contiene i vari file di log, è necessario se si esegue syslog all'interno del chroot.

/tmp/ directory temporanea, può essere usata da qualche processo per memorizzare dati temporanei
(la sua presenza e` richiesta solo da particolari processi)


Creazione del database degli utenti e dei file di configurazione

Bisogna modificare il file /new_root/etc/master.passwd ed inserire gli account degli utenti presenti all'interno del chroot. Ecco un esempio di file:

# cat etc/master.passwd
root:*:0:0:daemon:0:0:r00t:/:/bin/false
ftp:*:67:67::0:0:ftp server:/ftp:/bin/false

Creare il file dei gruppi /new_root/etc/groups in modo da contenere la definizione dei gruppi elencati nel file /new_root/etc/master.passwd

Ecco un esempio:

# cat etc/groups
wheel:*:0:root
ftp:*:67:

Conviene utilizzare nomi di utenti, di gruppi, uid e gid già presenti nel sistema, in modo da non avere problemi poi con i permessi sui file.

Il file /etc/shells deve contenere la riga /bin/false, in questo modo /bin/false verrà ritenuta una shell valida.

Ora è possibile generare i file .db ovvero i veri database degli account del sistema. Per fare questo è necessario copiare nella directory /new_root/bin il file /usr/sbin/pwd_mkdb, questo file serve appunto per creare i 2 database. Bisogna lanciare il comando all'interno del chroot in modo da avere i path corretti, si può utilizzare un comando del genere:

# chroot /new_root /bin/pwd_mkdb -p /etc/master.passwd

In questo modo il comando pwd_mkdb verrà eseguito nel miniambiente, verrà cosi' letto il file /new_root/etc/master.passwd e saranno creati i file /new_root/etc/pwd.db, /new_root/etc/spwd.db e /new_root/etc/passwd

Ora è possibile cancellare dalla directory /new_root/bin il file pwd_mkdb, in quanto non servirà più.

Rimangono due file da sistemare: /new_root/etc/hosts e /new_root/etc/resolv.conf. Il primo dovrà contenere una riga per ogni host.

Ecco un esempio:

# cat etc/hosts
127.0.0.1 localhost
192.168.132.22 faXe.shadow.net faXe
192.168.132.20 CybOrG.shaDoW.net CybOrG
192.168.132.21 gulliver.shaDoW.net gulliver

L'indirizzo di loopback (127.0.0.1) e della macchina (faXe.shadow.net) sono necessari. Il file resolv.conf dovrà contenere gli indirizzi dei dns server ed il nome del dominio della rete.

Ecco un esempio:

# cat etc/resolv.conf
search shaDoW.net
nameserver 192.168.200.1 # primary dns server
nameserver 192.168.1.20 # secondary dns server

Ultima cosa, i permessi dei file. Tutti i file di /new_root/etc dovranno essere leggibili da tutti tranne
/new_root/etc/master. passwd e /new_root/etc/spwd.db che dovranno essere accessibili solamente dall'utente "root"


Installazione del servizio all'interno del chroot

Ogni servizio richiederà librerie e file di configurazione differenti. Ipotizziamo che il chroot ospiti un server ftp (la versione del server a cui l'esempio fa riferimento è "OpenBSD ftpd versione 6.5").
Il binario del server ftp deve essere installato all'interno del chroot. Successivamente si deve provvedere all'installazione delle librerie dinamiche richieste dal servizio, configurare il servizio ed installare eventuali servizi di appoggio necessari al suo funzionamento.

Installazione del servizio

Basta semplicemente copiare il binario all'interno della directory /bin del chroot.

# cp /usr/libexec/ftpd /new_root/bin

Installazione delle librerie

Il miglior modo per individurare le librerie richieste dal binario, eseguito nel chroot, è quello di usare il comando ldd. Questo comando permette di visualizzare le librerie linkate ad un particolare binario.

# ldd /new_root/bin/ftpd
/new_root/bin/ftpd:
-lskey.1 => /usr/lib/libskey.so.1.0 (0x4002a000)
-lkafs.6 => /usr/lib/libkafs.so.6.0 (0x40031000)
-lkrb.9 => /usr/lib/libkrb.so.9.0 (0x40034000)
-ldes.6 => /usr/lib/libdes.so.6.0 (0x4004d000)
-lwrap.1 => /usr/lib/libwrap.so.1.1 (0x40057000)
-lc.25 => /usr/lib/libc.so.25.2 (0x4005e000)

Tutti i file della directory /usr/lib/ indicati dall'output di "ldd" dovranno essere inclusi nel chroot.

Configurazione del servizio

I file di configurazione devono essere gli stessi usati dal servizio eseguito all'esterno del chroot, ovvero (i path sono relativi a /new_root/):

/etc/ftpusers elenco degli utenti non autorizzati ad accedere al servizio (1)

/etc/ftpchroot se l'utente compare in questo file la sessione ftp sara` eseguita in un ulteriore chroot, la home directory dell'utente (1)

/etc/ftpwelcome messaggio di benvenuto

/etc/motd messaggio di benvenuto visualizzato dopo il login

/etc/nologin messaggio visualizzato in caso di rifiuto dell'accesso


I seguenti file vengono utilizzati dal servizio per tenere traccia del traffico:

/var/run/utmp file contente i dati relativi ai vari login degli utenti (1)

/var/log/ftpd log file usato per registrare i download dell'utente anonimo(1)

Questi file sono necessari solamente se si desidera realizzare un servizio di ftp non anonimo. In questo caso di deve provvedere ad inserire nel database degli utenti un account per ogni utente che dovrà accedere al servizio e si dovrà creare una home directory per ogni utente.

L'output di ldd mostra che il server ftp è stato compilato con il supporto per le librerie "libwrap" che permettono di impostare dei filtri che limitano l'accesso al servizio a particolari indirizzi. Se si desidera impostare filtri di questo genere sarà necessario creare nella directory /etc/ i file hosts.allow e hosts.deny e configurarli a dovere.

L'utente ftp, usato per le connessioni anonime, deve avere una sua home directory, che viene specificata nel file /etc/master.passwd. Sarà necessario crearla e renderla di proprietà dell'utente ftp, ricordandosi di togliere i permessi in scrittura, altrimenti gli utenti anonimi saranno in grado di effettuare upload.

Installazione dei binari di appoggio

Il server ftp può essere lanciato come servizio stand alone oppure dal superserver inetd.
In questo esempio il server ftp verrà lanciato tramite inetd.

Sostanzialmente si tratta di ripetere i passi eseguiti in precedenza in modo da avere un nuovo binario eseguibile all'interno del chroot. E' necessario copiare nel chroot il binario di inetd, le librerie richieste per il suo funzionamento ed il suo file di configurazione.

Il file /usr/sbin/inetd deve essere copiato nella directory dei binari del chroot, mentre le librerie richieste dovranno stare in /usr/lib.

# ldd /new_root/bin/inetd
/new_root/bin/inetd:
-lc.25 => /usr/lib/libc.so.25.2 (0x4001f000)

Non sono necessarie altre librerie oltre a quelle già presenti nel chroot.

L'unico file di configurazione richiesto da inetd è /etc/inetd.conf. Questo e` un esempio del file che deve essere presente nella directory /etc/ del chroot.

# simple inetd configuration file, runs olny ftpd
ftp stream tcp nowait root /bin/ftpd ftpd -US

Il servizio di appoggia anche al demone syslog. Sarà necessario configurare syslog in modo che processi anche i log provenienti dal chroot. Per fare questo è sufficiente lanciare il demone con il parametro "-a /new_root/dev/log"

# kill -9 pid_syslog
# syslogd -a /new_root/dev/log

Syslog creerà un file particolare, /new_root/dev/log, e sarà pronto per ascoltare anche i log generati all'interno del chroot.

Avvio del servizio all'interno dell'ambiente ristretto

Ora il nuovo root file system e` pronto per diventare operativo. Non resta che provare se tutto funziona.

Basta eseguire la chiamata di sistema chroot e poi lanciare il servizio.

# chroot /new_root /bin/inetd

In questo modo viene impostata /new_root come nuova root directory e eseguito il demone inetd.

Se ci fossero dei problemi è possibile utilizzare il comando ktrace. Questo comando permette di tracciare tutte le chiamate del processo e verificare eventuali anomalie. La soluzione migliore consiste nel lanciare il servizio in foreground tramite ktrace per poi andare ad analizzare l'output con kdump.

# cd
# ktrace chroot /new_root /bin/inetd -d
....
# kdump | less

Una volta che si ha la certezza che tutto funzioni correttamente si può modificare lo script di avvio in modo che faccia partire il servizio all'interno del chroot. Ecco un estratto del file /etc/rc:

if [ "X${ftpd_flags}" != X"NO" ]; then
echo -n ' chrooted ftpd'; /usr/sbin/chroot /new_root /bin/inetd
fi


Lorenzo Martignoni <lorenzo@security.dsi.unimi.it>
Ultima modifica: 03 Jul 2001, 19:10 (CEST)