Есть ли способ для некорневых процессов связываться с «привилегированными» портами в Linux? - PullRequest
353 голосов
/ 05 января 2009

Очень неприятно иметь такое ограничение на моем блоке разработки, когда не будет никаких пользователей, кроме меня.

Мне известны стандартные обходные пути , но никто из них не делает именно то, что я хочу:

  1. authbind (версия в тестировании Debian, 1.0, поддерживает только IPv4)
  2. Использование цели iptables REDIRECT для перенаправления низкого порта на высокий порт (таблица "nat" еще не реализована для ip6tables, версии iptables IPv6)
  3. sudo (Запуск от имени root - это то, чего я пытаюсь избежать)
  4. SELinux (или аналогичный). (Это всего лишь мой блок разработчика, я не хочу вводить много дополнительной сложности.)

Существует ли какая-либо простая переменная sysctl, позволяющая процессам без полномочий root связываться с "привилегированными" портами (портами менее 1024) в Linux, или мне просто не повезло?

РЕДАКТИРОВАТЬ: В некоторых случаях вы можете использовать возможности , чтобы сделать это.

Ответы [ 22 ]

362 голосов
/ 05 января 2009

Хорошо, спасибо людям, которые указали на возможности системы и CAP_NET_BIND_SERVICE возможности. Если у вас последнее ядро, это действительно возможно использовать для запуска службы без полномочий root, но для привязки низких портов. Короткий ответ, что вы делаете:

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

И затем каждый раз, когда выполняется program, он будет иметь возможность CAP_NET_BIND_SERVICE. setcap находится в пакете debian libcap2-bin.

