OpenSSH用户枚举漏洞(CVE-2018-15473)分析
简介
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:
简介
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服务器,
www.wnhack.com
然后运行带有已知用户名的脚本:
在服务器端可以看到报错信息:
这个报错信息也可以在/var/log/auth.log目录下找到:
解析请求失败会导致服务器在不返回任何信息的情况下中断客户端和服务器间的通讯:
注意最后一个粉红色的数据包(客户端的数据包),这里没有后续返回的蓝色数据包(服务器数据包)。 无奈人生安全网
当执行一个不存在的用户名的PoC脚本时:
没有发生“incomplete message”的报错信息:
服务器也返回给客户端一条信息:
注意最后的蓝色(服务器)数据包。
这就是利用公钥身份认证中的漏洞来判断用户名是否存在的过程。
通过分析OpenSSH源码中的userauth_pubkey函数,可以发现它对公钥身份认证的过程如下:收到SSH2_MSG-USERAUTH_REQUEST(公钥类型)发来的数据后,调用函数进行验证,验证失败时返回0,验证成功时返回1。然后将结果(SSH2_MSG_USERAUTH_FAILURE或SSH2_MSG_USERAUTH_SUCCESS)发回给客户端。 www.wnhack.com
函数的相关逻辑如下:
如果是未知用户名 -> 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:
本文来自无奈人生安全网