2016-09-23 滴滴安全部 滴滴安全应急响应中心
昨天 OpenSSL 放出了1.1.0a, 1.0.2i 和 1.0.1u 版本,并发公告修复了 CVE-2016-6304 高危漏洞,该漏洞利用客户端发起的重新协商,在 TLS Handshake 的 Client_Hello 扩展的 status_request 字段中填充 OCSP ids ,并不停的发起 Client Renegotiation,加上服务端在实现上存在内存泄漏,最终 Server 端因为内存耗尽而造成 DoS 攻击。
上述攻击中的一个前提是 Server 端允许 Client 发起 Renegotiation , Nginx 在 09 年 11 月发布的 0.8.23 这个版本中已经禁止在 TLS Handshake 中 Client 发起的 Renegotiation,所以对 NGINX 版本号大于 0.8.23 的 Server 没有任何影响,但还是建议升级 OpenSSL 到最新的稳定版本。
几天前看到 Cloudflare 的 Filippo Valsorda (@FiloSottile ) 同学在 Twitter 上表示 OpenSSL 在 22 号要发版 1.1.0a, 1.0.2i,1.0.1u ,并修复了高危漏洞。
果然昨天 OpenSSL 官方发布了公告(链接https://www.openssl.org/news/secadv/20160922.txt )
下面我们从 Record 协议开始分析下 CVE-2016-6304 :
CVE-2016-6304 中的攻击实际上是一种 TLS 的握手攻击, 并不罕见, 如去年阿里云盾发布的 《2015年下半年互联网 DDoS 状态和趋势报告》(链接http://yundunddos-help.oss-cn-hangzhou.aliyuncs.com/%E4%BA%91%E7%9B%BE%E4%BA%92%E8%81%94%E7%BD%91DDoS%E7%8A%B6%E6%80%81%E5%92%8C%E8%B6%8B%E5%8A%BF%E6%8A%A5%E5%91%8A-2015H2-Final%20Version.pdf )中的 HTTPS CC 流量攻击,5 亿次请求。本次原理类似,但是使用了 Server 端的一个实现漏洞。
HTTPS 以 Record 协议工作在 TCP 上,TLS Handshake、 应用层数据的传输都以 Record 格式包裹,先来看下 Record 协议的协议头:
Byte 0 = TLS Record Type : 22 为 Handshake, 23 为应用数据
Bytes 1-2 = SSL version (major/minor)
Bytes 3-4 = Length of data in the record (excluding the header itself). 最大为 16KB , 这样就是 360 公告中在 OpenSSL 1.0.2x 系列版本一次重新协商最多能在 Server 端分配 16KB 内存的原因。
CVE-2016-6304 填充的 TLSEXT_TYPE_status_request 是 RFC 4366中 Handshake Protocol 补充字段(链接https://tools.ietf.org/html/rfc5246#section-7.4.1.4):
在原来的 ClientHello 的基础上补充了 client_hello_extension_list :
ExtensionType 是一个 enum 的数据结构:
status_request 就是ExtensionType 中的一个成员,在http://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml 可以看到更详细 IANA 对 ExtensionType 分配的信息:
OpenSSL 1.0.2i 对 Extension 的支持如下:
再来看看 OCSP Stapling 是什么?
OCSP 的全称是 Online Certificate Status Protocol ,是为替换 CRL 设计的。 如果在服务端开启 OCSP Stapling 的话,在 TLS Full Handshake 阶段能省略去 CA 验证证书的过程,一般来说能节约 2 个 RTT 。
看下移动网络下的第一次 HTTPS 第一次数据传输,假设证书深度为 3 ,会经历 11 这个过程:
如果开启在 Server 端开启 OCSP Stapling , 则会省去 5-9 这几个过程,本身是非常好的设计, CVE-2016-6304 和 OCSP 的设计并没有直接关系,是实现上的 Bug 。
t1_lib.c 中的 ssl_scan_clienthello_tlsext 函数没有释放上一次协商过程中分配的OCSP_RESPID ,最终导致了连续多次协商后有可能耗尽 Server 端内存的 DoS 攻击, 从下面的 Patch 中可以看到修复方案是移除了上次协商时分配的 OCSP_RESPID
CVE-2016-6304 基本对 Nginx 0.8.23 之后的版本没有影响,但还是建议升级到对应的 OpenSSL 最新稳定版。
CVE-2016-6304 能触发的前提是 Server 端允许 Client 发起的 Renegotiation ,最近几年的发展来看,在 Handshake Protocol 中客户端的话语权越来越小,Nginx 在 0.8.23 这个版本中就开始不支持客户端发起的重新协商了。另外一个佐证就是 Chrome 51 的稳定版开始, Chrome 放弃支持由客户端发起的 NPN 了,仅支持 ALPN。
NPN 和 APLN 用于 HTTP 1.1 、SPDY 3.1 、 HTTP/2 的协商, NPN 是由客户端发起, ALPN 是由服务端发起。
温馨提示:本文由滴滴安全部原创,转载请注明来源
原文链接:http://sec.didichuxing.com/notice.html#/detail/63