Теперь о предостережениях:

  1. Вам понадобится как минимум ядро ​​2.6.24
  2. Это не будет работать, если ваш файл представляет собой скрипт. (т. е. использует строку #! для запуска интерпретатора). В этом случае, насколько я понимаю, вам придется применить эту возможность к самому исполняемому файлу интерпретатора, что, конечно, является кошмаром безопасности, поскольку любая программа, использующая этот интерпретатор, будет иметь такую ​​возможность. Я не смог найти какой-либо простой и простой способ обойти эту проблему.
  3. Linux отключит LD_LIBRARY_PATH для любого program с повышенными привилегиями, например setcap или suid. Поэтому, если ваш program использует свой собственный .../lib/, вам, возможно, придется поискать другой вариант, например переадресацию портов.

Ресурсы:

Примечание: RHEL впервые добавил это в v6 .

31 голосов
/ 05 января 2009

Стандартный способ состоит в том, чтобы сделать их "setuid", чтобы они запускались от имени пользователя root, а затем они отбрасывают эту привилегию root, как только они привязаны к порту, но до того, как начинают принимать подключения к нему. Вы можете увидеть хорошие примеры этого в исходном коде для Apache и INN. Мне сказали, что Lighttpd - еще один хороший пример.

Другим примером является Postfix, который использует несколько демонов, которые обмениваются данными по каналам, и только один или два из них (которые делают очень мало, за исключением принимаемых или отправляемых байтов) работают в качестве пользователя root, а остальные работают с более низким уровнем привилегий.

28 голосов
/ 19 ноября 2009

Вы можете сделать перенаправление порта. Это то, что я делаю для сервера политики Silverlight, работающего на Linux box

iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 943 -j REDIRECT --to-port 1300
19 голосов
/ 05 января 2009

Или исправьте ядро ​​и уберите галочку.

(опция последней инстанции, не рекомендуется).

В net/ipv4/af_inet.c удалите две строки, которые читают

      if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
              goto out;

и ядро ​​больше не будет проверять привилегированные порты.

19 голосов
/ 03 августа 2013

Вы можете настроить локальный туннель SSH, например, если вы хотите, чтобы порт 80 достиг вашего приложения, привязанного к 3000:

sudo ssh $USERNAME@localhost -L 80:localhost:3000 -N

Это имеет преимущество работы с серверами сценариев и очень простое.

18 голосов
/ 09 октября 2011

Возможности файлов не идеальны, потому что они могут сломаться после обновления пакета.

Идеальным решением, ИМХО, должна быть возможность создания оболочки с наследуемым CAP_NET_BIND_SERVICE набором.

Вот несколько запутанный способ сделать это:

sg $DAEMONUSER "capsh --keep=1 --uid=`id -u $DAEMONUSER` \
     --caps='cap_net_bind_service+pei' -- \
     YOUR_COMMAND_GOES_HERE"

capsh утилита находится в пакете libcap2-bin в дистрибутивах Debian / Ubuntu. Вот что происходит:

  • sg изменяет эффективный идентификатор группы на идентификатор пользователя демона. Это необходимо, потому что capsh оставляет GID без изменений, и мы определенно не хотим его.
  • Устанавливает бит «сохранить возможности при изменении UID».
  • Изменяет UID на $DAEMONUSER
  • Отбрасывает все заглавные буквы (на данный момент все заглавные буквы все еще присутствуют из-за --keep=1), кроме наследуемых cap_net_bind_service
  • Выполняет вашу команду ('-' является разделителем)

Результатом является процесс с указанными пользователем и группой и привилегиями cap_net_bind_service.

Например, строка из ejabberd сценария запуска:

sg $EJABBERDUSER "capsh --keep=1 --uid=`id -u $EJABBERDUSER` --caps='cap_net_bind_service+pei' -- $EJABBERD --noshell -detached"
15 голосов
/ 06 января 2009

Две другие простые возможности:

Существует старое (немодное) решение для «демона, который привязывается к низкому порту и передает управление вашему демону». Это называется inetd (или xinetd). Минусы:

  • ваш демон должен общаться по stdin / stdout (если вы не управляете демоном - если у вас нет источника - тогда это, возможно, showtopper, хотя некоторые службы могут иметь флаг совместимости с inetd )
  • новый процесс-демон разветвляется для каждого соединения
  • это одно дополнительное звено в цепочке

Плюсы:

  • доступно на любой старой UNIX
  • как только ваш системный администратор настроит конфигурацию, вы можете приступить к разработке (когда вы пересобираете своего демона, можете ли вы потерять возможности setcap? И тогда вам придется вернуться к администратору), пожалуйста сэр ... ")
  • демон не должен беспокоиться об этом сетевом материале, он просто должен поговорить по stdin / stdout
  • можно настроить для запуска вашего демона от имени пользователя без полномочий root, в соответствии с запросом

Другая альтернатива: взломанный прокси (netcat или даже что-то более надежный ) из привилегированного порта в произвольный порт с высоким номером, где вы можете запустить целевой демон. (Очевидно, что Netcat - это не производственное решение, а «просто мой компьютер разработчика», верно?). Таким образом, вы можете продолжать использовать версию вашего сервера с поддержкой сети, для запуска прокси-сервера (при загрузке) потребуется только root / sudo, не полагаясь на сложные / потенциально хрупкие возможности.

14 голосов
/ 15 июня 2009

Мой "стандартный обходной путь" использует socat в качестве перенаправителя пространства пользователя:

socat tcp6-listen:80,fork tcp6:8080

Остерегайтесь, что это не будет масштабироваться, разветвление дорого, но так работает socat.

14 голосов
/ 16 января 2015

Обновление 2017:

Использовать authbind


Гораздо лучше, чем CAP_NET_BIND_SERVICE или пользовательское ядро.

  • CAP_NET_BIND_SERVICE предоставляет доверие к двоичному файлу, но не предоставляет контроль доступа к порту.
  • Authbind предоставляет доверие пользователь / группа и обеспечивает контроль доступа к каждому порту; поддерживает как IPv4, так и IPv6 (поддержка IPv6 была добавлена ​​в последнее время).

    1. Установка: apt-get install authbind

    2. Настройка доступа к соответствующим портам, например, 80 и 443 для всех пользователей и групп:

      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. Выполните команду с помощью authbind
      (необязательно указав --deep или другие аргументы, см. справочную страницу):

      authbind --deep /path/to/binary command line args
      

      например.

      authbind --deep java -jar SomeServer.jar
      
<ч />

В качестве продолжения невероятной (= не рекомендуется, если вы не знаете, что делаете) Джошуа рекомендации взломать ядро:

Я впервые опубликовал это здесь .

Simple. С нормальным или старым ядром у вас нет.
Как отмечают другие, iptables может переадресовывать порт.
Как также отметили другие, CAP_NET_BIND_SERVICE также может выполнять эту работу.
Конечно, CAP_NET_BIND_SERVICE потерпит неудачу, если вы запустите свою программу из скрипта, если вы не установите ограничение на интерпретатор оболочки, что бессмысленно, вы также можете запустить свой сервис как root ...
например для Java вы должны применить его к JAVA JVM

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

Очевидно, это означает, что любая Java-программа может связывать системные порты.
Дито для моно / .NET.

Я также уверен, что xinetd - не самая лучшая идея.
Но поскольку оба метода являются хакерами, почему бы просто не снять ограничение, сняв ограничение?
Никто не говорил, что вам нужно запустить нормальное ядро, поэтому вы можете просто запустить свое собственное.

Вы просто скачиваете исходный код для последнего ядра (или того же, что у вас есть в настоящее время). После этого вы переходите к:

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

Вот вы ищете эту строку

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

и измените его на

#define PROT_SOCK 0

если вы не хотите иметь небезопасную ситуацию с ssh, измените ее следующим образом: #define PROT_SOCK 24

Как правило, я бы использовал самый низкий параметр, который вам нужен, например, 79 для http или 24 при использовании SMTP для порта 25.

Это уже все.
Скомпилируйте ядро ​​и установите его.
Перезагрузка.
Закончено - этот глупый предел ушел, и это также работает для сценариев.

Вот как вы собираете ядро:

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 ..

В двух словах, используйте iptables, если хотите оставаться в безопасности, скомпилируйте ядро, если хотите быть уверенным, что это ограничение больше вас не беспокоит.

13 голосов
/ 27 мая 2016

Я знаю, что это старый вопрос, но теперь с последними (> = 4.3) ядрами, наконец, есть хороший ответ на это - окружающие возможности.

Быстрый ответ - получить копию последней (пока не выпущенной) версии libcap из git и скомпилировать ее. Скопируйте полученный progs/capsh бинарный файл куда-нибудь (/usr/local/bin - хороший выбор). Затем с правами root запустите вашу программу с

/usr/local/bin/capsh --keep=1 --user='your-service-user-name' \
    --inh='cap_net_bind_service' --addamb='cap_net_bind_service' \ 
    -- -c 'your-program'

В порядке, мы

  • Заявив, что когда мы переключаем пользователей, мы хотим сохранить наши текущие наборы возможностей
  • Переключение пользователя и группы на 'your-service-user-name'
  • Добавление возможности cap_net_bind_service к унаследованным и окружающим наборам
  • Форкинг bash -c 'your-command' (поскольку capsh автоматически запускает bash с аргументами после --)

Здесь много всего происходит под капотом.

Во-первых, мы работаем как root, поэтому по умолчанию мы получаем полный набор возможностей. В это входит возможность переключать uid & gid с помощью системных вызовов setuid и setgid. Однако обычно, когда программа делает это, она теряет набор своих возможностей - это так, что старый способ удаления root с setuid все еще работает. Флаг --keep=1 указывает capsh на системный вызов prctl(PR_SET_KEEPCAPS), который отключает сброс возможностей при смене пользователя. Фактическое изменение пользователей на capsh происходит с флагом --user, который запускает setuid и setgid.

Следующая проблема, которую нам нужно решить, - это как настроить способности так, чтобы они продолжались после того, как мы exec будем нашими детьми. Система возможностей всегда имела «унаследованный» набор возможностей, который является «набором возможностей, сохраненных в execve (2)» [abilities (7) ]. Хотя это звучит так, как будто это решает нашу проблему (просто установите для cap_net_bind_service возможность наследоваться, верно?), На самом деле это применимо только к привилегированным процессам - и наш процесс больше не является привилегированным, потому что мы уже изменили пользователя (с --user флаг).

Новый набор возможностей окружения работает вокруг этой проблемы - это «набор возможностей, которые сохраняются в execve (2) программы, которая не является привилегированной». Поместив cap_net_bind_service в окружение, когда capsh exec будет нашей серверной программой, наша программа унаследует эту возможность и сможет привязывать слушателей к низким портам.

Если вам интересно узнать больше, то справка на странице руководства объясняет это очень подробно. Запуск с capsh по strace также очень информативен!

...