Member of The Internet Defense League Últimos cambios
Últimos Cambios
Blog personal: El hilo del laberinto Geocaching

CHROOT y Seguridad

Última Actualización: 1 de Julio de 1.999 - Jueves

CHROOT es una llamada al sistema en UNIX que permite configurar un directorio como "raíz" del sistema de ficheros para un proceso y sus hijos. En otras palabras, permite configurar el sistema de forma tal que se puedan lanzar procesos confinados dentro de un determinado directorio. Para ellos, dicho directorio será el "/" (la raíz). Cualquier fichero o directorio que esté fuera del CHROOT les quedará inaccesible.

Antes de continuar, es conveniente estudiar con detenimiendo las entradas del manual correspondientes al CHROOT. Suele existir tanto una llamada al sistema como un comando SHELL. Estudia ambos.


Los detalles

CHROOT, en sus dos modos (comando shell y llamada al sistema), sólo puede ser invocado por el superusuario del sistema (root), lo cual es bastante lógico dado el poder que supone. Ya que un CHROOT cambia la raíz del sistema de ficheros, los procesos lanzados no pueden ampliar sus privilegios, ya que el nuevo estará contenido en el antiguo. Ni siquiera el superusuario puede invertir eso... en teoría.

El CHROOT funciona con los ficheros que se manejen a continuación, pero cualquier descriptor de fichero activo seguirá funcionando. En otras palabras, si abrimos un fichero y hacemos un CHROOT que lo deje fuera, seguiremos pudiendo acceder a él a través del descriptor abierto. Ello resulta útil, por ejemplo, para hacer que los logs de un servidor en CHROOT se almacenen fuera de su alcance. Es, no obstante, un punto al que prestar atención para no dejar abierta alguna puerta de forma inadvertida.

También hay que recordar que no podremos acceder a nada fuera del CHROOT. Eso incluye comandos shell y librerías dinámicas/compartidas. Habrá que replicar los comandos y librerías necesarias dentro del CHROOT. Se pueden copiar o bien, ocupando menos sitio, hacerles un enlace "duro". Un enlace simbólico no funciona porque el fichero original no estará disponible.

En algunos casos, dependiendo del sistema, será necesario incluso replicar algunos dispositivos "/dev". Eso es lo que ocurre, por ejemplo, en Solaris si queremos que los servidores corriendo en el nuevo entorno tengan acceso a la red.

La relación entre el CHROOT y algunos demonios del sistema, como el SYSLOG, es bastante... bueno, digamos que "truculenta" :-). Es cuestión de probar en cada caso.


Un Script CHROOT para FTP

En general es muy mala política que un ISP proporcione cuentas Shell, a menos que sea masoquista };-), pero frecuentemente sí se dan cuentas FTP con el fin de que los usuarios actualicen sus web, etc. Aunque no es imprescindible, suele ser buena política que se configure el servidor FTP para que haga un CHROOT y un SETUID tras el "login".

Por tanto en la cuenta del usuario se necesitará, al menos, el comando "LS" y las librerías dinámicas que éste use. Es conveniente crear un fichero "passwd" y otro "group" con valores no reales (se pueden hasta poner vacíos) con el fin de que el LS nos dé un listado coherente y no tenga que esperar a un "timeout" hasta que se entera de que no existen.

A continuación incluyo el script que utilizamos en ARGO a la hora de abrir nuevas cuentas de usuario. Debe ejecutarse como "root" y desde el directorio raíz del usuario, cuyo último segmento debe coincidir con el "login" del usuario. Por ejemplo, para "jcea", podría ser "/export/home/usuarios/a/jcea". Válido para máquinas Solaris.

#! /bin/sh
# Instala todos los directorios y ficheros necesarios dentro de
# una cuenta de usuario para que pueda utilizar el FTP restringido
# y así actualizar sus páginas WEB sin tener que depender de nosotros.
#
# Jcea - Jesús Cea Avión
# Versión 1, Revisión 1 - 05 Feb 97
#
# **** ATENCION ****
#
# Este script debe ser invocado desde la cuenta del usuario, ya que
# instala todo en el directorio actual.
#
#

origen="/export/home/ftp/anonimo"
usuario=`pwd | awk -F/ '{print $NF}'`
echo El directorio fuente de la configuración es $origen
echo El nombre de usuario es $usuario
echo

umask 666

temp=`pwd`
echo Creando estructura de directorios en $temp
ln $origen/../actualizar_web ./actualizar_web
mkdir dev
mkdir usr
mkdir etc
mkdir usr/bin
mkdir usr/lib
ln -s usr/bin bin

lib=$origen/usr/lib
cd usr/lib
temp=`pwd`
echo Creando enlaces a las librerías compartidas en $temp
ln $lib/ld.so.1 ld.so.1
ln $lib/libc.so.1 libc.so.1
ln $lib/libdl.so.1 libdl.so.1
ln $lib/libintl.so.1 libintl.so.1
ln $lib/libnsl.so.1 libnsl.so.1
ln $lib/libsocket.so.1 libsocket.so.1
ln $lib/libw.so.1 libw.so.1
ln $lib/nss_dns.so.1 nss_dns.so.1
ln $lib/nss_files.so.1 nss_files.so.1
ln $lib/nss_nis.so.1 nss_nis.so.1
ln $lib/nss_nisplus.so.1 nss_nisplus.so.1
ln $lib/straddr.so.2 straddr.so.2

bin=$origen/usr/bin
cd ../bin
temp=`pwd`
echo Creando enlace a \"/bin/ls\" en $temp
ln $bin/ls ls

