内容简介:在本文中,我们将详细分析该漏洞的利用和防范技巧。
简介
OpenSSH 用户枚举漏洞( CVE-2018-15473 )已经通过 Github 公开 ( https://github.com/openbsd/src/commit/779974d35b4859c07bc3cb8a12c74b43b0a7d1e0 ) 。尽管该漏洞不能用来生成有效的用户名列表,但依旧可以拿来枚举猜测用户名。
在本文中,我们将详细分析该漏洞的利用和防范技巧。
技术细节
该漏洞涉及到多个 OpenSSH 中的用户身份验证函数。首先我们来研究下 Ubuntu 下 OpenSSH 中的公钥认证中的这个漏洞。
通过向 OpenSSH 服务器发送一个错误格式的公钥认证请求,可以判断是否存在特定的用户名。如果用户名不存在,那么服务器会发给客户端一个验证失败的消息。如果用户名存在,那么将因为解析失败,不返回任何信息,直接中断通讯。相关的漏洞利用 PoC 脚本链接如下: http://www.openwall.com/lists/oss-security/2018/08/16/1 。
这里涉及的漏洞发生在解析请求前就收到的用户名不存在的请求。修复漏洞的方式也很简单:修改下判断逻辑,先解析信息,再建立通讯。
用来测试该 PoC 的方式如下:先在调试模式下启动 OpenSSH 服务器,
然后运行带有已知用户名的脚本:
在服务器端可以看到报错信息:
这个报错信息也可以在 /var/log/auth.log 目录下找到:
解析请求失败会导致服务器在不返回任何信息的情况下中断客户端和服务器间的通讯:
注意最后一个粉红色的数据包(客户端的数据包),这里没有后续返回的蓝色数据包(服务器数据包)。
当执行一个不存在的用户名的 PoC 脚本时:
没有发生“ incomplete message” 的报错信息:
服务器也返回给客户端一条信息:
注意最后的蓝色(服务器)数据包。
这就是利用公钥身份认证中的漏洞来判断用户名是否存在的过程。
通过分析 OpenSSH 源码中的 userauth_pubkey 函数,可以发现它对公钥身份认证的过程如下:收到 SSH2_MSG-USERAUTH_REQUEST( 公钥类型 ) 发来的数据后,调用函数进行验证,验证失败时返回 0 ,验证成功时返回 1 。然后将结果 (SSH2_MSG_USERAUTH_FAILURE 或 SSH2_MSG_USERAUTH_SUCCESS) 发回给客户端。
函数的相关逻辑如下:
- 如果是未知用户名 -> 0
- 如果是错误密码的已知用户名 -> 0
- 如果是正确密码的用户名 -> 1
漏洞提交者找到的是在第一步和第二步之间,能够设法停止 userauth_pubkey 函数的执行,从而在第一步 userauth_pubkey 函数获取客户端发来的信息字符串时,构造特定格式的字符串,在不返回任何信息的情况下停止并关闭这一通讯连接。
这里的关键是 packet_get_string 函数:
如果存在该用户名,那么第一步后会从消息中提取有效字符串。
第一部分 packet_get_char() 函数提取的字符串是一个布尔变量( 1 字节),之后是两个字符串:算法和对应的密钥。在 SSH 信息中,字符串以长度 – 值的配对方式编码:一个字符串包含 4 字节(字符串长度)的开头和包含字符串内容的可变大小的字节数(根据之前声明的长度)。这里的长度采用大端的方式进行编码:先声明重要的 4 字节最高有效字节,再添加次要的有效字节。
packet_get_string 函数在验证的同时,也负责提取信息中的字符串,从而用于验证信息的长度是否正确。这个函数也依赖其他函数:
首先是函数中的定义到的 ssh_packet_get_string :
ssh_packet_get_string 函数调用 sshpkt_get_string 函数,如果该函数返回的值不是 0 ,那么调用 fatal 函数。 Fatal 函数记录发生的报错信息,然后不返回任何信息,直接终结生成的 OpenSSH 进程。
现在再看下涉及的另一组函数: sshpkt_get_string 调用了 sshbuf_get_string :
sshbuf_get_string 调用了 sshbuf_get_string_direct:
sshbuf_get_string_direct 调用 sshbuf_peek_string_direct:
最后 sshbuf_peek_string_direct 对字符串进行验证:
如果剩下的数据长度小于 4 字节(也就是不能包含字符串长度的声明)或者剩下的数据长度小于字符串的长度,那么会返回 SSH_ERR_MESSAGE_INCOMPLETE 错误 ( 可以在日志中找到该信息 ) 。
总的来讲,函数这一过程如下:先用 packet_get_string 函数来提取信息中的字符串,如果遇到特定的恶意格式字符串,那么会发生一个严重的报错,从而关闭 OpenSSH 进程。
这也就是 Python 编写的 PoC 脚本触发原理:先创建与 OpenSSH 服务器连接的加密请求,然后发送恶意构造的 SSH2_MSG_USERAUTH_REQUEST (公钥格式)请求信息。脚本中将 Paramiko 的 add_boolean 函数重新定义为一个空函数, Paramiko 是 Python 中用于 SSH 通讯的模块。通过重新定义 add_boolean 函数,从而省略了信息中的布尔字段(也就是算法和字符串值之前的内容)。
当 userauth_pubkey 函数解析该恶意构造的信息时,会先读取布尔字段,如果缺少了该字段,那么会读取下一个字段的第一位字节( packet_get_char 函数):也就是算法字符串中的 4 位最高有效字节。之后 pakcet_get_string 函数会调用来读取(并验证)算法字符串。这一过程将会因为缺少布尔字节而发生错误。
下面是一个正确格式的信息解析过程:
如果是缺少布尔字节的恶意格式信息,那么解析函数在事先不知道的情况下,先将第一位字节解析为布尔字节,使得信息整体左移了一位。
这会导致尝试解析一个 1907 字节长度的信息( 0x00000773 的十六进制),也就是超过实际信息长度的信息。那么 ssh_packet_get_string 函数就会调用 fatal 函数来结束 OpenSSH 进程。
漏洞总结
这是一个非常巧妙的漏洞,因为它没有涉及到可以远程代码执行的缓冲区溢出漏洞和输入的验证过程。
在整个过程中既没有缓冲区溢出,使用到的输入内容也都符合验证要求。唯一的问题是可能出于性能需求的考虑,在一些函数处理后才进行对输入的验证,先判断用户名是否存在,如果不存在,那么就没必要进一步验证它的后续请求过程。
如果用户名存在,再对后续请求进行验证,那么会导致不返回信息就中断连接。这样就可以用来枚举一个用户名是否存在。
这个问题的解决方法也很简单:改变下顺序,在调用其他函数前先对所有输入进行验证。
在其他的身份验证函数中也有可能存在类似的问题,一个粗暴的,简单的判断方法是:检查所有类似 ”authctc -> valid” 的表达式。
同样的问题也出现在基于主机的身份认证中(相关链接如下: https://github.com/openbsd/src/commit/779974d35b4859c07bc3cb8a12c74b43b0a7d1e0 )
Kerberos 身份认证中也存在该问题:
SSH1 RSA 身份认证中也可能存在该问题(考虑到现在的 OpenBSD 中都已经停止使用,我们就没有进一步进行检查)。
注意备注信息中也提到该风险问题。
总结
如果你还在使用 OpenSSH ,那么在新的官方修复补丁推送前,禁用易受攻击的身份认证机制。例如关闭公钥身份认证后,能够有效地防止 PoC 脚本和类似的恶意格式认证请求攻击。
也可以检查日志中的报错信息来判断该漏洞是否遭到利用。例如 Ubuntu 下,会有 ”incomplete message” 的报错信息。然而根据 OpenSSH 版本的不同,报错信息也会有一些区别。同样对恶意格式的请求进行修改,比如说构造一个字符串超过最大允许值长度的恶意信息,也有可能会产生其他的报错信息。
在默认的配置中,你只会收到一个简单的报错信息,不会记录客户端的 IP 地址。因此你可以通过调整日志等级( LogLevel ),从 INFO 改为 VERBOSE ,从而创建包含客户端 IP 地址等具体信息的日制。但要注意这会生成更大的日志文件,因此还需要监控日志是否超过容量限制。
以上所述就是小编给大家介绍的《OpenSSH用户枚举漏洞(CVE-2018-15473)分析》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- OpenSSH用户枚举漏洞:一探究竟
- 漏洞分析:OpenSSH用户枚举漏洞(CVE-2018-15473)分析
- OpenSSH 7.8 发布,修复了用户名枚举漏洞
- OpenSSH 7.8 发布,修复了用户名枚举漏洞
- Apache Roller服务器侧请求伪造和文件枚举漏洞(CVE-2018-17198)
- c# – 枚举时项目发生变化时是否会影响枚举?
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
松本行弘的程序世界
松本行弘 / 柳德燕、李黎明、夏倩、张文旭 / 人民邮电出版社 / 2011-8 / 75.00元
《松本行弘的程序世界》是探索程序设计思想和方法的经典之作。作者从全局的角度,利用大量的程序示例及图表,深刻阐述了Ruby编程语言的设计理念,并以独特的视角考察了与编程相关的各种技术。阅读《松本行弘的程序世界》不仅可以深入了解编程领域各个要素之间的关系,而且能够学到大师的思考方法。 《松本行弘的程序世界》面向各层次程序设计人员和编程爱好者,也可以供相关技术人员参考。一起来看看 《松本行弘的程序世界》 这本书的介绍吧!