Una de las tareas mas comunes de un administrador de sistemas consiste principalmente en la correcta configuración y arranque de diversos servicios tales como servidores web, servidores de correo, servidores DNS, etc. En todos los casos, alguien consciente de que la seguridad en los servicios expuestos al publico tendrá como referencia determinadas políticas de seguridad entre las cuales, sin lugar a dudas, se debe incluir la ejecución de dichos servicios con un usuario con privilegios limitados, es decir, el usuario ROOT no debería iniciar servicios como Apache o SendMail, ya que si existe algún problema con dichos servicios, como por ejemplo una vulnerabilidad que le permita al atacante acceder de forma remota (como por ejemplo el aprovechamiento de una vulnerabilidad de Buffer Overflow) este automáticamente tendrá privilegios de ROOT sobre el sistema, no hace falta indicar las nefastas consecuencias que conllevan incidencias como estas.

Aunque dicha política de seguridad sea casi como una ley (divina?) “No arrancaras servicios expuestos al publico utilizando para ello el usuario ROOT” existe un inconveniente que es intrínseco al diseño original de como funcionan los sistemas operativos basados en UNIX y consiste en que todos los puertos privilegiados (menores a 1024) solamente pueden ser enlazados (binding) por el usuario ROOT, servicios comunes como Servidor SSH, Servidor web, Servidor de Correo, Finger, Servidor DNS, etc. frecuentemente se ejecutan en puertos menores a 1024, para tratar con este tipo de situaciones, se cuentan con algunas alternativas ante estas situaciones, las que mas destacan son:

– Crear un entorno CHRooted

– Utilizar el comando SUDO y editar el fichero de sudoers correspondiente

– Utilizar herramientas que permitan abrir un puerto privilegiado utilizando permisos de ROOT y posteriormente remover dichos permisos del proceso principal.

La primera alternativa en muchos casos es difícil de mantener, ya que se debe realizar un estudio detallado sobre cuales ejecutables tendrá disponible el usuario enjaulado, es una tarea con un nivel de dificultad considerable y las implicaciones de seguridad que trae consigo un entorno CHRooted mal configurado pueden ser desastrosas, por otro lado el uso del comando “SUDO” permite a un usuario con permisos limitados realizar determinadas acciones como ROOT, este enfoque resulta practico en muchos casos, no obstante el proceso ejecutado con este comando permanecerá cargado en memoria hasta su terminación con los privilegios que se han asignado por medio del comando “SUDO” por lo tanto también trae consigo implicaciones en términos de seguridad. Finalmente la ultima opción (que será el enfoque de esta entrada) consiste en utilizar herramientas que permitan ejecutar el proceso que abra los puertos privilegiados (como un servidor web como apache que puede abrir los puertos 80 y 443) y una vez abiertos, remueva automáticamente cualquier privilegio de ROOT que pueda estar asignado al proceso en ejecución.

Las herramientas que actualmente se enfocan en permitir que una aplicación pueda abrir un puerto reservado (inferior a 1024) utilizan uno de dos mecanismos, en primer lugar pueden utilizar la característica de “capabilities” incluida en Linux y que permite declarar determinados permisos a una aplicación concreta, una aplicación que utilizan este mecanismo es setcap, por otro lado también se puede utilizar la variable LD_PRELOAD que permite sobreescribir las invocaciones a la llamada del sistema bind las herramientas authbind y privbind utilizan este método para permitir que una aplicación determinada pueda abrir puertos reservados y este será el mecanismo explicado en esta entrada dado que es el mejor en terminos funcionales y de seguridad.

authbind

Authbind es una herramienta sencilla y flexible que permite abrir puertos reservados sin que el usuario que ejecuta el proceso tenga privilegios de ROOT. Para conseguir esto, authbind utiliza la funcionalidad de LD_PRELOAD incluida en las distribuciones Linux actuales, la cual permite a un programa (incluyendo sus correspondientes sub procesos) abrir puertos inferiores a 1024, los cuales son reservados para servicios tan importantes como servidores web, servidores de correo, servidores DNS, servidores SSH, servidores FTP, etc.

