一、漏洞简介



1、漏洞编号和类型


CVE-2018-15473 SSH 用户名(USERNAME)暴力枚举漏洞

2、漏洞影响范围


OpenSSH 7.7及其以前版本

3、漏洞利用方式


由于SSH本身的认证机制存在缺陷,导致攻击者可以使用字典,暴力枚举SSH存在的用户名(Username)

4、漏洞修复方式


升级openssh

二、漏洞原理及其利用分析



1、漏洞原理


参考国外文献:http://www.openwall.com/lists/oss-security/2018/08/15/5

观察下列openssh代码

  87 static int
88 userauth_pubkey(struct ssh *ssh)
89 {
...
101 if (!authctxt->valid) {
102 debug2("%s: disabled because of invalid user", __func__);
103 return 0;
104 }
105 if ((r = sshpkt_get_u8(ssh, &have_sig)) != 0 ||
106 (r = sshpkt_get_cstring(ssh, &pkalg, NULL)) != 0 ||
107 (r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0)
108 fatal("%s: parse request failed: %s", __func__, ssh_err(r));

可以看出来,当用户不可用时,连接userauth_pubkey会直接返回,如果用户可用,则会进入下一个条件判断,调用fatal函数。所以在username可用于不可用两种情况下,可以看出来这个函数的返回是不同的

2、PoC原理


PoC地址:https://github.com/Rhynorater/CVE-2018-15473-Exploit

可以看下这段代码,这就是判断username是否可用的原理

try:
transport.auth_publickey(username, paramiko.RSAKey.generate(1024))
except BadUsername:
return (username, False)
except paramiko.ssh_exception.AuthenticationException:
return (username, True)

由此可见,一切就在paramiko这个库的transport.auth_publickey这个函数中

def auth_publickey(self, username, key, event=None):
"""
Authenticate to the server using a private key. The key is used to
sign data from the server, so it must include the private part. If an ``event`` is passed in, this method will return immediately, and
the event will be triggered once authentication succeeds or fails. On
success, `is_authenticated` will return ``True``. On failure, you may
use `get_exception` to get more detailed error information. Since 1.1, if no event is passed, this method will block until the
authentication succeeds or fails. On failure, an exception is raised.
Otherwise, the method simply returns. If the server requires multi-step authentication (which is very rare),
this method will return a list of auth types permissible for the next
step. Otherwise, in the normal case, an empty list is returned. :param str username: the username to authenticate as
:param .PKey key: the private key to authenticate with
:param .threading.Event event:
an event to trigger when the authentication attempt is complete
(whether it was successful or not)
:return:
list of auth types permissible for the next stage of
authentication (normally empty) :raises:
`.BadAuthenticationType` -- if public-key authentication isn't
allowed by the server for this user (and no event was passed in)
:raises:
`.AuthenticationException` -- if the authentication failed (and no
event was passed in)
:raises: `.SSHException` -- if there was a network error
"""
if (not self.active) or (not self.initial_kex_done):
# we should never try to authenticate unless we're on a secure link
raise SSHException('No existing session')
if event is None:
my_event = threading.Event()
else:
my_event = event
self.auth_handler = AuthHandler(self)
self.auth_handler.auth_publickey(username, key, my_event)
if event is not None:
# caller wants to wait for event themselves
return []
return self.auth_handler.wait_for_response(my_event)

根据PoC的代码,在username可用时,auth_publickey的函数会抛出异常,但是抛出的类型AuthenticationException,通过阅读这个函数的代码,返现只有self.auth_handler = AuthHandler(self)、self.auth_handler.auth_publickey(username, key, my_event), return self.auth_handler.wait_for_response(my_event)三条语句有可能会抛出这个异常,运行PoC测试发现,在最后一句话中抛出了异常(测试方法很简单的点灯法,节点前后print信息即可判断),跟踪进入这个函数wait_for_response。

def wait_for_response(self, event):
max_ts = None
if self.transport.auth_timeout is not None:
max_ts = time.time() + self.transport.auth_timeout
while True:
event.wait(0.1)
#print self.transport.is_active()
if not self.transport.is_active():
e = self.transport.get_exception()
#print "e:",e
if (e is None) or issubclass(e.__class__, EOFError):
e = AuthenticationException('Authentication failed.')
raise e
if event.is_set():
break
if max_ts is not None and max_ts <= time.time():
raise AuthenticationException('Authentication timeout.') if not self.is_authenticated():
e = self.transport.get_exception()
if e is None:
e = AuthenticationException('Authentication failed.')
# this is horrible. Python Exception isn't yet descended from
# object, so type(e) won't work. :(
if issubclass(e.__class__, PartialAuthentication):
return e.allowed_types
raise e
return []

这里有三个点可以抛出Authentication异常,经过修改打印信息获取到,异常抛出在下面的这个地方。

    if (e is None) or issubclass(e.__class__, EOFError):
e = AuthenticationException('Authentication failed.')
raise e

当用户不可用时,也是在这个点位抛出异常,但是没有进上文那个判断,所以e应该不是None,也不是EOFerror, 我们屏蔽掉BadUsername,回归到最近本的Python异常,发现返回的是这个Authencation Failed2异常,

def wait_for_response(self, event):
max_ts = None
if self.transport.auth_timeout is not None:
max_ts = time.time() + self.transport.auth_timeout
while True:
event.wait(0.1)
#print self.transport.is_active()
if not self.transport.is_active():
e = self.transport.get_exception()
#print "e:",e
if (e is None) or issubclass(e.__class__, EOFError):
e = AuthenticationException('Authentication failed1.')
raise e
if event.is_set():
break
if max_ts is not None and max_ts <= time.time():
raise AuthenticationException('Authentication timeout.') if not self.is_authenticated():
e = self.transport.get_exception()
if e is None:
e = AuthenticationException('Authentication failed2.')
# this is horrible. Python Exception isn't yet descended from
# object, so type(e) won't work. :(
if issubclass(e.__class__, PartialAuthentication):
return e.allowed_types
raise e
return []

彻掉后event事件被置位了,可以看出,而且根据下文中auth_publickey函数的注释部分可以看到的确如此,当身份验证完成时触发事件,根据漏洞原来描述,当username不可用时,openssh的函数就返回了,身份验证完成,触发了事件,因而跳出了while循环,又因为身份验证失败,所以进入了下一个判断,exception的对象e是None,于是就成了一个新的AuthenticationException异常。而username可用时,并没有完成身份认证,event没有触发,所以在while循环中因为认证失败跑出了异常。当然PoC中定义自定义异常,来区别这两个异常,从而做到判断,但是从程序过程中可以看到两个地方的的确在网络通信上是有差别的。

"""
Authenticate to the server using a private key. The key is used to
sign data from the server, so it must include the private part. If an ``event`` is passed in, this method will return immediately, and
the event will be triggered once authentication succeeds or fails. On
success, `is_authenticated` will return ``True``. On failure, you may
use `get_exception` to get more detailed error information. Since 1.1, if no event is passed, this method will block until the
authentication succeeds or fails. On failure, an exception is raised.
Otherwise, the method simply returns. If the server requires multi-step authentication (which is very rare),
this method will return a list of auth types permissible for the next
step. Otherwise, in the normal case, an empty list is returned. :param str username: the username to authenticate as
:param .PKey key: the private key to authenticate with
:param .threading.Event event:
an event to trigger when the authentication attempt is complete
(whether it was successful or not)
:return:
list of auth types permissible for the next stage of
authentication (normally empty) :raises:
`.BadAuthenticationType` -- if public-key authentication isn't
allowed by the server for this user (and no event was passed in)
:raises:
`.AuthenticationException` -- if the authentication failed (and no
event was passed in)
:raises: `.SSHException` -- if there was a network error
"""

SSH用户枚举漏洞(CVE-2018-15473)原理学习的更多相关文章

  1. 【推荐】CentOS修复OpenSSH用户枚举漏洞

    注:以下所有操作均在CentOS 6.8 x86_64位系统下完成. #漏洞说明# OpenSSH(OpenBSD Secure Shell)是OpenBSD计划组所维护的一套用于安全访问远程计算机的 ...

  2. 漏洞分析:OpenSSH用户枚举漏洞(CVE-2018-15473)分析

    漏洞分析:OpenSSH用户枚举漏洞(CVE-2018-15473)分析 漏洞分析:OpenSSH用户枚举漏洞(CVE-2018-15473)分析 - FreeBuf互联网安全新媒体平台 https: ...

  3. 漏洞复现-CVE-2018-15473-ssh用户枚举漏洞

          0x00 实验环境 攻击机:Win 10 0x01 影响版本 OpenSSH 7.7前存在一个用户名枚举漏洞,通过该漏洞,攻击者可以判断某个用户名是否存在于目标主机 0x02 漏洞复现 针 ...

  4. SMTP用户枚举原理简介及相关工具

    前言 SMTP是安全测试中比较常见的服务类型,其不安全的配置(未禁用某些命令)会导致用户枚举的问题,这主要是通过SMTP命令进行的.本文将介绍SMTP用户枚举原理以及相关工具. SMTP SMTP命令 ...

  5. Linux启动或禁止SSH用户及IP的登录

    启动或禁止SSH用户登录 一般情况下,在使用Linux操作系统都不会去机房来操作机器,都是使用一些第三方的工具来操作. 比如使用SSH Secure File Transfer Client工具来传输 ...

  6. Linux启动或禁止SSH用户及IP的登录,只允许密钥验证登录模式

    启动或禁止SSH用户登录 一般情况下,在使用Linux操作系统都不会去机房来操作机器,都是使用一些第三方的工具来操作. 比如使用SSH Secure File Transfer Client工具来传输 ...

  7. Linux启动与禁止SSH用户及IP的登录

    以下就针对SSH方面讨论一下.假设有人特别关注Linux环境的安全性,第一就从login方面来进行讨论 1:Linux启动或禁止SSH root用户的登录 2:Linux限制SSH用户 事实上这些东西 ...

  8. SSH免密登陆配置过程和原理解析

    SSH免密登陆配置过程和原理解析 SSH免密登陆配置过很多次,但是对它的认识只限于配置,对它认证的过程和基本的原理并没有什么认识,最近又看了一下,这里对学习的结果进行记录. 提纲: 1.SSH免密登陆 ...

  9. linux查看ssh用户登录日志与操作日志

    linux查看ssh用户登录日志与操作日志 2013-11-01转载   ssh用户登录日志 linux下登录日志在下面的目录里:  代码如下 复制代码 cd /var/log 查看ssh用户的登录日 ...

随机推荐

  1. Mac/win eclipse genymotion 插件下载地址

    eclipse -->new install --> 填写该地址 (目前最新的地址) https://dl.genymotion.com/eclipse/

  2. MyEclipse如何恢复删掉的文件

    今天一不小心删了项目里的两个包,心里那个痛啊,一想MyEclipse这么强大,应该会有恢复文件的功能吧,要不就太坑了啊. 果不其然让我找到了方法: 如图:右击项目选择 然后在弹出的页面勾选需要恢复的文 ...

  3. 性能监控-TP理解

    首先给出Google到的答案: The tp90 is a minimum time under which 90% of requests have been served. tp90 = top ...

  4. level 1 -- unit 2 - what 引导的特殊疑问句

    特殊疑问句 what 引导的特殊疑问句 常见结构如下: 1. what be sb/sth? 1.1 如 谓语动词是单数is what is your phone number ? what is y ...

  5. 安装MySQL-python: EnvironmentError:mysql config not found

    1执行 sudo yum install python-devel 2 find / -name mysql_config 在/usr/bin/下发现了这个文件 3. 后修改MySQL-python- ...

  6. mysql数据库中,如何对json数据类型的值进行修改?通过json_set函数对json字段值进行修改?

    需求描述: 今天在看mysql中存放json数据类型的问题,对于json数据进行修改的操作, 在此记录下. 操作过程: 1.创建包含json数据类型的表,插入基础数据 mysql> create ...

  7. Golang 在 Mac、Linux、Windows 交叉编译

    https://blog.csdn.net/panshiqu/article/details/53788067

  8. 关于openssl的编译与使用

    关于openssl的编译与使用,可以参考这两往篇文章 http://blog.csdn.net/lazyclough/article/details/7456131 http://www.leaves ...

  9. 【PHP代码审计】 那些年我们一起挖掘SQL注入 - 1.什么都没过滤的入门情况

    0x01 背景 首先恭喜Seay法师的力作<代码审计:企业级web代码安全架构>,读了两天后深有感触.想了想自己也做审计有2年了,决定写个PHP代码审计实例教程的系列,希望能够帮助到新人更 ...

  10. 【RF库Collections测试】Set List Value

    Name:Set List ValueSource:Collections <test library>Arguments:[ list_ | index | value ]Sets th ...