SSH用户枚举漏洞(CVE-2018-15473)原理学习
一、漏洞简介
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)原理学习的更多相关文章
- 【推荐】CentOS修复OpenSSH用户枚举漏洞
注:以下所有操作均在CentOS 6.8 x86_64位系统下完成. #漏洞说明# OpenSSH(OpenBSD Secure Shell)是OpenBSD计划组所维护的一套用于安全访问远程计算机的 ...
- 漏洞分析:OpenSSH用户枚举漏洞(CVE-2018-15473)分析
漏洞分析:OpenSSH用户枚举漏洞(CVE-2018-15473)分析 漏洞分析:OpenSSH用户枚举漏洞(CVE-2018-15473)分析 - FreeBuf互联网安全新媒体平台 https: ...
- 漏洞复现-CVE-2018-15473-ssh用户枚举漏洞
0x00 实验环境 攻击机:Win 10 0x01 影响版本 OpenSSH 7.7前存在一个用户名枚举漏洞,通过该漏洞,攻击者可以判断某个用户名是否存在于目标主机 0x02 漏洞复现 针 ...
- SMTP用户枚举原理简介及相关工具
前言 SMTP是安全测试中比较常见的服务类型,其不安全的配置(未禁用某些命令)会导致用户枚举的问题,这主要是通过SMTP命令进行的.本文将介绍SMTP用户枚举原理以及相关工具. SMTP SMTP命令 ...
- Linux启动或禁止SSH用户及IP的登录
启动或禁止SSH用户登录 一般情况下,在使用Linux操作系统都不会去机房来操作机器,都是使用一些第三方的工具来操作. 比如使用SSH Secure File Transfer Client工具来传输 ...
- Linux启动或禁止SSH用户及IP的登录,只允许密钥验证登录模式
启动或禁止SSH用户登录 一般情况下,在使用Linux操作系统都不会去机房来操作机器,都是使用一些第三方的工具来操作. 比如使用SSH Secure File Transfer Client工具来传输 ...
- Linux启动与禁止SSH用户及IP的登录
以下就针对SSH方面讨论一下.假设有人特别关注Linux环境的安全性,第一就从login方面来进行讨论 1:Linux启动或禁止SSH root用户的登录 2:Linux限制SSH用户 事实上这些东西 ...
- SSH免密登陆配置过程和原理解析
SSH免密登陆配置过程和原理解析 SSH免密登陆配置过很多次,但是对它的认识只限于配置,对它认证的过程和基本的原理并没有什么认识,最近又看了一下,这里对学习的结果进行记录. 提纲: 1.SSH免密登陆 ...
- linux查看ssh用户登录日志与操作日志
linux查看ssh用户登录日志与操作日志 2013-11-01转载 ssh用户登录日志 linux下登录日志在下面的目录里: 代码如下 复制代码 cd /var/log 查看ssh用户的登录日 ...
随机推荐
- AngularJS orderBy 使用要点
AngularJS orderBy 使用要点总结: 1,书写格式 基本应用格式为: ng-repeat="item in itemList | orderBy:p1:p2" 参数p ...
- How to use base class's assignment operator in C++
看了android下的代码,好长时间没看了,有个关于C++的知识点不是很清楚,查了下: 如何使用基类中的赋值运算符? 引述自http://stackoverflow.com/questions/122 ...
- UITextField禁用掉编辑之后...
某些UITextField只为了摆数据,还有响应点击,为了避免频繁出现键盘,所以把UITextField的人机交互(userInteractionEnabled)给关闭了 此时,给UITextFiel ...
- mint-ui loadmore组件注意问题
loadTop(){ this.$store.dispatch('getNewsList',{channelId:this.id,page:0,size:this.size}); this.$refs ...
- 教你ABBYY FineReader 12添加图像的技巧
ABBYY FineReader 12是一款OCR图片文字识别软件,而且强大的它现在还可使用快速扫描窗口中的快速打开.扫描并保存为图像或任务自动化任务,在没有进行预处理和OCR的ABBYY FineR ...
- 带有logo的二维码
摘要: 前面介绍了使用javascript生成二维码,但是这样并不能满足我们的需求,我们有时也会看到带有logo的二维码,本文就介绍如何生成带有logo的二维码. 简介: 主要使用了svg的文本和图像 ...
- ubuntu alsa
今天要在linux下搞音频编程,在网上查阅了一下资料,网上很多资料都是在linux下直接对/dev/dsp进行编程的,因为在以往的linux系统中,我们是可以通过cat xxx.wav /dev/d ...
- extjs 分组函数自定义统计
//获取统计信息函数 Ext.getStatText = function (values) { var zy = 0; var tm = 0; for (var i = 0; i < valu ...
- Java多线程之可见性与原子性——synchronized VS volatile
<转:http://blog.csdn.net/uniquewonderq/article/details/48113071> 程序举例: 代码: package com.synch; p ...
- 恶劣条件下的apache配置(Linux)
(本文出自yangjj ^_^) 前提:1.没联网,yum挂.2.至少要有GCC,要不玩个屁. 3.你有充足的咖啡并且有几个小时时间不想打dota. 4.你要做集群. 以上条件不满足其一,看到这里 ...