OpenSSH用户枚举漏洞:一探究竟

栏目: 服务器 · 发布时间: 6年前

内容简介:本文翻译自:OpenSSH用户枚举漏洞(CVE-2018-15473)是由这个漏洞虽然不会生成有效用户名的列表名单,但它允许猜测用户名。

本文翻译自: https://blog.nviso.be/2018/08/21/openssh-user-enumeration-vulnerability-a-close-look/

介绍

OpenSSH用户枚举漏洞(CVE-2018-15473)是由 GitHub commit 公开的。

这个漏洞虽然不会生成有效用户名的列表名单,但它允许猜测用户名。

在这篇博客文章中,我们对这个漏洞进行了更深入的研究,并提出了缓解措施和监控措施。

技术细节

该漏洞表现在OpenSSH的几个认证功能中。我们密切关注Ubuntu OpenSSH实现的公钥认证中的这个漏洞。

通过向OpenSSH服务器发送格式错误的公钥认证消息,可以确定特定用户名的存在。如果用户不存在,则向客户端发送认证失败消息。如果用户存在,解析消息失败将中止通信:连接将在不发送任何消息的情况下关闭。此漏洞在 Python 的PoC脚本中实现。

该漏洞是因为在对消息进行完全解析之前,存在用户名不存在的通信。修复漏洞本质上是简单的:逆向逻辑。首先完全解析消息,然后进行通信。

测试PoC的一种方法是在调试模式下启动OpenSSH服务器:

OpenSSH用户枚举漏洞:一探究竟

之后,使用已存在的用户名执行PoC脚本

OpenSSH用户枚举漏洞:一探究竟

在服务器端,将会发生错误:

OpenSSH用户枚举漏洞:一探究竟

也可以在/var/log/auth.log中找到这个错误:

OpenSSH用户枚举漏洞:一探究竟

解析消息失败,导致客户端和服务器之间的连接关闭,而且没有来自服务器的消息:

OpenSSH用户枚举漏洞:一探究竟

注意,最后一个报文是粉红色的(即客户端报文),没有后续的蓝色报文(即服务器报文)。

当使用不存在的用户名来执行PoC脚本时:

OpenSSH用户枚举漏洞:一探究竟

没有出现“不完整消息”的错误信息:

OpenSSH用户枚举漏洞:一探究竟

服务器向客户端发回消息:

OpenSSH用户枚举漏洞:一探究竟

在通信结束时注意蓝色服务器报文。

这就是如何利用公钥认证中的漏洞来揭露用户名的有效性。

当然,OpenSSH的行为是在源代码中定义好的。函数 userauth_pubkey 是实现的身份验证功能之一,特别用于通过公钥进行身份验证。验证失败返回0,验证成功则返回1。当收到消息 SSH2_MSG_USERAUTH_REQUEST (类型为publickey)时就会调用它,之后这个结果会被用来将消息 SSH2_MSG_USERAUTH_FAILURESSH2_MSG_USERAUTH_SUCCESS 发送回客户端。

OpenSSH用户枚举漏洞:一探究竟

该函数的逻辑如下:

如果是未知用户名->0

如果是已知用户名,但密钥不正确->0

如果是已知用户名,并且密钥正确 ->1

一个 很聪明的人 想到的是,在步骤1和步骤2之间可以停止执行函数 userauth_pubkey 。步骤1后,函数 userauth_pubkey 从客户端发送的消息中检索字符串。如果这个失败,由于字符串格式错误,进程将停止并关闭连接,而不发送任何消息。

这种情况可能是由函数 packet_get_string 导致的:

OpenSSH用户枚举漏洞:一探究竟

如果用户名存在,则在步骤1之后将从消息中提取字段。

第一个字段为boolean(一个字节),使用 函数packet_get_char() 提取。当认证类型为publickey时,该字段值等于1。接下来是2个字符串:算法和密钥。在SSH消息中,字符串会被编码为 长度-值 键值对。这个字符串由4个字节(即字符串的长度)组成,后面紧跟包含字符串内容的可变字节数。长度会被编码为bigendian(大端)格式,即先存放4字节整数的最高有效字节,然后是较低有效字节。

函数 packet_get_string 从消息中提取并验证字符串, 即检查字符串的长度是否正确。但此功能依赖于其他项:

函数 ssh_packet_get_string 的定义如下:

OpenSSH用户枚举漏洞:一探究竟

函数 ssh_packet_get_string 会调用函数 sshpkt_get_string ,如果其返回值不为0,则调用函数 fatal ,而函数 fatal 会记录严重错误的事件,然后终止OpenSSH进程,且不发回任何消息。

OpenSSH用户枚举漏洞:一探究竟

现在我们来看看另一个函数链:函数 sshpkt_get_string 调用 sshbuf_get_string

OpenSSH用户枚举漏洞:一探究竟

sshbuf_get_string 调用 sshbuf_get_string_direct

OpenSSH用户枚举漏洞:一探究竟

sshbuf_get_string_direct 调用 sshbuf_peek_string_direct

OpenSSH用户枚举漏洞:一探究竟

最后, sshbuf_peek_string_direct 函数实现字符串的验证:

