systemd 的手动 Desktop-Bus-over-SSH 隧道是否存在安全隐患?

信息安全 SSH 代理人
2021-08-14 04:47:00

在 2017-09-02 上,Peter Wullinger 写道

☑ 到远程 dbus 的隧道连接
☑ 硬编码 ssh(无路径)
☑ 有转义、解析、取消转义错误
☑ 不记录任何这些

当使用or选项时,systemd 会告诉其 D-Bus 库在远程机器上运行一个名为的程序的幕后执行。-H--hostsystemctl该程序充当远程机器上的 D-Bus 代理和本地机器上的 D-Bus 客户端之间的简单消息泵。 只需与通过 SSH 代理的桌面总线对话,就好像它正在与本地系统对话一样。sshsystemd-stdio-bridgesystemctlsystemctlsystemd-stdio-bridge

作为回应,其他人想知道这可能是另一个系统安全问题。是吗?

(这不是关于一般 SSH 安全性的问题,而是关于这个特定的 systemd 机制的问题。对于一般 SSH 安全性,还有其他问题需要考虑,例如“ SSH 隧道的安全性含义是什么? ”。也不是这是一个类似“与 systemv init 相比 systemd 的安全含义是什么? ”的问题。对于初学者来说,这与 van Smoorenburgrc文件无关。)

2个回答

在 Twitter 上讨论这个问题相当于现代费马通过边际讨论数学证明。因此,让我们扩展一下 Peter Wullinger 没有足够的空间将其放入Twitter 帖子的空白处。

当然,systemd 人员可以通过其他方式做到这一点:

  • 建议系统管理员使用

    ssh -x --账户@host systemctl东西……
    代替

    systemctl -H account @ host  stuff
  • 对本地域套接字使用 OpenSSH 的内置转发机制,以便在内部systemctl产生类似的东西

    ssh -xT -L /run/user/用户/账户@host /bus:/run/dbus/system_bus_socket --账户@host / bin /true
    而不是(就像它一样)

    ssh -xT --账户@host systemd -stdio-bridge

实际采用的方法存在许多问题,其中一些安全相关然而,到目前为止,似乎没有一个会上升到完全脆弱的程度。

“这个无证systemd-stdio-bridge程序是什么?”

首先考虑系统管理员查看日志和 的输出ps,并想知道这些人都systemd-stdio-bridge通过 SSH运行从“在我的 VPS 上运行的奇怪的 'agetty' 进程”中可以看出,我们有Weitse Venema 的agetty程序感到好奇的人,我们知道MacOS 已经有恶意软件命名systemd以试图愚弄人们,所以这不是一个延伸也不能不合理地想象系统管理员也会对此感到疑惑systemd-stdio-bridge

问题是,这是另一个 systemd 的 doco 比穷更糟糕的情况:它完全不存在。根本没有由 systemd 人员编写的手册页。systemd-stdio-bridge所以系统管理员的第一选择,就是阅读手册,也无济于事。这是 systemd 人员有意为之,他们没有包括想要在他们的用例中识别正在运行的程序的系统管理员。)

它可能有助于系统管理员了解该程序经历了一个被调用的阶段,systemd-bus-proxyd该阶段有一个手册页。它和手册页都从 systemd 中删除了,但是当systemd 开发人员 David Herrmann 后来带回旧程序时,手册页并没有随之恢复。(注意,如果你去挖掘它,旧的手册页systemd-bus-proxyd并没有正确描述 . 的当前命令行用法systemd-stdio-bridge。)

如果 systemd 开发人员将 doco 与程序一起考虑,他们可能已经发现了一个当前的错误:systemctl在某些情况下传递systemd-stdio-bridge不支持的选项,并支持不使用的systemd-stdio-bridge不同选项。systemctl

“这是什么未记录的sd_bus_set_address东西?”