El mecanismo empleado por authbind es sencillo, consiste básicamente en cargar y utilizar la variable LD_PRELOAD para sobre escribir la llamada al sistema bind la cual se encarga de asignar un espacio de memoria compartido con otros procesos remotos llamados habitualmente “clientes”, este espacio de memoria es referenciado por un número único que es habitualmente llamado “puerto”. Cuando se invoca a authbind este ejecutará la llamada del sistema bind sobreescrita por la utilidad, esto en el caso de que el usuario no tenga el uid 0 (es decir no es ROOT) authbind intentará invocar la función auxiliar setuid-root e intentará abrir el puerto privilegiado, en el caso de que el usuario tenga el uid igual a 0 (es decir, es root) o el puerto que se intenta abrir es mayor a 1024, authbind no necesitará invocar a la función de bind sobreescrita, en su lugar invoca a la función bind original para que esta reserve el espacio de memoria compartido solicitado (para que abra el puerto).

Instalación y funcionamiento de authbind

En primer termino para instalar authbind, se puede ejecutar el comando apt-get correspondiente o compilar e instalar desde código fuente, en el primer caso solamente basta con ejecutar el comando “apt-get install authbind” en el segundo caso es necesario descargar el código fuente de authbind desde: http://www.chiark.greenend.org.uk/ucgi/~ijackson/cvsweb/authbind/ y posteriormente realizar el procedimiento de compilación, construcción e instalación estándar en programas escritos en C (make && make install)

Una vez instalado el programa es necesario comprender como es el mecanismo de control de acceso que utiliza authbind para poder abrir puertos restringidos.

  1. Authbind primero busca el fichero /etc/authbind/byport/port donde “port” es simplemente el número de puerto que authbind permitirá abrir por medio de la función de bind sobreescrita, en el caso de que dicho fichero sea accesible, el acceso es autorizado y authbind procederá a abrir dicho puerto.
  2. En el caso de que el fichero anterior no exista o no sea accesible por el usuario que esta ejecutando authbind la herramienta intentará validar el fichero /etc/authbind/byaddr/addr:port donde “addr” y “port” son la dirección de la maquina y el puerto que tienen autorización para abrir el puerto.
  3. Finalmente, si ninguno de los dos ficheros anteriores ha podido ser validado correctamente, authbind realiza un ultimo intento en buscar el fichero /etc/authbind/byuid/uid donde uid indica el identificador único de usuario, si este fichero es encontrado, se garantiza el acceso y authbind procede a abrir el puerto solicitado, sin embargo en el caso de que no sea localizado dicho puerto, automáticamente se lanzará un error de “Operación No Permitida”

Dada la explicación anterior, se cuenta ya con un conocimiento detallado del funcionamiento de authbind ahora se indican las opciones incluidas en esta herramienta que son dos:

  1. –deep: La herramienta por defecto solamente afecta al programa que recibe como argumento, no obstante con esta opción, authbind incluirá en su ejecución todos los programas que se puedan invocar de forma directa o indirecta pro el programa especificado, lo que quiere decir que si el programa invocado, utiliza otro programa que requiera abrir un puerto inferior a 1024, authbind realizará el mismo procedimiento de control de acceso anteriormente descrito y así para todos y cada uno de los programas que se invoquen de forma directa o indirecta por el programa.
  2. –depth niveles: Como se ha explicado, la opción anterior afecta a todos los programas invocados de forma directa o indirecta por el programa pasado como argumento a authbind no obstante, con esta opción se puede controlar y limitar este comportamiento, indicando el numero de niveles de profundidad (programas tratados por authbind) que podrán pasar por el control de acceso de la herramienta en el caso de que intenten abrir un puerto reservado. El valor por defecto de esta opción es “1” y es el valor que se aplica siempre a menos que la opción “–deep” sea indicada de forma explicita.

Para centrar estos conceptos, en un ejemplo practico, se procede a iniciar un servidor web Apache, el cual intentará abrir los puertos 80 (HTTP) y 443 (HTTPS). Como se ha indicado anteriormente, el primer paso es establecer el control de acceso creando los ficheros correspondientes a estos dos puertos en las ubicaciones adecuadas, para esto se pueden ejecutar los siguientes comandos (evidentemente estos comandos solo pueden ser ejecutados como ROOT, de otro modo cualquier usuario podría “darse permisos” sin conocimiento del administrador, al momento de instalar authbind, la herramienta establece los permisos adecuados al directorio /etc/authbind para que no pueda ser accedido por cualquier usuario):

touch /etc/authbind/byport/80chmod 500 /etc/authbind/byport/80

chown adastra /etc/authbind/byport/80

touch /etc/authbind/byport/443

chmod 500 /etc/authbind/byport/443

chown adastra /etc/authbind/byport/443

