libssh2被发现整数溢出和越界读取漏洞(CVE-2019-13115)

libssh2是一个C函数库,用来实现SSH2协议。SSH2是一套安全通讯协议框架(早期的SSH1由于存在安全漏洞),基于SSH2协议的产品主要有openssh,putty,SSH Secure Shell Client等,这些都是开源的,但是这些代码非常难懂而且复杂,一个个函数深层次的调用很快就让人在C语言代码的海洋中迷失了方向,妄图通过从这些开源软件中抽取程序代码段来“组装”自己的应用程序是非一般人所能实现的。不过还好网路上出现了一些开源的SSH2开发库,利用这些开发库开发自己的SSH2程序却要简单得多,由于这些开发库都是开源的,往往是针对linux平台的,而且一般只提供了源代码。

不过,最近libssh2 被发现整数溢出和越界读取漏洞(CVE-2019-13115)。

但是,切勿惊慌!这不是openssh中的漏洞,因此它不会影响我们每天都使用的ssh。其次,这不是libssh中的漏洞,libssh是一个与libssh2不相关的C函数库,只不过提供与libssh2类似的功能。

该漏洞只存在于libssh2 1.8.2及更早版本中,在版本1.9.0中已经得到了修复。建议用户尽快升级到版本1.9.0,除此之外,我不知道有任何针对此漏洞的缓解措施。

该漏洞会越界读取,可能导致攻击者发起远程攻击。当使用libssh2连接到恶意SSH服务器时,该漏洞就会被触发。溢出发生在Diffie Hellman密钥交换期间,这意味着在完成身份验证之前,该漏洞可以在连接过程的早期被触发。libssh2从恶意服务器接收一个uint32_t,并且不对其进行边界检查,然后libssh2从uint32_t指定的偏移量中读取内存。为此,我编写了一个概念验证漏洞利用程序,其中恶意SSH服务器会返回一个非常大的偏移值,这会导致libssh2崩溃并出现分段错误。但是,我认为只有经过精心设计的偏移量才可能会导致远程攻击的发生,因为所读取的内存随后会返回到服务器。概念验证漏洞利用程序取决于堆布局,由于libssh2只是一个库,因此它将根据使用应用程序而有所不同。PHP大马

漏洞的发现过程

2019年3月18日,Canonical公司的Chris Coulson研究员披露了libssh2 (CVE-2019-3855到CVE-2019-3863)中的9个漏洞。这些漏洞已在libssh2 1.8.1版本中得到了修复。当时,我注意到提交的修复程序在LGTM上引入了几个新警报。这些警报里包含的代码如下:

if((p_len = _libssh2_get_c_string(&buf, &p)) < 0)
C

问题是_libssh2_get_c_string返回-1作为错误代码,但p_len是无符号的,因此将忽略错误条件。事实证明,libssh2团队已经在稍后的提交中修复了这些问题,这样我就可以根据完整的修复过程仔细查看代码,看看它们是否包含任何其他明显的漏洞。很快,我就发现了以下这个执行得很糟糕的边界检查函数:

int _libssh2_check_length(struct string_buf *buf, size_t len)
{
    return ((int)(buf->dataptr - buf->data) <= (int)(buf->len - len)) ? 1 : 0;
}
C

这个函数的问题是,对int的强制转换可能会溢出。左边的转换是安全的,因为buf的字段是可信的值,但是右边的转换是不安全的,因为len的值是不可信的。通过使len的值大于buf-> len + 0x80000000来创建一个概念验证漏洞,就可以很容易绕过此溢出检查。 另外,该概念验证现在可以在GitHub上找到。

我后来了解到(参见下面的时间线),在版本1.8.2发布之后,主开发分支引入了_libssh2_check_length,因此在版本1.8.2中不存在这种易受攻击的界限检查漏洞。不幸的是,1.8.2版却没有任何边界检查,所以概念验证漏洞仍然可以工作。在1.8.2版本中,漏洞的源位置是kexc:1675。不过由于p_len包含一个不受信任的值,因此对s的后续读取可能是越界的。因为在1.8.2版本中不存在_libssh2_check_length,所以p_len的值无需大于0x80000000,就可以触发漏洞。这意味着len的值越小,越容易触发越界读取漏洞,这意味着该漏洞更有可能被用来实现远程攻击。

包含负值的错误码查询命令会被理解成无符号

当我正在查看修复Chris Coulson发现的漏洞的提交时,却意外地注意到一个常见的错误模式,其中一个包含负值的错误码查询命令会被理解成无符号。这个错误是变体分析的理想候选项,因为这是一个容易犯的错误,并且它没有被标准编译器警告捕获。所以我编写了这个简单的查询来查找漏洞的每个实例:奇热影视

import cpp
import semmle.code.cpp.dataflow.DataFlow
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis

from Function f, FunctionCall call, ReturnStmt ret, DataFlow::Node source, DataFlow::Node sink
where call.getTarget() = f
and ret.getEnclosingFunction() = f
and ret.getExpr().getValue().toInt() < 0
and source.asExpr() = call
and DataFlow::localFlow(source, sink)
and sink.asExpr().getFullyConverted().getType().getUnderlyingType().(IntegralType).isUnsigned()
and lowerBound(sink.asExpr()) < 0
select sink

这个查询的代码如下:

r_len = _libssh2_get_c_string(&buf, &r);
if(r_len <= 0)
    return -1;
C

查询查找有时返回负整数常量的函数,例如,_libssh2_get_c_string在第773行执行此操作。然后,它查找对该函数的调用,该函数获取返回值并将其转换为无符号类型。

你可以在此处查看此查询当时找到的9个结果。我在2019年3月28日发送给libssh2团队的电子邮件中包含了该链接,他们已经修复了所有这些错误。

时间线

libssh2团队在收到我的报告后的几天内,就在GitHub上发布了针对该漏洞的修复程序,但花了差不多3个月才发布了新版本。

2019-03-28:我私下向libssh2团队透露漏洞;

2019-03-29:libssh2团队发送初步答复;

2019-04-05:libssh2团队修复了他们开发分支上的错误:08ef9b7,5929e26,b4289ee;

2019-05-08:我要求更新修补程序何时发布;

2019-05-09:libssh2团队回应说该漏洞仅存在于开发分支上,并且从未包含在发行版中;

2019-05-11:我告诉libssh2团队我的PoC也适用于1.8.2版本;

2019-05-16:libssh2团队在1.8.2版本中询问错误的源位置;

2019-05-16:我在版本1.8.2中回复了错误的源位置;

2019-06-17:我警告libssh2团队,我们的90天披露截止日期将于2019-06-26到期;

2019-06-20:libssh2版本1.9.0发布;

2019-06-30:该漏洞被记为CVE-2019-13115;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值