一、漏洞简介



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. iOS:第三方库使用非ARC编译

    iOS: 解决某些第三方库因为ARC不能使用的问题 1.在target下面的build phases下有一个compile source,下面有很多待编译文件.可以看到一个compile flag,可 ...

  2. 浅谈Linux系统中如何查看进程

    进程是一个其中运行着一个或多个线程的地址空间和这些线程所需要的系统资源.一般来说,Linux系统会在进程之间共享程序代码和系统函数库,所以在任何时刻内存中都只有代码的一份拷贝. 1,ps命令 作用:p ...

  3. CSDN极客头条使用指南

    CSDN极客头条使用指南 今天给大家介绍一下CSDN博客最新推出的这个栏目--CSDN极客头条. 极客头条是什么 极客头条大家分享优质IT资源的聚集地. 大家不仅能够分享CSDN的文章,更能够将其它社 ...

  4. 用Fiddler可以设置浏览器的UA 和 手动 --Chrome模拟手机浏览器(iOS/Android)的三种方法,亲测无误!

    附加以一种软件的方法是:用Fiddler可以设置浏览器的UA 以下3种方法是手动的 通过伪装User-Agent,将浏览器模拟成Android设备. 第一种方法:新建Chrome快捷方式 右击桌面上的 ...

  5. [Learn AF3]第七章 App framework组件之Popup

    AF3的弹出对话框Popup 组件名称:Popup 是否js控件:是,$.afui.popup     说明:af3中的popup和af2中相比变化不大,依然是通过插件popup来实现的     方法 ...

  6. rlwrap安装报错You need the GNU readline 解决方法

    首先大家肯定知道rlwrap是干什么的? 在linux以及unix中,sqlplus的上下左右.回退无法使用,会出现乱码情况.而rlwrap这个软件就是用来解决这个的.   这个错误曾经困扰我很久很久 ...

  7. python获取两个dict的不同

    参数: dict1, dict2 需求:如果dict1和dict2中有不同的key,那么返回这个(key, dict1[key]):如果dict1和dict2中有相同的key,但是value不同,返回 ...

  8. [Unity3D] 01 - Try Unity3D

    01. Move and Rotate 标准全局坐标系 Keyboard using UnityEngine; using System.Collections; public class NewBe ...

  9. 为什么React事件处理函数必须使用Function.bind()绑定this?

    最近在React官网学习Handling Events这一章时,有一处不是很明白.代码如下: class Toggle extends React.Component { constructor(pr ...

  10. 图解Python深拷贝和浅拷贝

    Python中,对象的赋值,拷贝(深/浅拷贝)之间是有差异的,如果使用的时候不注意,就可能产生意外的结果. 下面本文就通过简单的例子介绍一下这些概念之间的差别. 对象赋值 直接看一段代码: will ...