Últimos Cambios |
||
Blog personal: El hilo del laberinto |
Última Actualización: 31 de Julio de 1.998 - Viernes
Artículo escrito el 05/Jun/98 y publicado en
Linux Actual, Julio 98, número 3, páginas 75-76
Este artículo toma como base otro documento escrito por mí. En la revista se suprimió una tabla y numerosas referencias al sistema operativo Solaris. Este documento es mi texto íntegro.
La informática, y la programación en particular, están muy lejos todavía de convertirse en ciencia. De momento apenas llegan a arte. Escribir programas seguros y a prueba de bomba no es una tarea sencilla. Requiere pericia, experiencia y una buena dosis de sana paranoia. Analizaremos con detalle el problema de escribir programas seguros en nuestro próximo número.
Este mes vamos a centrarnos, sin embargo, algo más del día a día: confinamiento de procesos mediante CHROOT.
"Chroot" es una forma de confinar procesos a una determinada zona del árbol de directorios, impidiendo que dichos procesos accedan a servicios o documentos fuera de su entorno. Ello resulta muy útil, ya que si el programa falla, su impacto será mucho más localizado que si se le permite acceder a todo el disco duro. Esto nos protege muchísimo no sólo ante fallos de programación o problemas de funcionamiento, sino también, incluso, ante ataques y violaciones de seguridad. Resulta una práctica casi imprescindible en un entorno abierto en donde se ejecutan servicios conectados a internet, o cuando no estamos seguros del todo respecto a la fiabilidad de un programa que vamos a probar.
En casi todos los UNIX, el "chroot" está accesible a través de dos vías: la línea de comandos y la propia llamada al sistema. Antes de continuar es aconsejable que el lector haga un "man -S8 chroot" y un "man -S2 chroot". La sintaxis es muy sencilla y, aparentemente, su uso también.
Pero las apariencias engañan, y la vida no es siempre tan fácil. En este artículo intentaremos desentrañar algunos de los misterios y mitos que rodean el "chroot", sus usos y sus limitaciones.
"Chroot", sea como comando o como llamada al sistema, sólo puede ser invocado por el superusuario, lo cual es comprensible dado el tremendo poder que supone. El "chroot" cambia la raíz del sistema de ficheros, desde el punto de vista del proceso lanzado y de sus hijos, y los nuevos procesos no pueden ampliar sus privilegios, ya que un nuevo "chroot" sería relativo al actual. Es decir, estaría contenido en su interior.
Todos los ficheros que se abran tras un "chroot" son relativos al nuevo directorio raíz, que será el especificado en dicho comando. Es decir, a todos los efectos el directorio "barra", cabeza del nuevo árbol de archivos, será el directorio en cuestión. Por lo tanto sólo será posible acceder a ficheros y comandos shell contenidos en el nuevo entorno. Esta comprobación sólo se efectúa al abrir ficheros; un fichero en uso antes del "chroot" no se verá afectado. Esto resulta muy útil, por ejemplo, para que los logs de un servidor se almacenen fuera de su alcance. Como contrapartida, claro, hay que tener cuidado con no filtrar ningún fichero abierto innecesario al entorno "chroot".
Es muy importante recordar que no se puede acceder a ningún fichero externo al "chroot". Y no basta con copiar los ejecutables que vamos a usar. Muchas veces dichos ejecutables necesitan de librerías dinámicas, con lo que es preciso o bien compilar el código indicando enlazado estático, o bien replicar las librerías dinámicas en el entorno "chroot". No sirve crear un enlace simbólico, ya que en el "chroot" la referencia indicada no tiene sentido (normalmente se apuntará a sí misma). Se pueden o bien copiar las librerías necesarias o bien, más recomendable, crearles un enlace "hard" si estamos trabajando dentro de la misma partición. Lo mismo se aplica a posibles dispositivos bajo "/dev", y similares. Si necesitamos crearlos dentro podemos usar el comando "mknod".
Saber qué librerías y ficheros necesita un proceso determinado no es inmediato. Las librerías, bajo Solaris, se pueden comprobar con un simple comando "pldd", y en Linux se puede emplear la interfaz "map" bajo "/proc", y el comando "find" para buscar el fichero referenciado por ese "inode". Otra posibilidad, más sencilla, consiste en emplear el comando "ldd" sobre el propio fichero del ejecutable. Bajo Solaris se permite repetir el proceso con cada librería que se liste, ya que pueden contener referencias a otras.
Conocer los ficheros abiertos a lo largo de la vida de un programa es más complicado, sobre todo cuando se manejan muchos y no se tienen abiertos más que por períodos muy cortos. Si un fichero permanece abierto durante todo el programa se puede localizar mediante la interfaz "fd" bajo "/proc", usando el comando "find" nuevamente para localizar el nombre del fichero dado su "inode". En Solaris se puede hacer lo mismo con el comando "pfiles". Algunos de los "fd" abiertos pueden corresponderse a ficheros que no existen realmente, como la entrada y salida estándares, pipes, etc.
Localizar ficheros abiertos apenas un instante es bastante más complejo. Lo normal en estos casos consiste en ejecutar el programa trazando las llamadas al sistema que realiza, entre ellas llamadas tales como "open". En Solaris se dispone de una utilidad sencilla llamada "truss" que las llamadas al sistema por parte de un proceso. Bajo Linux no conozco una utilidad así, aunque es sencillo ejecutar el proceso con el GDB (GNU Debugger) y poner un punto de ruptura a la entrada del "open".
Una vez que sabemos qué librerías, ficheros y dispositivos necesita un proceso podemos replicarlos dentro de la nueva estructura "chroot", ya sea copiándolos o bien creando un enlace "hard". Recordad que un enlace simbólico no sirve.
¿Cómo de seguro es un entorno "chroot"?. La respuesta no es sencilla. Bien configurado, un confinamiento de este tipo es muy útil, pero en la práctica una máquina en producción tiene tantos procesos abiertos y las interrelaciones entre los mismos es tan compleja que asegurarlo es muy difícil. En realidad nuestra obligación es construir toda una serie de barreras anti-intrusiones, como un tamiz. En ese sentido el "chroot" es una herramienta más, y muy útil. Debemos ser conscientes, sin embargo, de sus limitaciones; su misión consiste en confinar el sistema de ficheros, no en proporcionar una auténtica máquina virtual absolutamente segura.
Existen, no obstante, una serie de principios básicos, de obligado cumplimiento:
En la figura se puede ver un caso práctico de creación de un entorno CHROOT para el FTP, configurando éste para que haga "chroot" y SETUID tras el "login". Es bastante sencillo de entender. Debe ejecutarse como "root" y desde el directorio raíz del usuario que estamos configurando, cuyo último segmento debe coincidir con el "login" del usuario. Por ejemplo, para el usuario "jcea", un path correcto podría ser "/export/home/usuarios/jcea".
El listado, naturalmente, no es para que lo utilicéis tal cual, sino para estudiarlo con detenimiento.
Otra posibilidad para el FTP sería tener un único directorio "chroot", con todo lo necesario duplicado allí, y, colgando de él, el directorio de cada usuario. Naturalmente el directorio "chroot" sería "no listable" para evitar curiosos (no nos interesa que nadie sepa qué usuarios tenemos, ¿no?) y cada directorio en particular sólo permitiría la entrada a su usuario, mediante los permisos apropiados. Yo he preferido independizarlo un poco más para posibilitar montar usuarios en diferentes particiones, etc. Esto va un poco al gusto de cada cual; la ocupación en disco es similar, ya que estamos creando vínculos "hard", no copiando todas las librerías cada vez.
Espero que este artículo os permita protegeros mejor y os solucione algún que otro problema. Se puede encontrar una versión previa de este documento en http://www.argo.es/~jcea/artic/chroot.htm.
Como regalito, una demostración de por qué no debe ser posible hacerse "root" dentro de un "chroot":
mkdir("xploit",S_IRUSR | S_IXUSR); chroot("xploit"); chdir("..");
Librerías Compartidas# ldd /usr/sbin/syslogd (Linux) libc.so.5 => /lib/libc.so.5.3.12 # ldd /usr/sbin/syslogd (Solaris) libnsl.so.1 => /usr/lib/libnsl.so.1 libc.so.1 => /usr/lib/libc.so.1 libdl.so.1 => /usr/lib/libdl.so.1 libintl.so.1 => /usr/lib/libintl.so.1 libmp.so.1 => /usr/lib/libmp.so.1 libw.so.1 => /usr/lib/libw.so.1 |
FTP en CHROOT#! /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 \"/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!! |
Más información sobre los OpenBadges
Donación BitCoin: 19niBN42ac2pqDQFx6GJZxry2JQSFvwAfS