[ 登录 ][ 注册 ] 天极传媒: 比特网 | 天极网 | IT专家网 | IT商网 | 52PK游戏网 | 手机天极 | IT分众 |
您现在的位置: IT专家网 > 安全子站 > 评论分析

MS07-029的教训:DNS RPC缓冲溢出漏洞

作者: Michael Howard,  出处:赛迪网, 责任编辑: 张帅, 
2007-08-30 09:52
  本文通过在代码层分析一类漏洞形成的原因,以提醒读者注意,并一道讨论解决这类问题的方法……

  本文通过在代码层分析一类漏洞形成的原因,以提醒读者注意,并一道讨论解决这类问题的方法。

      哪些产品受影响

  这个DNS漏洞只对Windows的服务器平台有影响,WindowsXP和Vista用户丝毫不用担心,因为这种客户操作系统不包含DNS服务器代码,只有DNS客户端代码。DNS服务器默认情况下是关闭的,除非安装的是中小企业版或计算机被配置成活动目录控制器,这样DNS服务器才会默认打开。Windows2000、2003、长角服务器beta2都受到影响。

  该漏洞的本质

  该漏洞出现在RPC监听端口代码段,该端口是为DNS服务器管理所用的,反而在DNS服务主线程监听53端口的编码上没有出现问题。自从Windows XP SP2以来,微软就是用RPC通讯进行默认认证,这是个直接教训,在Blaster蠕虫中以领教。这里更有趣的是RPC端点的匿名访问方式。对于其本身来讲,匿名访问不能仅仅称之为漏洞,而应该说就是一种攻击后门,可导致大范围攻击。

  代码

  该漏洞出现在一个结构中的堆栈,如下:

