¿Existe alguna forma de que los procesos no root se vinculen a puertos "privilegiados" en Linux?

Resuelto Jason C asked hace 15 años • 25 respuestas

Es muy molesto tener esta limitación en mi caja de desarrollo, cuando nunca habrá más usuarios que yo.

Conozco las soluciones estándar , pero ninguna hace exactamente lo que quiero:

  1. authbind (La versión en pruebas de Debian, 1.0, solo admite IPv4)
  2. Uso del objetivo REDIRECT de iptables para redirigir un puerto bajo a un puerto alto (la tabla "nat" aún no está implementada para ip6tables, la versión IPv6 de iptables)
  3. sudo (Ejecutar como root es lo que intento evitar)
  4. SELinux (o similar). (Este es solo mi cuadro de desarrollo, no quiero introducir mucha complejidad adicional).

¿Existe alguna sysctlvariable simple que permita que procesos no root se vinculen a puertos "privilegiados" (puertos menores que 1024) en Linux, o simplemente no tengo suerte?

EDITAR: en algunos casos, puede utilizar capacidades para hacer esto.

Jason C avatar Jan 06 '09 00:01 Jason C
Aceptado

Bien, gracias a las personas que señalaron el sistema de capacidades y CAP_NET_BIND_SERVICEla capacidad. Si tiene un kernel reciente, es posible usarlo para iniciar un servicio como no root pero vincular puertos bajos. La respuesta corta es que sí:

setcap 'cap_net_bind_service=+ep' /path/to/program

Y luego, en cualquier momento programque se ejecute a partir de entonces, tendrá la CAP_NET_BIND_SERVICEcapacidad. setcapestá en el paquete debian libcap2-bin.

