Con un usuario normal sin permisos de administración no puedes hacer uso de puertos por debajo del 1024 por motivos de seguridad. Estos puertos son utilizados por servicios conocidos como FTP, servidores web Apache o Nginx, DNS, etc… y requieren de root o usuario con permisos adecuados.
Podemos hacer una prueba sencilla con netcat (nc) intentando abrir un socket en un puerto por debajo del 1024 con un usuario no administrativo:
[jota@jota-pc ~]$ nc -v -l 90 nc: Permission denied
Ahora en un puerto no privilegiado no habrá problemas:
[jota@jota-pc ~]$ nc -v -l 9000 Listening on [0.0.0.0] (family 0, port 9000)
Tenemos distintas opciones para conseguir que un usuario normal pueda utilizar estos puertos.
Uso de setcap
Con setcap (Set Capabilities) podemos permitir que un usuario no administrativo haga uso de determinadas aplicaciones sin necesidad de privilegios especiales.
Para el caso que nos ocupa la sintaxis para permitir el uso de puertos privilegiados por un usuario normal sería:
setcap 'cap_net_bind_service=+ep' /ruta/binario
No se pueden aplicar propiedades con setcap en ficheros no regulares (por ejemplo enlaces simbólicos). Como /bin/nc es un enlace simbólico en Debian pasaría lo siguiente:
[root@jota-pc ~]# setcap cap_net_bind_service=+ep /bin/nc Failed to set capabilities on file `/bin/nc' (Invalid argument) The value of the capability argument is not permitted for a file. Or the file is not a regular (non-symlink) file
Resulta que en Debian el binario que tenemos de netcat corresponde a la implementación en OpenBSD:
[root@jota-pc ~]# ls -l /bin/nc lrwxrwxrwx 1 root root 20 Aug 7 2015 /bin/nc -> /etc/alternatives/nc [root@jota-pc ~]# ls -l /etc/alternatives/nc lrwxrwxrwx 1 root root 15 Aug 25 2017 /etc/alternatives/nc -> /bin/nc.openbsd
De esta manera aplicamos la propiedad sobre el binario:
[root@jota-pc ~]# setcap cap_net_bind_service=+ep /bin/nc.openbsd
Comprobamos con getcap
:
[root@jota-pc ~]# getcap /bin/nc.openbsd /bin/nc.openbsd = cap_net_bind_service+ep
Ahora de nuevo con el usuario jota abro un socket en el puerto 90 sin problema:
[jota@jota-pc ~]$ nc -v -l 90 Listening on [0.0.0.0] (family 0, port 90)
Para quitar la propiedad utilizamos la opción -r
[root@jota-pc ~]# setcap -r /bin/nc.openbsd [root@jota-pc ~]# getcap /bin/nc.openbsd
El principal problema de esta aproximación es que abrimos la puerto a que cualquier usuario pueda hacer uso de ese binario abriendo puertos privilegiados. Una solución a esto es utilizar ACL (Access Control List) quitando permisos de ejecución al fichero para “otros” y poniendo un ACL que sólo permita a mi usuario ejecutarlo (además de al usuario/grupo propietario del binario):
[jota@jota-pc ~]$ ls -l /bin/nc.openbsd -rwxr-xr-x 1 root root 31208 Mar 3 2017 /bin/nc.openbsd [root@jota-pc ~]# chmod 750 /bin/nc.openbsd [root@jota-pc ~]# ls -l /bin/nc.openbsd -rwxr-x--- 1 root root 31208 Mar 3 2017 /bin/nc.openbsd
Aplicamos ACL con setfactl
y comprobamos con getfacl
:
[root@jota-pc ~]# setfacl -m u:jota:x /bin/nc.openbsd [root@jota-pc ~]# getfacl /bin/nc.openbsd getfacl: Removing leading '/' from absolute path names # file: bin/nc.openbsd # owner: root # group: root user::rwx user:jota:--x group::r-x mask::r-x other::---
Para quitar el ACL aplicado:
setfacl -x u:jota /bin/nc.openbsd
Regla prerouting con iptables
Otra solución consiste en utilizar la tabla nat de iptables para redirigir las peticiones de puertos inferiores a puertos superiores. Imaginemos que tenemos un servidor web Apache que escucha en el puerto 80 y necesitamos levantar este servicio con un usuario no administrativo, nos encontraríamos con la misma casuística. Con iptables podríamos hacer:
iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8000
Nosotros podríamos levantar el servidor web Apache cambiando el puerto de escucha a 8000, ej.:
Listen 192.168.1.101:8000
Las peticiones de los usuarios, aplicaciones o servicios llegarían al puerto 80 e iptables se encargaría internamente y de forma transparente de redirigir estas peticiones al puerto 8000 que es donde hemos levantado nuestro servicio.
Un poco de sudo para el usuario
Podemos dar permisos de sudo a un usuario en concreto para ejecutar un binario con permisos de administrador. Para ello editamos el fichero /etc/sudoers
como root con el comando visudo. Para el ejemplo inicial con nc introduciríamos:
jota ALL= /bin/nc
Ahora con el usuario jota hacemos sudo al comando:
[jota@jota-pc ~]$ sudo nc -v -l 90 [sudo] password for jota: Listening on [0.0.0.0] (family 0, port 90)
Cada vez que lo ejecutemos tendremos que introducir nuestra contraseña. Si esto se nos hace demasiado pesado podemos configurar /etc/sudoers
para que no pida contraseña:
jota ALL=(ALL) NOPASSWD:/bin/nc
Ahora ejecutamos nc:
[jota@jota-pc ~]$ sudo nc -v -l 90 Listening on [0.0.0.0] (family 0, port 90)
En cuanto a la primera opción expuesta en el artículo, es interesante echarle un vistazo a la página del manual correspondiente con man capabilities
para ver todas las posibilidades que ofrece.