Es muy molesto tener esta limitación en mi cuadro de desarrollo, cuando no habrá ningún usuario que no sea yo.
Soy consciente de las soluciones estándar , pero ninguna de ellas hace exactamente lo que quiero:
- authbind (la versión en las pruebas de Debian, 1.0, solo admite IPv4)
- 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)
- sudo (Ejecutar como root es lo que estoy tratando de evitar)
- SELinux (o similar). (Este es solo mi cuadro de desarrollo, no quiero introducir mucha complejidad adicional).
¿Existe alguna sysctlvariable simple para permitir que los procesos no root se unan a puertos "privilegiados" (puertos menores de 1024) en Linux, o simplemente no tengo suerte?
EDITAR: en algunos casos, puede usar capacidades para hacer esto.

Respuestas:
Bien, gracias a las personas que señalaron el sistema de
CAP_NET_BIND_SERVICEcapacidades y la capacidad. Si tiene un kernel reciente, de hecho es posible usarlo para iniciar un servicio como no raíz pero enlazar puertos bajos. La respuesta corta es que haces:Y luego, en cualquier momento que
programse ejecute, tendrá laCAP_NET_BIND_SERVICEcapacidad.setcapestá en el paquete debianlibcap2-bin.Ahora para las advertencias:
programque tenga privilegios elevados comosetcaposuid. Entonces, siprogramusa los suyos.../lib/, es posible que deba buscar otra opción, como el reenvío de puertos.Recursos:
setcap.Nota: RHEL primero agregó esto en v6 .
fuente
/usr/bin/javay luego abriría la capacidad a cualquier aplicación Java que se ejecute en el sistema. Las capacidades demasiado malas tampoco se pueden establecer por usuario./etc/security/capability.confDebian / Ubuntu alguna ayuda?Puede hacer una redirección de puerto. Esto es lo que hago para un servidor de políticas Silverlight que se ejecuta en un cuadro de Linux
fuente
/etc/network/if-up.d/firewall.La forma estándar es hacerlos "setuid" para que se inicien como root, y luego descarten ese privilegio de root tan pronto como se unan al puerto pero antes de que comiencen a aceptar conexiones a él. Puede ver buenos ejemplos de eso en el código fuente de Apache e INN. Me dicen que Lighttpd es otro buen ejemplo.
Otro ejemplo es Postfix, que utiliza múltiples demonios que se comunican a través de tuberías, y solo uno o dos de ellos (que hacen muy poco, excepto aceptar o emitir bytes) se ejecutan como root y el resto se ejecuta con un privilegio menor.
fuente
binfmt_miscsu bandera 'C'; no estoy seguro de los demás.)O parchear su núcleo y eliminar el cheque.
(Opción de último recurso, no recomendado).
En
net/ipv4/af_inet.c, elimine las dos líneas que leeny el kernel ya no verificará los puertos privilegiados.
fuente
Puede configurar un túnel SSH local, por ejemplo, si desea que el puerto 80 llegue a su aplicación vinculada a 3000:
Esto tiene la ventaja de trabajar con servidores de script y ser muy simple.
fuente
sudo nc -l 80 | nc localhost 3000Actualización 2017:
Use authbind
Mucho mejor que CAP_NET_BIND_SERVICE o un kernel personalizado.
Authbind otorga confianza al usuario / grupo y proporciona control sobre el acceso por puerto, y es compatible con IPv4 e IPv6 (últimamente se ha agregado compatibilidad con IPv6).
Instalar en pc:
apt-get install authbindConfigure el acceso a los puertos relevantes, por ejemplo, 80 y 443 para todos los usuarios y grupos:
Ejecute su comando vía
authbind(opcionalmente especificando
--deepu otros argumentos, vea la página del manual):p.ej
Como seguimiento a la fabulosa (no recomendada de Joshua a menos que sepas lo que haces) recomendación para hackear el kernel:
Lo publiqué por primera vez aquí .
Simple. Con un núcleo normal o antiguo, no lo hace.
Como señalaron otros, iptables puede reenviar un puerto.
Como también señalaron otros, CAP_NET_BIND_SERVICE también puede hacer el trabajo.
Por supuesto, CAP_NET_BIND_SERVICE fallará si inicia su programa desde un script, a menos que configure el límite en el intérprete de shell, lo cual no tiene sentido, podría ejecutar su servicio como root ...
por ejemplo, para Java, debe aplicarlo a la JVM JAVA
Obviamente, eso significa que cualquier programa Java puede enlazar puertos del sistema.
Dito para mono / .NET.
También estoy bastante seguro de que xinetd no es la mejor de las ideas.
Pero dado que ambos métodos son hacks, ¿por qué no simplemente levantar el límite levantando la restricción?
Nadie dijo que tenía que ejecutar un núcleo normal, por lo que puede ejecutar el suyo.
Simplemente descargue la fuente del último kernel (o el mismo que tiene actualmente). Luego, vas a:
Ahí buscas esta línea
y cambiarlo a
si no desea tener una situación ssh insegura, modifíquela a esto: #define PROT_SOCK 24
En general, 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 núcleo e instálelo.
Reiniciar.
Terminado: ese límite estúpido se ha ido, y eso también funciona para los scripts.
Así es como compila un núcleo:
https://help.ubuntu.com/community/Kernel/Compile
En pocas palabras, use iptables si desea mantenerse seguro, compile el kernel si desea asegurarse de que esta restricción nunca lo moleste nuevamente.
fuente
Las capacidades de archivo no son ideales, porque pueden romperse después de una actualización del paquete.
La solución ideal, en mi humilde opinión, debería ser la capacidad de crear un shell con un
CAP_NET_BIND_SERVICEconjunto heredable .Aquí hay una forma algo complicada de hacer esto:
capshLa utilidad se puede encontrar en el paquete libcap2-bin en las distribuciones Debian / Ubuntu. Esto es lo que pasa:sgcambia la identificación efectiva del grupo a la del usuario daemon. Esto es necesario porquecapshdeja GID sin cambios y definitivamente no lo queremos.$DAEMONUSER--keep=1), excepto heredablescap_net_bind_serviceEl resultado es un proceso con usuario y grupo especificados, y
cap_net_bind_serviceprivilegios.Como ejemplo, una línea del
ejabberdscript de inicio:fuente
capshhacer otra cosa que "no puedo ejecutar el archivo binario" cuando uso las opciones--o==. Me pregunto qué me estoy perdiendo.--se pasa a/bin/bash, por lo que es posible que desee probar-c 'your command'. Por desgracia, parece que estoy experimentando el mismo problema que @Cyberax, porque obtengo un "permiso denegado" cuando intentobind.--giden lugar desg(o--userqué conjuntos--uid,--gidy--groups):sudo capsh --caps='cap_net_bind_service+eip cap_setpcap,cap_setuid,cap_setgid+ep' --keep=1 --user="$service_user" --addamb=cap_net_bind_service -- -c 'exec $service $service_args'Por alguna razón, nadie menciona acerca de reducir sysctl net.ipv4.ip_unprivileged_port_start al valor que necesita. Ejemplo: necesitamos vincular nuestra aplicación al puerto 443.
Algunos pueden decir que existe un posible problema de seguridad: los usuarios no privilegiados ahora pueden unirse a los otros puertos privilegiados (444-1024). Pero puede resolver este problema fácilmente con iptables, bloqueando otros puertos:
Comparación con otros métodos. Este método:
Dependiendo de la situación, elegiría entre sysctl, CAP, authbind e iptables-redirect. Y esto es genial porque tenemos tantas opciones.
fuente
Otras dos posibilidades simples:
Hay una solución antigua (pasada de moda) para "un demonio que se une a un puerto bajo y controla las manos de su demonio". Se llama inetd (o xinetd). Los contras son:
Pros:
Otra alternativa: un proxy pirateado (netcat o incluso algo más robusto ) desde el puerto privilegiado a algún puerto arbitrario de alto número donde puede ejecutar su demonio de destino. (Netcat obviamente no es una solución de producción, sino "solo mi caja de desarrollo", ¿verdad?). De esta manera, podría continuar utilizando una versión de su servidor con capacidad de red, solo necesitaría root / sudo para iniciar el proxy (en el arranque), no dependería de capacidades complejas / potencialmente frágiles.
fuente
Mi "solución estándar" usa socat como redirector de espacio de usuario:
Tenga en cuenta que esto no escalará, la bifurcación es costosa pero es la forma en que funciona socat.
fuente
Linux admite capacidades para admitir permisos más específicos que simplemente "esta aplicación se ejecuta como root". Una de esas capacidades es la
CAP_NET_BIND_SERVICEque se trata de vincular a un puerto privilegiado (<1024).Desafortunadamente, no sé cómo explotar eso para ejecutar una aplicación como no root mientras la sigo dando
CAP_NET_BIND_SERVICE(probablemente usandosetcap, pero seguramente habrá una solución existente para esto).fuente
Sé que esta es una vieja pregunta, pero ahora con núcleos recientes (> = 4.3) finalmente hay una buena respuesta a esto: capacidades ambientales.
La respuesta rápida es tomar una copia de la última versión (aún no publicada) de libcap de git y compilarla. Copie el
progs/capshbinario resultante en alguna parte (/usr/local/bines una buena opción). Luego, como root, inicie su programa conEn orden, somos
cap_net_bind_servicecapacidad a los conjuntos heredados y ambientalesbash -c 'your-command'(ya quecapshautomáticamente comienza a golpear con los argumentos después--)Aquí pasan muchas cosas debajo del capó.
En primer lugar, nos estamos ejecutando como root, por lo que, de forma predeterminada, obtenemos un conjunto completo de capacidades. Se incluye en esto la capacidad de cambiar uid & gid con las llamadas al sistema
setuidysetgid. Sin embargo, normalmente cuando un programa hace esto, pierde su conjunto de capacidades, esto es para que la antigua forma de eliminar la raízsetuidaún funcione. El--keep=1indicador le indicacapshque emita laprctl(PR_SET_KEEPCAPS)llamada al sistema, que deshabilita la pérdida de capacidades al cambiar de usuario. El cambio real de usuarios porcapshocurre con la--userbandera, que se ejecutasetuidysetgid.El siguiente problema que debemos resolver es cómo establecer capacidades de una manera que continúe después de que
execnuestros hijos. El sistema de capacidades siempre ha tenido un conjunto de capacidades 'heredado', que es "un conjunto de capacidades preservadas en un execve (2)" [ capacidades (7) ]. Si bien esto suena como que resuelve nuestro problema (solo establece lacap_net_bind_servicecapacidad de heredado, ¿verdad?), Esto en realidad solo se aplica a procesos privilegiados, y nuestro proceso ya no es privilegiado, porque ya cambiamos de usuario (con la--userbandera).El nuevo conjunto de capacidades ambientales soluciona este problema: es "un conjunto de capacidades que se conservan en un execve (2) de un programa que no tiene privilegios". Al poner
cap_net_bind_serviceel entorno, cuando elcapshejecutivo es nuestro programa de servidor, nuestro programa heredará esta capacidad y podrá vincular a los oyentes a puertos bajos.Si está interesado en obtener más información, la página del manual de capacidades explica esto con gran detalle. Correr
capsha travésstracetambién es muy informativo!fuente
--addambbandera se introdujo con libcap 2.26. Mi sistema tenía 2.25 y tuve que construir desde la fuente.TLDR: Para "la respuesta" (tal como la veo), salte a la parte >> TLDR << en esta respuesta.
De acuerdo, lo he descubierto (de verdad esta vez), la respuesta a esta pregunta, y esta respuesta mía también es una forma de disculparme por promover otra respuesta (tanto aquí como en Twitter) que pensé que era "la mejor ", pero después de intentarlo, descubrí que me había equivocado al respecto. Aprenda de mi error, niños: ¡no promocionen algo hasta que lo hayan intentado ustedes mismos!
Nuevamente, revisé todas las respuestas aquí. He probado algunos de ellos (y elegí no probar otros porque simplemente no me gustaron las soluciones). Pensé que la solución era utilizar
systemdcon susCapabilities=yCapabilitiesBindingSet=ajustes. Después de luchar con esto por un tiempo, descubrí que esta no es la solución porque:¡Las capacidades están destinadas a restringir los procesos raíz!
Como el OP declaró sabiamente, siempre es mejor evitar eso (¡para todos tus demonios si es posible!).
No puede usar las opciones relacionadas con Capacidades con
User=yGroup=ensystemdarchivos de unidad, porque las capacidades SIEMPRE se restablecen cuandoexecev(o como se llame la función). En otras palabras, cuando sesystemdbifurca y cae sus permisos, las capacidades se restablecen. No hay forma de evitar esto, y toda esa lógica de enlace en el núcleo es básica en torno a uid = 0, no a las capacidades. Esto significa que es poco probable que Capacidades sea la respuesta correcta a esta pregunta (al menos en el corto plazo). Por cierto,setcapcomo otros han mencionado, no es una solución. No funcionó para mí, no funciona bien con los scripts, y estos se restablecen de todos modos cada vez que cambia el archivo.En mi exigua defensa, dije (en el comentario que eliminé ahora), que la sugerencia de iptables de James (que también menciona el OP) era la "segunda mejor solución". :-PAGS
>> TLDR <<
La solución es combinarla
systemdconiptablescomandos sobre la marcha , como este ( tomado de DNSChain ):Aquí logramos lo siguiente:
iptablessystemdlimpia las reglas del firewall para nosotros, asegurándonos de eliminarlas cuando el demonio no se está ejecutando.systemdafirma), supuestamente incluso si el demonio se ve comprometido y se estableceuid=0.iptablessigue siendo, desafortunadamente, una utilidad bastante fea y difícil de usar. Si el demonio está escuchando eneth0:0lugar deeth0, por ejemplo, los comandos son ligeramente diferentes .fuente
eth0:0nunca más a menos que tengan una distribución de Linux realmente antigua . Han quedado en desuso durante años y eventualmente desaparecerán.# Generated by SolusVMAmbientCapabilities=CAP_NET_BIND_SERVICEfuncionó perfectamente bien para mí en combinación conUser=.systemd es un reemplazo de sysvinit que tiene la opción de lanzar un demonio con capacidades específicas. Opciones Capacidades =, CapabilityBoundingSet = en la página de manual systemd.exec (5) .
fuente
systemd.La redirección de puertos tenía más sentido para nosotros, pero nos encontramos con un problema en el que nuestra aplicación resolvería una URL localmente que también necesitaba ser redirigida; (eso significa que eres shindig ).
Esto también le permitirá ser redirigido al acceder a la url en la máquina local.
fuente
Soportes modernos de Linux
/sbin/sysctl -w net.ipv4.ip_unprivileged_port_start=0.fuente
Con systemd, solo necesita modificar ligeramente su servicio para aceptar sockets preactivados.
Más tarde puede usar systemd socket active .
No se necesitan capacidades, iptables u otros trucos.
Este es el contenido de los archivos systemd relevantes de este ejemplo de servidor http python simple
Expediente
httpd-true.serviceExpediente
httpd-true.socketfuente
Al inicio:
Luego puede unirse al puerto al que desea reenviar.
fuente
--to-portexiste?man iptablessolo menciona--to-ports(plural).systemd.Use la utilidad privbind : permite que una aplicación sin privilegios se una a puertos reservados.
fuente
También existe la 'forma djb'. Puede usar este método para iniciar su proceso como root que se ejecuta en cualquier puerto bajo tcpserver, luego le dará el control del proceso al usuario que especifique inmediatamente después de que comience el proceso.
Para obtener más información, consulte: http://thedjbway.b0llix.net/daemontools/uidgid.html
fuente
Dado que el OP es solo desarrollo / prueba, las soluciones menos que elegantes pueden ser útiles:
setcap se puede usar en el intérprete de un script para otorgar capacidades a los scripts. Si setcaps en el binario del intérprete global no es aceptable, haga una copia local del binario (cualquier usuario puede hacerlo) y obtenga root para setcap en esta copia. Python2 (al menos) funciona correctamente con una copia local del intérprete en su árbol de desarrollo de scripts. No se necesita suid para que el usuario root pueda controlar a qué capacidades tienen acceso los usuarios.
Si necesita realizar un seguimiento de las actualizaciones de todo el sistema para el intérprete, utilice un script de shell como el siguiente para ejecutar su script:
fuente
Probé el método de REDUCCIÓN DE PREROUTING de iptables. En núcleos anteriores parece que este tipo de regla no era compatible con IPv6 . Pero aparentemente ahora es compatible con ip6tables v1.4.18 y Linux kernel v3.8.
También descubrí que PREROUTING REDIRECT no funciona para conexiones iniciadas dentro de la máquina. Para trabajar para conexiones desde la máquina local, agregue también una regla de SALIDA - vea la redirección de puerto de iptables que no funciona para localhost . Por ejemplo, algo como:
También descubrí que PREROUTING REDIRECT también afecta los paquetes reenviados . Es decir, si la máquina también reenvía paquetes entre interfaces (por ejemplo, si actúa como un punto de acceso Wi-Fi conectado a una red Ethernet), entonces la regla de iptables también detectará las conexiones de los clientes conectados a los destinos de Internet y los redirigirá a la máquina. Eso no era lo que quería: solo quería redirigir las conexiones que se dirigían a la máquina misma. Descubrí que puedo hacer que solo afecte los paquetes dirigidos a la caja, agregando
-m addrtype --dst-type LOCAL. Por ejemplo, algo como:Otra posibilidad es utilizar el reenvío de puertos TCP. Por ejemplo, usando
socat:Sin embargo, una desventaja de ese método es que la aplicación que está escuchando en el puerto 8080 no conoce la dirección de origen de las conexiones entrantes (por ejemplo, para el registro u otros fines de identificación).
fuente
Respuesta en 2015 / septiembre:
ip6tables ahora es compatible con IPV6 NAT: http://www.netfilter.org/projects/iptables/files/changes-iptables-1.4.17.txt
Necesitarás el kernel 3.7+
Prueba:
fuente