【问题标题】:How non root user able to run on privilige port非root用户如何在特权端口上运行
【发布时间】:2021-09-03 21:06:37
【问题描述】:

我预计以下命令会因权限异常而失败,因为它是以非特权用户身份运行的。但相反,它似乎成功了。

% docker run --rm -u nobody  alpine  nc -l 0.0.0.0 443
% docker exec -it b2b471d05398 sh
~ $ id
uid=65534(nobody) gid=65534(nobody)
~ $ ps
PID   USER     TIME  COMMAND
    1 nobody    0:00 nc -l 0.0.0.0 443
    8 nobody    0:00 sh
   15 nobody    0:00 ps
~ $ %

我尝试禁用各种功能,但这些都不能阻止nc 成功运行并绑定到端口。

docker run --rm -u nobody --cap-drop=SETUID --cap-drop=NET_BIND_SERVICE --cap-drop=SETFCAP --cap-drop=NET_RAW  alpine  nc -l 0.0.0.0 443

针对 David Maze 的回答, 我用Debian GNU/Linux 构建了一个图像。

这里是Dockerfile:

FROM python:slim-buster
EXPOSE 80
USER nobody
CMD python -m http.server 80

docker build 命令

docker build -t test .

非root用户仍然可以绑定特权端口

docker run  --rm test

我也试过这个来放弃这个功能:

docker run  --rm --cap-drop=SETUID --cap-drop=NET_BIND_SERVICE --cap-drop=SETFCAP --cap-drop=NET_RAW  test

知道我应该怎么做才能删除该功能并触发我试图重现的错误吗?

【问题讨论】:

  • 我试图理解这里的问题,443端口只在容器内部运行,并没有暴露在外部机器中。每个容器内会有多个用户吗?
  • 假设您试图让 Docker 接管您的 public 端口 443,如果不获取这些特权,就无法真正获得对特权资源的访问。您可以通过配置sudo 来限制您的权限,以尽可能地限制它们;但在这种情况下,能够运行sudo docker run 可能已经足以接管系统,因此不清楚如何有效地限制此命令的权限。我的建议是简单地运行它并承担后果。 (但你不是这样做的。)
  • 我应该得到绑定异常,而不是绑定端口。那应该是小于1024的行为端口号不应该被非root用户打开

标签: linux docker


【解决方案1】:

TL;DR: 在你的命令中包含选项--sysctl "net.ipv4.ip_unprivileged_port_start=1024"


长答案:

在docker docs 中声明

警告

docker 组授予 root 用户等效权限。

这不是指您打算在容器内使用的用户,而是您的 ${USER}。这是重要,因为这将授予所有 docker 可以做的事情!

但是,虽然没有人不是可以登录的正确用户,但存在 uid,docker 将使用该 uid 运行程序。 see here

我没有在 alpine nc 上找到任何合适的资源,但测试它似乎没有正确打开端口。

python 服务器在测试时提供更多洞察力。

环顾四周可以发现,docker bridge 接口不包括在端口开放限制中。请看issuemerge。

如果您尝试以下操作,您会发现主机网络的安全性正常工作。

正确的权限被拒绝:

docker run -u nobody --cap-drop=all --network host --rm python:slim-buster python -m http.server 80
docker run  --cap-drop=all --network host --rm python:slim-buster python -m http.server 80
docker run -u nobody --network host --rm python:slim-buster python -m http.server 80

工作:

docker run --network host --rm python:slim-buster python -m http.server 80

为桥梁工作

docker run -u nobody --cap-drop=all --rm python:slim-buster python -m http.server 80

像往常一样查看他们的tests,您会发现“答案”是您潜在问题的答案。

再次拒绝所有 3 种风格的权限

docker run -u nobody --cap-drop=all --sysctl "net.ipv4.ip_unprivileged_port_start=1024" --rm python:slim-buster  python -m http.server 80
docker run -u nobody --sysctl "net.ipv4.ip_unprivileged_port_start=1024" --rm python:slim-buster  python -m http.server 80
docker run --cap-drop=all --sysctl "net.ipv4.ip_unprivileged_port_start=1024" --rm python:slim-buster  python -m http.server 80

在这里它适用于 root

docker run --sysctl "net.ipv4.ip_unprivileged_port_start=1024" --rm python:slim-buster  python -m http.server 80

【讨论】:

  • 我会离开一段时间,但必须解决这个问题,否则它会困扰我。不过,我可能需要一点时间才能回复 cmets。
  • 当你想知道某件事是如何工作的,看看他们的测试。正确的测试是最好的文档!
【解决方案2】:

Alpine 基于称为BusyBox 的最小工具集,其中包含许多标准命令行实用程序的自己的实现。 BusyBox 支持的nc 语法是

nc -l -p 443 0.0.0.0

其中-l 设置“监听”模式,-p 443 表示监听端口。 (实际上,如果没有 -p 选项,我希望 BusyBox nc 到 exit immediately 带有 -l 选项和两个位置参数,然后您将无法将 docker exec 放入容器中。)

如果没有 -p 选项,BusyBox nc 将 pick an arbitrary port and print it to stderr。这不会是一个特权端口,这就是为什么你在那里没有收到错误的原因。 docker logs 应该显示端口号,容器内的netstat 应该显示备用端口上的侦听器。

【讨论】:

  • 嗨,大卫,我已将图像从 Alpine 更改为 buster,但非 root 用户仍然能够打开特权端口
  • 更改您的问题以使现有答案不再有效是 Stack Overflow 上不可接受的行为。但是,在这种情况下,我觉得这个答案无论如何只是指出了一个切线的细节。
  • 这个问题仍然有效@tripleee 为什么非root用户能够打开特权端口,即使功能被丢弃
  • 我更新了这个问题,希望能澄清它。有了这个,我认为这个答案不再相关。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-07-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多