云服务器价格_云数据库_云主机【优惠】最新活动-搜集站云资讯

网站空间_服务器主机配置_好用

小七 141 0

深入了解CVE-2015-5477以及如何保护CloudFlare虚拟DNS客户

上周,ISC发布了一个补丁,针对bind9dns服务器中的一个可远程攻击的严重漏洞发布了一个补丁,该漏洞能够导致单包崩溃。CC BY 2.0图像由Ralph Aversen提供公共摘要告诉我们,在处理TKEY类型的查询时出错会导致断言失败,进而导致服务器崩溃。由于断言发生在查询解析期间,因此没有办法避免它:它是在接收包时发生的第一件事,在决定如何处理它之前。TKEY查询是在TSIG的上下文中使用的,一个DNS服务器可以用来相互认证的协议。它们的特殊之处在于,与普通的DNS查询不同,它们在消息的额外/附加部分包含一个"meta"记录(类型为TKEY)。CC BY 2.0图像由Ralph Aversen提供由于漏洞攻击包现在是公开的,我想我们可以深入研究一下易受攻击的代码。让我们先看看崩溃实例的输出:2015年8月3日16:38:55.509消息。c:2352:REQUIRE(*name==((void*)0))失败,返回跟踪2015年8月3日16:38:55.510#0 0x100001510d在断言中_failed()+0x5d2015年8月3日16:38:55.510#1 0x1001ee56a in isc_assertion_failed()+0xa2015年8月31日消息2015年8月3日16:38:55.510#3 0x10017279c在dns_tkey_processquery()+0xfc中2015年8月3日16:38:55.510#4 0x100016945 in ns_query_start()+0x6952015年8月3日16:38:55.510#5 0x100008673 in client_request()+0x18d32015年8月3日16:38:55.510#6 0x1002125fe运行中()+0x3ce2015年8月3日16:38:55.510退出(由于断言失败)[1] 37363中止(核心转储)。/bin/named/named-f-c命名.conf这非常有用——毕竟这是一个由失败的断言引起的受控崩溃——它告诉我们什么失败了,在哪里:message.c:2352。这是节选。// https://source.isc.org/git/bind9.git--faa3b61—lib/dns/message.cisc结果dns_message_findname(dns_message_t*msg,dns_u部分_t部分,dns_name_t*目标,dns数据类型\u t类型,dns数据类型覆盖,dns名称**名称,dns数据集{dns_name_t*基金名称;结果;/**这些要求可能过于密集,尤其是*如果东西可以是空的,但是它们保证如果*某些内容是非空的,表示调用者期望它*我们实际上可以填写。*/要求(消息!=空);要求(有效节(节));需要(目标!=空);如果(名字!=空)==>要求(*name==NULL);[...]这里有一个函数"dns_message_findname",它在给定的消息部分中搜索具有给定名称和类型的RRset。它使用了一个非常常见的C API:为了得到结果,调用者传递的指针将被填充(dns_name_t**name,dns_rdataset_t**rdataset)。CC BY 2.0图像由Ralph Aversen提供正如大评论讽刺地承认的那样,在验证这些指针时确实很严格:如果它们不指向(dns_name_t*)NULL,则REQUIRE断言将失败,服务器将崩溃,而不尝试恢复。调用此函数的代码必须格外小心地传递指向空dns_name_t*的指针,该函数将填充该指针以返回找到的名称。在非内存安全语言中,当违反程序员断言时崩溃的情况并不少见,因为程序可能在发生不该发生的事情之后无法清理自己的内存。所以我们继续我们的调查,爬上堆栈跟踪找到非法调用。下一步是dns_tkey_processquery。这是一个简化的节选。// https://source.isc.org/git/bind9.git--faa3b61—lib/dns/tkey.cisc结果dns密钥进程查询,dns密钥环{isc_result_t result=isc_R_成功;dns_name_t*qname,*名称;dns数据集t*t密钥集;/**解释问题部分。*/结果=dns_message_firstname(msg,dns_SECTION_问题);如果(结果!=ISC\u R\u成功)返回(DNS_R_FORMERR);qname=空;dns_message_currentname(消息,dns_SECTION_QUESTION,&qname);/**查找与问题匹配的TKEY记录。*/tkeyset=NULL;名称=空;结果=dns_message_findname(msg,dns_SECTION_ADDITIONAL,qname,dns数据类型密钥,0,&name,&tkeyset);如果(结果!=ISC\u R\u成功){/**2000年以来的答案是什么*把它说出来。*/如果(dns_message_findname(msg,dns_SECTION_ANSWER,qname,dns数据类型密钥,0,名称(&N),&tkeyset)!=ISC\u R\u成功){结果=DNS_R_former;tkey_log("dns_tkey_processquery:找不到tkey""匹配问题");转到失败;}}[...]这里有两个dns_message_findname调用。因为我们要查找传递脏名称的名称,所以可以忽略前面有显式名称=NULL;的第一个名称;。第二个电话更有趣。在上一个dns_message_findname调用之后,相同的dns_name_t*名称将被重用,而不会将其重置为NULL。这一定是bug所在的地方。CC BY 2.0图像由Ralph Aversen提供现在的问题是:什么时候dns_message_findname设置名称而不返回ISC_R\u SUCCESS(以便if得到满足)?现在让我们来看看完整的功能体。// https://source.isc.org/git/bind9.git--faa3b61—lib/dns/message.cisc结果dns_message_findname(dns_message_t*msg,dns_u部分_t部分,dns_name_t*目标,dns数据类型\u t类型,dns数据类型覆盖,dns名称**名称,dns数据集{dns_name_t*基金名称;结果;/**这些要求可能过于密集,尤其是*如果东西可以是空的,但是它们保证如果*某些内容是非空的,表示调用者期望它*我们实际上可以填写。*/要求(消息!=空);要求(有效节(节));需要(目标!=空);如果(名字!=空)要求(*name==NULL);if(type==dns数据类型\u any){要求(rdataset==NULL);}其他{如果(数据集!=空)要求(*rdataset==NULL);}结果=findname(&foundname,target,&消息->节[节]);if(结果==ISC\u R\u NOTFOUND)返回(DNS_R_NXDOMAIN);否则如果(结果!=ISC\u R\u成功)返回(结果);如果(名字!=空)*名称=基金名称;/**现在来看看类型。*/if(type==dns数据类型\u any)返回(ISC\u R\u SUCCESS);结果=dns_message_findtype(foundname,type,covers,rdataset);if(结果==ISC\u R\u NOTFOUND)返回(DNS_R_nxrset);返回(结果);}如您所见,dns_message_findname使用第一个findname将记录与目标名称匹配,然后使用dns_message_findtype来匹配目标类型。在两个电话之间。。。*name=基金名称!因此,如果dns_message_findname可以在dns_SECTION_ADDITIONAL中找到一个name==qname的记录,但结果发现它没有dns\u rdatatype_tkey类型,则会填充名称并返回失败。第二个dns_message_findname调用将在脏名称和。。。繁荣。CC BY 2.0图像由Ralph Aversen提供实际上,补丁只是在第二次调用之前添加name=NULL。(不,我们不可能从补丁开始调查;这有什么好玩的!)diff—git a/lib/dns/tkey.c b/lib/dns/tkey.c索引66210d5..34ad90b 100644---a/lib/dns/tkey.c+++b/lib/dns/tkey.c@@-654,6+654,7@@dns_tkey_processquery(dns_message_t*msg,dns_tkeyctx t*tctx,*试试答案部分,因为那是Win2000的地方*把它说出来。*/+名称=空;如果(dns_message_findname(msg,dns_SECTION_ANSWER,qname,dns数据类型密钥,0,名称(&N),&tkeyset)!=ISC\u R\u成功){简而言之,以下是错误流程:接收到类型为TKEY的查询,调用dns_TKEY_processquery来解析它第一次在额外部分调用dns_message_findname在额外的部分中找到了与查询同名的记录,导致名称被填充,但它不是TKEY记录,导致结果!=成功第二次调用dns_message_findname以在ANS部分中查找,并传递now dirty name引用断言*名称!=NULL失败,绑定崩溃这个虫子是由@jfoote悻发现的。fuzzer是一种自动工具,它不断地向目标程序提供自动变化的输入,直到它崩溃为止。您可以看到它最终是如何偶然发现了TKEY query+non-TKEY EXTRA-RR组合并找到了这个bug。虚拟DNS客户始终受到保护好消息!CloudFlare虚拟DNS客户始终受到保护,不受此攻击,即使他们运行BIND。我们的定制godns服务器RRDNS在将所有查询转发到源服务器(如果需要的话)之前会对所有查询进行解析和清理。由于虚拟DNS不支持TSIG和TKEY(这是为了验证服务器到服务器的流量,而不是递归查找),它没有理由在查询中中继额外的部分记录,所以它不支持!这减少了攻击面,并确实使得无法通过虚拟DNS利用此漏洞。没有专门的规则来防止这个特定的漏洞:rrdn总是验证传入的数据包,确保它们看起来像常规查询,并在转发它们之前将它们分解成最简单的形式。