CVE-2019-17498:libssh2整形溢出漏洞分析
2019-12-18 14:00:26 Author: www.freebuf.com(查看原文) 阅读量:151 收藏

严重性与缓解方案

该漏洞并不是一个Openssh漏洞,所以它不会影响ssh。Libssh2是一个客户端C代码库,它能够帮助应用程序与SSH服务器建立连接。而且该漏洞也不是一个libssh漏洞,因为libssh并非C代码库,只不过它的功能跟libssh2类似而已。

该漏洞存在于libssh2 v1.9.0及更早版本之中,目前该漏洞已经在libssh2的master分支成功修复,但是官方并没有发布包含漏洞修复方案的正式版。

该漏洞涉及到越界读取的问题,并有可能导致目标服务出现拒绝服务或远程信息披露的风险。当libssh2被用来跟恶意SSH服务器建立连接时,便有可能触发该漏洞。当SSH服务器发送一条断开连接消息时,便会发生溢出。这也就意味着,该漏洞可以在连接过程的开始阶段,及身份认证完成之前被触发。

触发漏洞

该漏洞的原始位置位于packet.c:480处:

if(message_len < datalen-13) {

datalen的值是一个不受信的值,它由远程SSH服务器控制。如果datalen==11,那么减法运算将会发生溢出,针对message_len的越界检测将会失效。Message_len是一个无符号的32位整型,它的值同样由远程SSH服务器控制,所以这将导致第485行代码发生越界读取:

language_len =

_libssh2_ntohu32(data + 9 + message_len);

越界读取通常来说会导致分段错误,但是本文所描述的问题将有可能导致代码调用第499行的LIBSSH2_DISCONNECT:

if(session->ssh_msg_disconnect) {

    LIBSSH2_DISCONNECT(session, reason, message,

                       message_len, language, language_len);

}

具体情况取决于libssh2库是如何被使用的,因为session->ssh_msg_disconnect是一个回调函数,默认为NULL,但是用户也可以通过调用libssh2_session_callback_set来自行设置。

我在这里专门写了一个漏洞利用PoC:【点我获取】。它模拟了一个恶意SSH服务器,可以返回包含datalen==11和message_len==0×41414141的断开连接消息,这将导致libssh2出现分段错误并发生崩溃。

Liibssh2整型溢出变种分析

当我在将一个安全漏洞报告给厂商时,我通常会在报告中包含两个内容:

1、漏洞的漏洞利用代码PoC;

2、QL查询,识别所有我认为需要修复的代码位置;

在PoC中包含QL查询,个人认为有以下好处:

1、如果代码包含多个相似的漏洞,那么我们就可以编写一个查询请求来枚举它们。

2、QL查询可以帮助我快速判断漏洞是否成功被修复。

3、QL查询可以将结果以单独URL的形式呈现给我,便于我们进行后续分析。

创建一个PoC通常涉及到大量的工作,如果某个目标存在多个非常相似的漏洞,那我一般会针对其中一个漏洞写一个PoC,因为一个PoC足以证明漏洞的影响了。这个查询的目的并不是找到libssh2中所有的整形溢出漏洞,它的主要目的是找出该PoC触发的漏洞以及其他的相似变种。

Semmle QL查询代码如下:

/**

 * @kind path-problem

 */

import cpp

import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis

import semmle.code.cpp.dataflow.TaintTracking

import DataFlow::PathGraph

class Config extends DataFlow::Configuration {

  Config() { this = "_libssh2_ntohl bounds check overflow" }

  override predicate isSource(DataFlow::Node source) {

    source.asExpr().(FunctionCall).getTarget().getName().matches("_libssh2_ntoh%")

  }

  override predicate isSink(DataFlow::Node sink) {

    convertedExprMightOverflowNegatively(sink.asExpr()) and

    exists(RelationalOperation cmp | cmp.getAnOperand() = sink.asExpr())

  }

  override predicate isAdditionalFlowStep(DataFlow::Node source,

                                          DataFlow::Node target) {

    exists(Field f |

      source.asExpr() = f.getAnAssignedValue() and

      target.asExpr() = f.getAnAccess())

    or

    target.asExpr().(AddExpr).getAnOperand() = source.asExpr()

    or

    target.asExpr().(SubExpr).getAnOperand() = source.asExpr()

  }

}

from Config cfg, DataFlow::PathNode source, DataFlow::PathNode sink

where cfg.hasFlowPath(source, sink)

select sink, source, sink,

  "possible integer overflow of tainted expression in bounds check"

其中,isSource表示寻找到了针对_libssh2_ntohu32和 _libssh2_ntohu64的调用,它们主要用来进行网络至主机的字节顺序转义。这些函数一般都可以用来寻找那些“攻击者控制的数据”。但是我这里使用的isSink目的是寻找对比晕眩,其中包含可能发生溢出的子表达式。比如说,message_len < datalen-13是一个比较表达式,而datalen-13则有可能发生溢出。我的查询还会重写isAdditionalFlowStep选项,并自定义数据流边界集。

* 参考来源:semmle,FB小编Alpha_h4ck编译,转载请注明来自FreeBuf.COM


文章来源: https://www.freebuf.com/vuls/221898.html
如有侵权请联系:admin#unsafe.sh