cd ../../etc
temp=`pwd`
umask 133
echo Creando "passwd" y "group" fantasma en $temp
cp /dev/null passwd
cp /dev/null group

dev=$origen/dev
cd ../dev
temp=`pwd`
echo Creando enlaces a dispositivos en $temp
ln $dev/tcp tcp
ln $dev/ticotsord ticotsord
ln $dev/udp udp
ln $dev/zero zero

cd ..
temp=`pwd`
echo Creando directorio raíz de páginas WEB en $temp
echo Cambiando su propietario y grupo
umask 066
mkdir publico
chown $usuario publico
chgrp usuarios publico

echo
echo ¡¡FIN!!


Sistema Operativo

Como ya se ha comentado, cada sistema operativo requiere la replicación de ciertos ficheros/dispositivos. Si tienes más información, házmela llegar.

Sistema Operativo Comandos Shell Librerías Dinámicas Dispositivos Otros
Solaris 2.5.1SiSiSiNo
Linux >2.0.30SiSiNoNo

Para saber qué ficheros, librerías dinámicas, dispositivos, etc., necesitamos replicar, se puede cargar el programa con un depurador (por ejemplo, gdb), y ver cuáles utiliza.

Solaris (>=2.5.1):

Para ver las librerías dinámicas, puedes hacer un "pmap". Este comando te listará la distribución de memoria de un proceso dado, indicando dónde están cargadas las librerías dinámicas. Por tanto sabemos cuáles necesita :-). También se puede utilizar el comando "pldd", que es más directo.

Para los ficheros y dispositivos, podemos utilizar el comando "truss", que vuelca a un fichero las llamadas al sistema realizadas por un proceso.

Para crear los dispositivos hay que utilizar "mknod", creando un directorio "/dev" y poniendo allí enlaces simbólicos a "/devices/pseudo".


Seguridad (o inseguridad, según se mire)

En principio, un entorno CHROOT es bastante seguro, al menos siempre y cuando:

  1. Se tenga un sistema operativo reciente y que se suponga sin bugs conocidos.

  2. Se eviten los comandos SUID como la peste. Ello evita su explotación y el posterior uso de los comandos MKNOD, MOUNT, UADMIN, acceso directo a la memoria del kernel, etc. En general, habría que modificar el kernel para no permitir el uso de las llamadas "chroot", "mknod", "chmod" y "mkdir" (para no crear entradas "/dev" falsas, por ejemplo), así como el acceso a dispositivos vía "/dev" o "/device".

  3. Sea imposible hacerse superusuario una vez dentro de un CHROOT. Si eres "root", el CHROOT se puede saltar de forma trivial.

  4. No se importen ficheros abiertos desde fuera del CHROOT.

  5. El directorio actual del proceso esté dentro del CHROOT.

  6. No se replique nada innecesario, especialmente directorios como "/dev", "/proc", etc. "/proc", por ejemplo, permite acceder al directorio raíz de cada proceso que corre en el sistema (bajo Linux). De hecho, bajo linux, "/proc" es toda una interfaz al kernel. Hay que evitarla a toda costa. Lo mismo para "/procfs" y "/kernfs" sobre NetBSD/FreeBSD.

  7. Los servicios accesibles no sean "explotables": léase SYSLOG flood y similares. Ojo con dejar el AT, CRON y CRONTAB accesibles.

  8. Que no se permitan cargar módulos en el Kernel.

  9. Si es posible montar particiones, hacerlas "sólo lectura". En las que se pueda escribir, usar el modo "NOSUID".

En todo caso un entorno CHROOT debe considerarse sólo una barrera más, de cara a la seguridad, no una forma de crear máquinas virtuales. Y, por supuesto, no debe ser el único obstáculo contra intrusiones.

Una interesante forma de salir de un chroot:

mkdir("foo",S_IRUSR|S_IXUSR);
chroot("foo");
chdir("..");

Esto explica, entre otras cosas, por qué:

  • No debe ser posible hacerse superusuario.
  • Hay que tener cuidado y hacer que el directorio actual del proceso esté dentro del CHROOT.


Historia:

  • 01/Jul/99: Ignacio Arenaza (inaki.arenaza@jet.es) me informa de la utilidad strace de Linux:
    Subject: Articulo sobre chroot en www.hispasec.com
       Date: 07 Feb 1999 21:46:13 +0100
       From: Ignacio Arenaza 
         To: jcea@argo.es
    
    Muy buenas,
    
    he estado leyendo el articulo sobre chroot en www.hispasec.com, y alli
    mencionas entre otras cosas que existe una utilidad llamada truss que
    sirve para "tracear" las llamadas al sistema en Solaris, y que no
    conoces nada equivalente en linux. Bueno, pues existe y se llama
    "strace", y basicamente tiene la misma funcionalidad que truss. Asi
    que si quieres completar el articulo, tu mismo.
    
    Saludos. Iñaki.
    
    P.D. El articulo me ha parecido muy bueno. Gracias por compartirlo con
    todos nosotros.
    
    -- 
      inaki.arenaza@jet.es
      http://web.jet.es/inaki.arenaza/
      PGP Key available at http://web.jet.es/inaki.arenaza/pgpkey.html
      Linux Registered User #44369
    

  • 05/Jun/98: Escribo un artículo para la revista Linux Actual.

  • 07/May/98: Actualizado con la información de la revista SunWold Online (sección Sistema Operativo: identificación de ficheros, dispositivos, etc., a replicar).

  • 22/Ene/98: Primera versión de este documento.



Python Zope ©1998-99 jcea@jcea.es

Más información sobre los OpenBadges

Donación BitCoin: 19niBN42ac2pqDQFx6GJZxry2JQSFvwAfS