Peter Wullinger 的注释之一是这些都没有记录在案,对于试图求助于阅读systemd-stdio-bridge程序代码的系统管理员来说,这至少是正确的。这是一个编译的 C 程序,而不是用解释性脚本语言编写的。正如 Peter Wullinger 所指出的,它依赖于调用一个sd_bus_set_address()函数。 systemd 人员不提供手册页sd_bus_set_address(),在其他 systemd 手册页上留下悬空的超链接(例如手册页中的超链接sd_bus_new()

解析错误

最初并不清楚 Peter Wullinger 认为什么是“逃避、解析、逃避错误”。但是在幕后进行了大量的解析;其中最重要的是 systemd 的桌面总线库,它在一个地方从它们的组成部分构造诸如“ unixexec:path=ssh,argv1=-xT,argv2=--,argv3=account%40host,argv4=systemd-stdio-bridge,arg5=--machine=fred”之类的字符串,然后再将它们解析回另一个地方的组成部分。我们从 Daniel J. Bernstein(以及许多其他人)那里了解到,避免解析的设计,包括这种编组为伪人类可读形式,然后解编回机器可读形式,是一个好主意。

事实证明,Peter Wullinger 指的argv2=--是现在存在的原因。这当然是一个众所周知的问题,很难说它的例证过于广泛。然而,在前面提到的多余的序列化和反序列化中,一个额外的和更微妙的解析相关问题是系统的非常特殊的性质。请注意,要传入的等号字符argv3被转义为%3d. 但是,等号登录arg5=--machine=不会被转义。序列化不遵循与反序列化相同的规则。这样,错误和安全问题就存在了;这是 Daniel J. Bernstein 建议通过不首先进行解析来避免的事情之一。

重新发明轮子

当然,有一种概念systemd-stdio-bridge是对车轮的重新发明,但它还没有把所有的角落都敲掉以使其足够圆。毕竟,如前所述,OpenSSH 有一个内置机制,被广泛使用和测试,用于通过从远程主机到本地机器的 SSH 连接转发对本地域套接字的访问。(它从 OpenSSH 6.7 开始,在 systemd 开发人员 David Herrmann 重新引入该systemd-stdio-bridge程序的前一年发布。自 2006 年以来,该程序的补丁就已经存在,比 systemd 存在早几年。)

反对这一点是两件事。

首先:远程生成一个程序,然后通过其标准输入和输出与它通信,通过 SSH 连接传输,这并不是 SSH 的不寻常用途。rexec毕竟是做事的模式。

第二:必须小心地进行本地域套接字转发。使用标准的 I/O 机制,没有其他 D-Bus 客户端程序可以(缺少调试访问等技巧)使用转发机制将自己连接到远程 D-Bus 代理。然而,上述机制必须小心:

  • 不允许用户以外的任何人访问,以便只有用户(和超级用户)的进程可以访问本地代理套接字/run/user/user/account@host/
  • 防止用户以外的其他人可写,这样其他人就不会出现并偷偷地用符号链接替换或执行其他此类技巧/run/user/user//run/user/user/account@host
  • 注意不要在多次调用之间发生冲突(这可以通过使用本地唯一名称而不是仅仅来完成/run/user/user/account@host/bussystemctlbus

进一步阅读

详细说明在挖掘了一堆 systemd 文档和源代码后发布的一条简短推文(其中没有一个令人愉快,这可能解释了语气)。

整个事情都是由这条推文触发的,这表明 systemd 没有(正如主要开发人员多次指出的那样)验证所有输入。

systemctl --host <host> 记录通过 ssh 远程执行指定的操作。

这是如何工作的

  1. systemctl 将主机参数向下传递到 sd_bus_open_system_remote(),它——作为一个未记录的特性(错误报告)——还 支持 <hostspec>:<machine>表示法来告诉它连接到给定容器中远程主机上的总线。

  2. sd_bus_open_system_remote()构造一个特殊的总线地址unixexec:path=ssh,argv1=-xT,argv2=--,argv3=<hostname>,argv4=systemd-stdio-bridge <container>请注意,这会ssh从目标计算机$PATH的目标用户systemd-stdio-bridge的远程进行选择。$PATH这个特殊的总线地址似乎已由systemd 的作者之一添加到 dbus 规范和参考实现中。

  3. 这个字符串被解析(仍然在本地),通过bus_start_address()支持任意 dbus 代理命令unixexec

  4. 最后,这会触发bus_start_address()执行提供的命令行并通过管道到该程序的 stdin/stdout 执行 dbus。

据我所知,这是三层未记录的间接,以获得一个简单的便利功能,您也可以使用ssh <host> systemctl --machine <machine>.

这种隐含的魔法通常会让我的内部错误搜索器自动驾驶。

好吧,有一个,但这并不重要:在最近提交之前,将从主机名中systemctl删除第一个之后的所有内容,但将其他所有内容作为第一个命令行参数传递给。这仍然在本地执行,并且从命令行非常明显,所以它似乎不是什么大问题。:ssh

但是,考虑到这一切的复杂性,拥有远程代理可能是处理这个问题的更安全的方法之一。-L是有问题的,因为它需要您启用 SSH 端口转发和适当的清理以及本地套接字的适当安全性。-W不支持 unix 域套接字(截至目前)。至少当前方法允许您使用ForceCommand.

真正的安全威胁可能在于整个过程的性质,它用一个基本上没有记录的自动化过程代替了可以明确完成的事情,该过程还硬编码了很多假设。