Una vez creados y establecidos los permisos adecuados para que el usuario “adastra” pueda acceder a dichos ficheros, se puede ejecutar el comando de arranque del servidor web apache de la siguiente forma:

authbind –deep /opt/apache2/apachectl start

Con esto es suficiente para iniciar el servidor apache desde la cuenta de usuario “adastra” la cual tiene privilegios limitados.

Privbind

Se trata de una herramienta que tiene un mecanismo similar al que utiliza authbind para permitir a una aplicación determinada abrir puertos reservados utilizando la variable LD_PRELOAD que permite sobreescribir las invocaciones que se lleven a cabo contra la función del sistema bind de esta forma, cuando un comando intenta invocar a la función bind para abrir un puerto privilegiado, privbind intercepta la llamada y la envía a un proceso que tiene privilegios de root, dicho proceso intenta abrir el puerto solicitado y posteriormente envía el resultado de la invocación (el File Descriptor) al proceso padre y continua con la ejecución normalmente. Este mecanismo es el modelo estándar de “fork + exec” que consiste en realizar una “bifurcación” del proceso principal a otro proceso dependiente para realizar cualquier tipo de operación que no puede (o no debe) realizarse desde el proceso principal y una vez esta operación sea finalizada, el control de la ejecución del programa es retomada por el proceso principal, tomando como insumo los resultados que ha dado la ejecución del proceso hijo. Se trata de un mecanismo sencillo no obstante muy efectivo que permite ejecutar operaciones desde un proceso hijo que el proceso padre por si solo no tendría permitido realizar, es así como solamente se le permite a un programa determinado abrir algún puerto menor o igual a 1024.

El proceso de instalación consiste en compilar, construir e instalar todo desde código fuente, se trata de un programa escrito en C, por lo tanto este proceso es muy sencillo (./configure && make && make install)

Una vez instalado es posible comenzar a utilizarlo, las opciones disponibles en dicho comando son:

-u: Opción obligatoria que indica bajo cual UID de usuario ejecutar la aplicación que es especificada por parámetro, puede indicarse el valor numérico o directamente el nombre del usuario y en ningún caso puede ser un usuario con privilegios de ROOT.

-g: Indica el GID del usuario que se ha indicado en la opción -u, en el caso de que no es especifique de forma explicita, se toma el grupo por defecto del usuario.

-n: Esta opción es importante ya que determina el numero de veces que se permitirá invocar a la función del sistema bind desde privbind, esto quiere decir que cuando este número de invocaciones es alcanzado el proceso hijo de privbind (el que se encarga de invocar la función bind) automáticamente finaliza su ejecución dejando activo solamente al proceso padre. Por defecto, si no se especifica esta opción de forma explicita

-l: Indica la ruta donde se encuentra ubicada la librería LD_PRELOAD en el caso de que no se encuentre localizada en las librerías compartidas del sistema.

Estas son todas las opciones que se incluyen en esta herramienta, ahora bien, para probarlo puede ser útil iniciar un servidor web como Apache utilizando un usuario sin privilegios, este servidor web intentará abrir los puertos 80 y 443, en este caso el comando que se ejecuta es el siguiente:

>privbind -u 1000 -g 1000 -n 2 /opt/apache2/bin/apachectl start

Se han especificado las opciones -u y -g que como ya se ha comentado anteriormente indican el uid del usuario que estará asociado al proceso padre y el grupo de dicho usuario respectivamente. Por otro lado también se controla el numero de invocaciones máximo que se podrán llevar a cabo contra la función del sistema bind, en este caso el valor de 2 es suficiente (ya que se deben abrir solamente dos puertos) finalmente se encuentra el comando que inicia el servidor web. Cabe anotar que este comando debe ser ejecutado por el usuario ROOT, la razón de esto es que el proceso principal debe tener los privilegios del usuario especificado en la opción -u pero el proceso hijo que será el encargado de realizar las invocaciones a la función bind debe tener privilegios de ROOT.

setuid feature