Ahora las advertencias:

  1. Necesitará al menos un kernel 2.6.24
  2. Esto no funcionará si su archivo es un script. (es decir, utiliza una #!línea para iniciar un intérprete). En este caso, hasta donde tengo entendido, habría que aplicar la capacidad al ejecutable del intérprete, lo que por supuesto es una pesadilla de seguridad, ya que cualquier programa que use ese intérprete tendrá la capacidad. No pude encontrar ninguna manera limpia y fácil de solucionar este problema.
  3. Linux se desactivará LD_LIBRARY_PATHen cualquiera programque tenga privilegios elevados como setcapo suid. Entonces, si programusa el suyo propio .../lib/, es posible que deba buscar otra opción, como el reenvío de puertos.

Recursos:

  • capacidades(7) página de manual . Lea esto detenidamente si va a utilizar capacidades en un entorno de producción. Hay algunos detalles realmente complicados sobre cómo se heredan las capacidades a través de llamadas exec() que se detallan aquí.
  • página de manual de setcap
  • "Vincular puertos por debajo de 1024 sin root en GNU/Linux" : el documento que me indicó por primera vez setcap.

Nota: RHEL agregó esto por primera vez en v6 .

Jason C avatar Jan 05 '2009 19:01 Jason C

Actualización 2017:

Usar enlace de autenticación

Descargo de responsabilidad (actualización para 2021): tenga en cuenta que authbindfunciona a través de LD_PRELOAD, que solo se usa si su programa usa libc, lo cual no es (o podría) no ser el caso si su programa está compilado con GO o cualquier otro compilador que evite C. Si usa Vaya, configure el parámetro del kernel para el rango de puertos protegidos, consulte la parte inferior de la publicación. </EndUpdate>

Authbindes mucho mejor que CAP_NET_BIND_SERVICEun kernel personalizado.

  • CAP_NET_BIND_SERVICEotorga confianza al binario pero no proporciona control sobre el acceso por puerto.
  • Authbindotorga confianza al usuario/grupo y proporciona control sobre el acceso por puerto, y admite tanto IPv4 como IPv6 ( últimamente se ha agregado compatibilidad con IPv6 ).
  1. Instalar:apt-get install authbind

  2. Configure el acceso a los puertos relevantes, por ejemplo, 80 y 443 para todos los usuarios y grupos:

    sudo touch /etc/authbind/byport/80
    sudo touch /etc/authbind/byport/443
    sudo chmod 777 /etc/authbind/byport/80
    sudo chmod 777 /etc/authbind/byport/443

  3. Ejecute su comando mediante authbind
    (opcionalmente especificando --deepu otros argumentos, consulte man authbind):

         authbind --deep /path/to/binary command line args
    
     e.g.  
    
         authbind --deep java -jar SomeServer.jar
    

Como seguimiento de la fabulosa recomendación de Joshua (=no recomendada a menos que sepas lo que haces) para hackear el kernel:

Lo publiqué aquí por primera vez .

Simple. Con un kernel normal o viejo, no es así.
Como han señalado otros, iptablesse puede reenviar un puerto.
Como también lo han señalado otros, CAP_NET_BIND_SERVICEtambién puede hacer el trabajo.
Por supuesto CAP_NET_BIND_SERVICE, fallará si inicia su programa desde un script, a menos que establezca el límite en el intérprete de shell, lo cual no tiene sentido, también podría ejecutar su servicio como root...
por ejemplo, para Java, debe aplicarlo a la JVM JAVA

sudo /sbin/setcap 'cap_net_bind_service=ep' /usr/lib/jvm/java-8-openjdk/jre/bin/java

Obviamente, eso significa que cualquier programa Java puede vincular puertos del sistema.
Lo mismo ocurre con mono/.NET.

También estoy bastante seguro de que xinetd no es la mejor idea.
Pero dado que ambos métodos son trucos, ¿por qué no simplemente eliminar el límite eliminando la restricción?
Nadie dijo que tengas que ejecutar un kernel normal, así que puedes ejecutar el tuyo propio.

Simplemente descargue la fuente del kernel más reciente (o el mismo que tiene actualmente). Después vas a:

/usr/src/linux-<version_number>/include/net/sock.h:

Ahí buscas esta línea

/* Sockets 0-1023 can't be bound to unless you are superuser */
#define PROT_SOCK       1024

y cambiarlo a:

#define PROT_SOCK 0

Si no desea tener una situación ssh insegura, cámbiela a esto:

#define PROT_SOCK 24

Generalmente, usaría la configuración más baja que necesite, por ejemplo, 79 para http o 24 cuando use SMTP en el puerto 25.

Eso ya es todo.
Compile el kernel e instálelo.
Reiniciar.
Terminado: ese estúpido límite desapareció, y eso también funciona para los scripts.

Así es como se compila un kernel:

https://help.ubuntu.com/community/Kernel/Compile

# You can get the kernel-source via package `linux-source`, no manual download required
apt-get install linux-source fakeroot

mkdir ~/src
cd ~/src
tar xjvf /usr/src/linux-source-<version>.tar.bz2
cd linux-source-<version>

# Apply the changes to PROT_SOCK define in /include/net/sock.h

# Copy the kernel config file you are currently using
cp -vi /boot/config-`uname -r` .config

# Install ncurses libary, if you want to run menuconfig
apt-get install libncurses5 libncurses5-dev

# Run menuconfig (optional)
make menuconfig

# Define the number of threads you wanna use when compiling (should be <number CPU cores> - 1), e.g. for quad-core
export CONCURRENCY_LEVEL=3
# Now compile the custom kernel
fakeroot make-kpkg --initrd --append-to-version=custom kernel-image kernel-headers

# And wait a long long time

cd ..

En una palabra:

  • Úsalo iptablessi quieres mantenerte seguro,
  • compila el kernel si quieres estar seguro de que esta restricción nunca más te molestará.

método syctl

Nota:
Últimamente ya no es necesario actualizar el kernel.
Ahora puedes configurar:

sysctl net.ipv4.ip_unprivileged_port_start=80

O persistir:

sysctl -w net.ipv4.ip_unprivileged_port_start=80

Y si eso produce un error, simplemente edite /etc/sysctl.confcon nano y configure el parámetro allí para persistencia durante los reinicios.

o víaprocfs

echo 80 | sudo tee /proc/sys/net/ipv4/ip_unprivileged_port_start
Stefan Steiger avatar Jan 16 '2015 17:01 Stefan Steiger

Puedes hacer una redirección de puerto. Esto es lo que hago para un servidor de políticas Silverlight que se ejecuta en una máquina Linux

iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 943 -j REDIRECT --to-port 1300
FlappySocks avatar Nov 19 '2009 11:11 FlappySocks

Por alguna razón, nadie menciona la posibilidad de reducir sysctl net.ipv4.ip_unprivileged_port_start al valor que necesita. Ejemplo: Necesitamos vincular nuestra aplicación al puerto 443.

sysctl net.ipv4.ip_unprivileged_port_start=443

Algunos pueden decir que existe un posible problema de seguridad: los usuarios sin privilegios ahora pueden conectarse a otros puertos privilegiados (444-1024). Pero puedes resolver este problema fácilmente con iptables, bloqueando otros puertos:

iptables -I INPUT -p tcp --dport 444:1024 -j DROP
iptables -I INPUT -p udp --dport 444:1024 -j DROP

Comparación con otros métodos. Este método:

  • desde algún punto es (en mi opinión) incluso más seguro que configurar CAP_NET_BIND_SERVICE/setuid, ya que una aplicación no establece ningún setuid, ni siquiera en parte (las capacidades en realidad lo son). Por ejemplo, para detectar un coredump de una aplicación con capacidad habilitada, necesitará cambiar sysctl fs.suid_dumpable (lo que conduce a otros posibles problemas de seguridad). Además, cuando CAP/suid está configurado, el directorio /proc/PID es propiedad de root, por lo que su usuario no root no tendrá información/control completo del proceso en ejecución, por ejemplo, el usuario no podrá (en casos comunes) determinar qué conexiones pertenecen a la aplicación a través de /proc/PID/fd/ (netstat -aptn | grep PID).
  • tiene una desventaja de seguridad: mientras su aplicación (o cualquier aplicación que use los puertos 443-1024) no funciona por algún motivo, otra aplicación podría tomar el puerto. Pero este problema también podría aplicarse a CAP/suid (en caso de que lo configure en el intérprete, por ejemplo, java/nodejs) e iptables-redirect. Utilice el método systemd-socket para excluir este problema. Utilice el método authbind para permitir únicamente la vinculación de usuarios especiales.
  • no requiere configurar CAP/suid cada vez que implementa una nueva versión de la aplicación.
  • no requiere soporte/modificación de la aplicación, como el método systemd-socket.
  • no requiere reconstrucción del kernel (si la versión en ejecución admite esta configuración de sysctl)
  • no hace LD_PRELOAD como el método authbind/privbind, esto podría afectar potencialmente el rendimiento, la seguridad y el comportamiento (¿lo hace? No lo he probado). En el resto, authbind es un método realmente flexible y seguro.
  • supera el método REDIRECT/DNAT de iptables, ya que no requiere traducción de direcciones, seguimiento del estado de la conexión, etc. Esto solo se nota en sistemas de alta carga.

Dependiendo de la situación, elegiría entre sysctl, CAP, authbind e iptables-redirect. Y es genial que tengamos tantas opciones.

urusha avatar Jul 20 '2018 09:07 urusha