typedef struct _CountName {
  UCHAR Length;
  UCHAR LabelCount;
  CHAR RawName[ DNS_MAX_NAME_LENGTH+1 ];
  } COUNT_NAME, *PCOUNT_NAME;

  该结构的一个指针被当作DNS主机名参数传递到下面的函数,如果PCOUNT_NAME->RawName溢出的话,非信任的代码就会出现在如下函数的第二个参数中。

      DNS_STATUS Name_ConvertFileNameToCountName(
  PCOUNT_NAME pCountName,
  PCHAR pchName,
  DWORD cchNameLength) {
  PCHAR pch;
  UCHAR ch;
  PCHAR pchstartLabel; // ptr to start of label
  PCHAR pchend; // ptr to end of name
  PCHAR presult;
  PCHAR presultLabel;
  PCHAR presultMax;
  WORD charType = 0;
  WORD maskDowncase;
  DNS_STATUS status;
  INT labelLength; // length of current label
  UCHAR labelCount = 0;
  // result buffer, leave space for label
  presultLabel = presult = pCountName->RawName;
  presultMax = presult + DNS_MAX_NAME_LENGTH;
  presult++;
  // Character selection mask
  // '\' slash quote
  // '.' dot label separator are special chars
  // upper case must be downcased
  // everything else is copied
  maskDowncase = B_UPPER;
  // setup start and end ptrs and verify length
  pchstartLabel = pch = pchName;
  if ( !cchNameLength )
  cchNameLength = strlen( pch );
  pchend = pch + cchNameLength;
  while ( pch ) {
  if ( pch >= pchend ) {
  ch = 0;
  charType = FC_NULL;
  }
  ...
  // downcase upper case
  if ( charType & maskDowncase ) {
  // if name exceeds DNS name max => invalid
  if ( presult >= presultMax )
  goto InvalidName;
  *presult++ = DOWNCASE_ASCII(ch);
  continue;
  }
  if ( charType & B_DOT ) {
  // verify label length
  labelLength = (int)(presult - presultLabel - 1);
  if ( labelLength > DNS_MAX_LABEL_LENGTH )
  goto InvalidName;
  // set label count in result name
  *presultLabel = (CHAR)labelLength;
  presultLabel = presult++;
  if ( pch >= pchend ) {
  if ( labelLength != 0 ) {
  labelCount++;
  *presultLabel = 0;
  break;
  }
  presult--;
  break;
  }
  // set up for next label
  if ( labelLength != 0 ) {
  labelCount++;
  continue;
  }
  goto InvalidName;
  }
  // quoted character
  // - single quote just get next char
  // - octal quote read up to three octal characters
  else if ( ch == SLASH_CHAR ) {
  // if name exceeds DNS name max => invalid
  if ( presult >= presultMax )
  goto InvalidName;
  << 注意:presult的长度未作限制 >>
  << extractQuotedChar 重写了 pch >>
  pch = extractQuotedChar(
  presult++,
  pch,
  pchend );
  }
  }

  我们可以看到,代码中有多处边界检查,但对于决定pch大小的重要变量presult却未加限制,因此就造成了该漏洞。教训啊,少检查一个都不行。

  分析工具

  一般的静态溢出代码分析工具找不出这种错误,因为该结构的本质就是超限的:

      typedef struct _CountName {
  UCHAR Length;
  UCHAR LabelCount;
  CHAR RawName[ DNS_MAX_NAME_LENGTH+1 ];
  } COUNT_NAME, *PCOUNT_NAME;

    我们来看结构中最后一个变量,是一段缓冲区。有一些结构遵循“放在缓冲区后”原则,例如安全标识(SID)结构:

   typedef struct _SID {

   BYTE  Revision;

   BYTE  SubAuthorityCount;

   SID_IDENTIFIER_AUTHORITY IdentifierAuthority;

   DWORD SubAuthority[ANYSIZE_ARRAY];

   } SID, *PSID;

  SID结构的最后一个变量是由DWORD组成的缓冲区,并且ANYSIZE_ARRAY初始化会设置成1。这就是通常所说的可变长数组,一般的静态分析工具遇到这种情况,就会有针对性的改变搜寻方式来查找bug,然而PCOUNT_NAME->RawName是固定长度数组,分析工具就不会对其进行有针对性的分析。简而言之,利用可变长数组和静态分析工具就可以检查到这种bug。

  Fuzz测试

  因为这是一个管理员权限的接口,只需要执行了最小的RPC Fuzz测试,虽然没有发现该漏洞,那是因为判断RPC端点是否需要认证。要提供一套接口,分析和测试是非常重要的,如果是可以远程匿名访问的接口,就一定要好好检查,其比本地管理接口出问题的可能性要大很多。要注意Fuzz测试也就这么大能耐了,其很有效,但对于发现所有漏洞来说,还远远不够。

  操作系统防御

  Windows2000基本没有任何防御,没有防火墙、没有/GS(编译时缓冲区安全检查指令)、没有DEP/NX(代码执行防护)和ASLR(地址空间布局随机化),利用代码漏洞很容易。

  Windows2003是使用/GS、DEP/NX编译的,但是没有ASLR,自带有个防火墙,但默认没开。而且由于编码的原因,即使编译时打开/GS,也漏掉了很多bug。

  Windows长角服务器和现在的Windows2008,是以/GS方式编译,链接是采用/SafeSEH和DEP/NX以及ASLR,使得堆栈随机分布。同时自带防火墙,这种组合防御增加了安全性。

  另一个重要的防御措施是服务重启策略,这个策略和ALSR一道增加缓冲区溢出攻击难度,因为ALSR使得攻击需要多次尝试,而服务重启策略限定了尝试次数。

  总结

  通过研究DNS RPC漏洞,我们要对RPC端点匿名认证多加小心,同时在缓冲区溢出检查时,注意可变长数组的用法。

  • 本文关键词:

网友评论

笔名 
请您注意:遵守国家有关法律、法规,尊重网上道德,承担一切因您的行为而直接或间接引起的法律责任。    IT专家网友拥有管理笔名和留言的一切权利。

邮件订阅


    • 解析Windows密码安全问题(第三部分)评论
      在前两部分文章中,我们讨论了Windows密码政策的问题以及它是如何在Active Directory环境被控制等问题,大家应该还记得在默认情况下密码政策和相关的设置位于默认域策略中(Default Domain Policy)。另外同样探讨了可以使用哪些技术破获windows密码,以及每种攻击方式的限制问题。那么,在本文中,我们将讨论如何让windows密码变得更加安全,以及如何能够解决在前两部分文章中出现的所有问题。本文将涉及Windows2002/2003/2008Active Directory默认安装带来的可能性以及其他能够整体提高密码安全的技术。
    • IDC创新和安全白皮书:合作或竞争评论
      业务创新是业务发展战略非常重要的一部分,并而日益成为公司保持竞争优势的决定性因素。由于创新的战略重要性,导致了我们越来越关注信息安全机制在抑制甚至扼杀业务创新方面起到的作用。IDC认为公司不仅是需要找到业务创新和有可能扼杀这种创新的信息安全机制,而且需要在这两者之间找到一个简洁的平衡来满足自己的业务需求。成功的企业能够在商业竞争中占有优势,是因为他们懂得去合理的利用两者使之成为一种具有杠杆作用的机制,而其它的企业只是单单强调其中的一个。
    • 预防企业数据丢失的6种最佳实践评论
      根据“私有权清算中心”(一家非赢利性消费者信息和倡导组织)的统计,自2005年1月以来,有将近2200万条记录遭到破坏。数据失窃和丢失案件数量惊人,这不仅是因为安全入侵事件正在以惊人的速度持续增长,数据丢失引发的财产损失事件也同样在飞速增加。根据美国政府的估计,所谓的“企业数据丢失”在去年使商业界损失了近1050亿美元。根据波尼蒙研究所(Ponemon Institute)的统计,仅仅内部人士导致的数据受损一项,每年给商业界造成的损失为平均每家公司3-4百万美元。产业分析公司Gartner集团估计,恢复数据的开销可以达到每条破坏记录150美元之高——这一数字还没有包括重拾客户信任和重建品牌价值、可能的罚款以及法律诉讼代理费的资金投入。在企业数据丢失案件有增无减的同时,公司也正在不断搜集更多数据,以求优化商业流程,改善客户服务,以及提升与合作伙伴的关系。更多的数据转化为相关数据在整个企业中数量不断增多的信息系统之间更广泛的传播。其结果就是——随着公司内外越来越多的用户获得接入系统的权限,敏感数据遭到破坏的风险也在不断增大。
    • RSA白皮书:管理银行的信息风险评论
      信息是银行的基础,但直到现在,金融机构还往往满足于以业务封闭式的方式管理风险。然而,行业的压力促使银行开始对这种战略展开思考。