Esta característica es muy popular en sistemas operativos basados en unix y esta directamente relacionada con los permisos que tiene un fichero o directorio, en el caso de un fichero binario, si el bit setuid esta activo, cuando el fichero sea ejecutado por un usuario, el proceso tendrá los mismos privilegios que el propietario del fichero que esta siendo ejecutado, por lo tanto si el propietario de dicho binario es ROOT el proceso tendrá los mismos privilegios y podrá realizar cualquier tipo de acción administrativa sobre el sistema. Esta característica es también conocida por tener implicaciones de seguridad importantes y es recomendable no utilizarla, dado que es un modelo de “todo o nada” es decir, si el bit setuid esta definido para un fichero ejecutable, el proceso creado por la ejecución de dicho fichero tendrá todos los privilegios que tiene el propietario del fichero, si no esta establecido, evidentemente el proceso solo tendrá los privilegios del usuario que le ha invocado, por este motivo es un mecanismo de “todos” los privilegios o “ninguno”, no obstante se intentará indicar su uso en las siguientes lineas.

Para saber si una aplicación tiene activado el bit de setuid, basta con utilizar el comando “ls” para listar los permisos de cada fichero y/o directorio

>ls -l /usr/bin/passwd -rwsr-xr-x 1 root root 43280 feb 15 2011 /usr/bin/passwd

Como puede apreciarse, los permisos de la aplicación passwd son: “-rwsr-xr-x” la “s” indica que el setuid esta establecido para dicha aplicación, desde el momento que un usuario con privilegios limitados utiliza el comando passwd, el proceso generado tiene, efectivamente los mismos privilegios que el propietario del fichero binario, que como puede verse en este caso es ROOT.

Esta característica puede ser activada fácilmente utilizando el comando chmod el cual permite cambiar los permisos que tiene asociados un fichero o directorio, no obstante este comando debe ser ejecutado como ROOT en el caso de ficheros binarios cuyo propietario es ROOT algo que es común en el caso de servidores web y aplicaciones relacionadas. Para cambiar el bit correspondiente al setuid basta con ejecutar el comando

>chown root:root <FICHERO_EJECUTABLE>>chmod 4777 <FICHERO_EJECUTABLE>

En las lineas anteriores se ha indicado en primera instancia que el fichero ejecutable es propiedad del usuario ROOT y posteriormente se ha establecido el setuid del fichero binario, de este modo aun cuando se ejecute con un usuario distinto a ROOT el proceso tendrá privilegios de ROOT.

NOTA:

Aunque el enfoque de esta entrada es el uso del bit setuid, existen otros dos valores de permisos que vale la pena mencionar aquí, los permisos adicionales que pueden establecerse a un fichero o directorio (aparte de los permisos estándar de lectura, escritura y ejecución) son:

setuid Indica que el proceso generado por el ejecutable tendrá los mismos permisos que el propietario del fichero

segid Indica que el proceso generado por el ejecutable tendrá los mismos permisos que el grupo del propietario del fichero

Sticky bit Antiguamente era definido para disparar un proceso adicional que se “pegará” en la memoria una vez finalizará su ejecución, actualmente esta funcionalidad esta obsoleta y ahora se utiliza con frecuencia para suprimir privilegios de borrado de ficheros que pertenecen a otros usuarios en el directorio donde se tiene permiso de escritura.

Ahora bien, por defecto estas características se encuentran desactivadas por defecto en la mayoría de distribuciones basadas en UNIX modernas, como es el caso de muchas distribuciones de Linux (como por ejemplo Ubuntu y Debian) sin embargo para “activar” esta característica basta con ejecutar la función setuid desde un programa simple escrito en C. Por ejemplo para iniciar el servicio de Apache se siguen las siguientes instrucciones

  1. Compilar y ejecutar el siguiente programa
    #include <stdio.h>#include <stdlib.h>

    #include <sys/types.h>

    #include <unistd.h>

    int main()

    {

    setuid( 0 );

    system( «/opt/apache2/bin/apachectl start» );

    return 0;

    }

    Compilar con “gcc” y posteriormente establecer el SETUID en dicho binario (todo utilizando el usuario ROOT).

    >gcc apachesuid.c -o apachesuid>chown root:root apachesuid

    >chmod 4777 apachesuid

  2. Desde la cuenta de un usuario con privilegios limitados ejecutar el comando “apachesuid” (que será el encargado de ejecutar el servidor web)
    >./apachesuid


    Con el comando anterior, será suficiente para activar el SETUID en una distribución Linux moderna, sin embargo, lo anterior solamente es demostrativo, no se recomienda hacerlo desde un entorno en producción.

Como nota final, se recomienda utilizar herramientas como authbind o privbind en lugar de características como SETUID en ficheros ejecutables dado que se trata de soluciones mucho más limpias y mejor implementadas desde el punto de vista de la seguridad.