OpenSSH用户枚举漏洞:一探究竟

如果消息中的剩余数据小于4个字节(不能包含字符串的长度),或者消息中的剩余数据小于消息的长度,则返回错误提示信息 SSH_ERR_MESSAGE_INCOMPLETE (在日志中能找到)字符串。

总结这一系列函数:当 packet_get_string 用于从消息中提取字符串时,如果字符串格式错误,则会发生严重的异常,从而导致OpenSSH进程终止。

这正是PoC Python脚本的触发条件。首先,它与OpenSSH服务器建立加密连接,然后发送格式错误的 SSH2_MSG_USERAUTH_REQUEST (类型为publickey)消息。这个脚本将 Paramikoadd_boolean 函数重新定义为 NULL 函数。 Paramiko 是用于SSH通信的Python模块。通过重新定义 add_boolea n函数,消息中省略了布尔字段(就在算法和关键字符串字段之前)。

当函数 userauth_pubkey 解析这个格式错误的消息时,首先读取boolean字段。由于该字段实际上是丢失的,因此读取下一个字段的第一个字节(函数 packet_get_char ):算法字符串的4字节长度的最高有效字节。调用下一个函数 packet_get_string 来读取(并验证)算法字符串。由于缺少boolean字段,毋庸置疑,这注定失败。

以下是格式稍好的消息的解析过程:

OpenSSH用户枚举漏洞:一探究竟

格式错误的消息是缺少boolean值的,但解析函数并不知道这一点,于是它将字符串的第一个字节解析为boolean字段:看起来就像消息向左移一个字节:

OpenSSH用户枚举漏洞:一探究竟

结果就是解析了1907字节长的字符串(0x00000773十六进制),这比消息本身长。因此,函数 ssh_packet_get_string 将调用 fatal 函数,导致OpenSSH进程终止。

漏洞总结

这是一个微妙的错误, 它不是关于缓冲区溢出导致远程代码执行或缺少输入验证的问题。

没有缓冲区溢出,所有输入在使用前都要经过验证。这里的问题是输入验证是在一些功能处理已经发生了之后再发生的:可能出于性能原因,首先检查用户名以查看它是否存在,如果它不存在,那么进一步的输入验证和处理就毫无必要了。

使用已经存在的用户名,将会进行输入验证,并且可以在不发送消息的情况下关闭连接。这可用于导出用户名的存在与否。

这个问题的解决方案很简单:在任何功能处理之前,切换顺序并首先进行所有的输入验证。

在其他身份验证功能中可能会出现相同的错误。一个粗略的,不完整的方法是检查表达式 !authctc-> valid ,如下所示:

OpenSSH用户枚举漏洞:一探究竟

在基于主机的身份验证中的确犯了同样的错误(可以在GitHub commit 中看到):

OpenSSH用户枚举漏洞:一探究竟

以及Kerberos的身份验证:

OpenSSH用户枚举漏洞:一探究竟

并且潜在的SSH1的RSA身份验证(我们没有进一步检查,因为它不再存在于OpenBSD等实现中):

OpenSSH用户枚举漏洞:一探究竟

请注意,这种风险万不可轻视!

结论

您在使用OpenSSH的过程中,可以自己动手来减缓这个漏洞。在修补程序可用并部署之前,可以禁用易受攻击的身份验证机制。例如,通过禁用公钥身份验证,PoC脚本将不再有效,因为已经拒绝了格式错误的身份验证请求。

当然,如果您不使用公钥认证,我们只建议您禁用公钥认证。如果您使用它,请不要切换到密码验证,但继续使用公钥验证!这不是远程执行代码漏洞,而是一个信息泄露漏洞。

您还可以检查日志中是否有利用这个漏洞的迹象。致命错误可能是一个迹象。在Ubuntu上使用这个PoC,致命错误是“不完整的消息”。但是,此消息可能略有不同,具体得看您的OpenSSH版本,其他方法也可以生成格式错误的消息,这可能会导致另一个致命错误。例如,可以构造一个字符串长度超过最大允许值的身份验证请求。

在默认配置中,您只会收到此致命错误。例如,客户端的IP地址将不会被记录。您可以通过将日志级别(LogLevel)从INFO级别提高到VERBOSE级别,从而创建额外的日志条目,其中包含客户端的IP地址。请注意,这将生成更大的日志,并且您应该随时留意日志不会超过您的可用容量。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

深入理解并行编程

深入理解并行编程

[美] Paul E.Mckenney(保罗·E·麦肯尼) / 谢宝友 鲁阳 / 电子工业出版社 / 2017-7-1 / 129

《深入理解并行编程》首先以霍金提出的两个理论物理限制为引子,解释了多核并行计算兴起的原因,并从硬件的角度阐述并行编程的难题。接着,《深入理解并行编程》以常见的计数器为例,探讨其不同的实现方法及适用场景。在这些实现方法中,除了介绍常见的锁以外,《深入理解并行编程》还重点介绍了RCU的使用及其原理,以及实现RCU的基础:内存屏障。最后,《深入理解并行编程》还介绍了并行软件的验证,以及并行实时计算等内容......一起来看看 《深入理解并行编程》 这本书的介绍吧!

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换