神刀安全网

v2.7.1以下版本的Git中存在漏洞,或可导致远程代码执行

v2.7.1以下版本的Git中存在漏洞,或可导致远程代码执行

据了解,安全研究人员在2.7.1版本之前的所有版本Git中发现了一个安全漏洞,其服务器端和客户端中均存在这一漏洞。攻击者可利用这个漏洞来引起目标系统的缓冲区溢出,从而在目标主机中实现远程代码执行。(漏洞信息目前尚未公布,CVE-2016-2324和CVE 2016‑2315)

在此之前,安全研究人员曾就这个缓冲区溢出漏洞进行过分析和描述,具体内容请点击 这里 进行查看。

2016年2月11日,Jeff King在git安全邮件中写下了下面这段内容:

“2016年2月11日,星期四,下午2点32分49秒,‘Laël Cellier’在Git安全中写到:利用一个较长的文件名,或者大量的嵌套树,就可以推送或者克隆一个Git代码库,这就是这个漏洞的工作方式。

而现在的问题就在于,受此漏洞影响的版本数量非常之多,大量版本的Git代码分支目前仍处于使用状态,而且其中还有很多为稳定的代码分支。所以我认为这个漏洞是一个非常严重的漏洞,它应该得到CVE的认证,并且我也认为应该将此漏洞的详细信息公布出来。”

没错,正如你所说的那样,我也确实认为低于v2.7.0版本的Git中存在一个堆溢出漏洞。但是我并不认为导致这一问题出现的唯一原因就是其中的path_name(),而且当前最新版本中仍然存在这一问题。

由于之前所发布的代码比较杂乱,阅读起来非常地有困难。所以我对相关代码进行了整理,并提供给大家:

char *path_name(const struct name_path *path, const char *name) {          const struct name_path *p;          char *n, *m;          int nlen = strlen(name);          int len = nlen + 1;            for (p = path; p; p = p->up) {                  if (p->elem_len)                          len += p->elem_len + 1;          }          n = xmalloc(len);          m = n + len - (nlen + 1);          memcpy(m, name, nlen + 1);          for (p = path; p; p = p->up) {                  if (p->elem_len) {                          m -= p->elem_len + 1;                          memcpy(m, p->elem, p->elem_len);                          m[p->elem_len] = '/';                  }          }          return n; }

根据漏洞的描述信息,系统所分配的内存空间大小与strcpy函数需要写入数据的大小并不匹配。但是从某种程度上来说,我们可以利用memcpy()函数来解决这一问题,因为至少“len”的初始值与我们所需要写入的数据字节数是匹配的(也许相关的数值并不是真实值,但是只要我们写入的数据大小不超过内存空间的分配值就可以了)。

但是在系统对数据进行了循环计算之后,“len”的值是会进行相应改变的。如果你已经获取到了path参数的序列值(每个值均小于2^31),系统将会把这些数值进行相加,并得出一个更小的正数值。比如说,我们需要处理的数据为A/B/C,其中各个数据长度如下: A=2^31-5, B=2^31-5, C=20,,系统在计算之后最终将会得到len=10。然后,缓冲区的大小将会变小,以至于无法存储C的数据,这样一来,系统将无法存储在第二轮循环中所需要写入的数据了。

针对这一问题,我也提出了我自己的解决方案。我发现,只需要将所有的“int”整形变量转变为“size_t”就可以适当缓解这个问题了。虽然这样做并不能完美解决所有的问题,但是这也意味着在一个64位架构的操作系统中,用户将需要利用一个长度为2^64的值来触发这个漏洞,这是很不切实际的。虽然这种操作方式可以帮助64位的系统来避免这个问题,但是32位的操作系统就没办法了。

这里还有一个值得注意的地方,在tree-diff.c中的path_appendnew()函数中还存在一个类似的问题。我们需要在strbuf中构建一个完整的路径名称,并利用相应的函数参数来对内存空间溢出进行检测。但是当我们将length长度作为一个整形参数传递给函数之后,系统会分配一个FLEX_ARRAY结构体来对传入的参数进行处理。我认为,这个问题比我们之前所讨论的问题都要有意思。因为我们可以通过git-log来触发这个漏洞,而且只有当系统对代码进行重新封装的过程中才会利用到path_name()函数。所以,虽然这个问题始终会对你产生影响,但是并不会在你刚开始克隆代码库的时候就出现问题。

而我就这一问题所提出的解决方案与之前方案的类似:我们需要使用size_t。这样一来,至少可以保证在64位操作系统中,必须分配一个较大的数值才能触发这个漏洞。虽然在32位操作系统中的效果并不是那么好,但是至少也可以帮助你避免内存空间分配失败的问题。

所以这也就是我为什么要将这个漏洞缓解方案提交上来的原因。我也承认,这些解决方案的确不能完美解决这些问题。完美的解决方案应该是:始终使用size_t来存储strlen()函数的返回值,并且当我们需要对size_t的数值进行计算处理之前,必须对内存空间做溢出检测。

可能有的读者还记得我在去年所发表的一系列相关文章,感兴趣的读者可以看一看,也许大家能够从中发现一些新的东西。

除此之外,我认为其实我们可以完全弃用path_name()函数。该函数的唯一用处就是计算数据包对象的包名哈希值,实际上我们并不需要通过在内存中重构数据包来实现这一点。

据了解,本文所有讨论的问题都已经在git 2.7.1版本中得到了修复,该版本移除了path_name(),tree-diff.c文件中的size_t,以及缓冲区溢出检测机制。其实在此之前,Github已经为其企业用户修复了这一问题。目前,Bitbucket和GitLab仍然会受到这个问题的影响。虽然目前此漏洞还未得到CVE认证,但是我相信相关人员很快会对这一问题进行处理。

本文由 360安全播报 翻译,转载请注明“转自360安全播报”,并附上链接。

原文链接:http://seclists.org/oss-sec/2016/q1/645

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » v2.7.1以下版本的Git中存在漏洞,或可导致远程代码执行

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
分享按钮