善意提醒

如果您打开本站很慢,布局排版混乱,并且看不到图片,那么可能是因为您还没有掌握用科学的方法上网的本领。
显示标签为“分析”的博文。显示所有博文
显示标签为“分析”的博文。显示所有博文

2014-01-22

2014 年 1 月全国性 DNS 劫持事件评析

许久没更新博客了。这次全国性事件既然这么轰动,震惊互联网界及翻墙界,那我就借此机会说上两句。

事件是 15:20 开始的,而我当时 15:30 刚好有个会,所以这个事件只经历了一点开头:
当时我正在整理自己的收藏夹,进行到 windbg 和 ollydbg 的时候,发现需要翻墙才能访问了。刚开始我在疑惑为啥 GFW 会对调试工具下手,难道愚民政策已经扩展到技术界了?随后我发现大部分时间这两个网站的域名被解析到了 65.49.2.178 这个 IP 上。少部分时间的尝试是正确的,但这个概率小得不足以完成大部分文件的载入。由于我用的 DNS 一直都是四个 8 ,所以第一个反应就是这两个站点被 DNS 污染了。
既然是污染,那么应该能抓到正确的 DNS 回应包,只是慢点而已。但这次我发现 DNS 回应包是一对一的,没有多余的包回来。只是第一次解析的时候往往能解析到正确的地址上,后面再解析,回复的就是 65.49.2.178 了。当时我还没试别的网站。
然后开会的时间到了,我就走了。再回来的时候,故障已经基本结束了,没什么时间和机会去分析。技术方面的分析,可以参考 这个。我认为分析得靠谱,符合此次事件的各种特征。我在这里只补充一些文中没有提到的部分。

首先,这不是「DNS 污染」,是「DNS 劫持」。
我这里不是在抠字眼,或者讨论这两个词的定义问题。我只是指出这个事实:这次 GFW 对于 DNS 的攻击方式,跟以往(或者说一直以来)的 DNS 污染有所不同。
一般,GFW 的做法是抢在 DNS 服务器的正常应答之前,伪造一个应答,欺骗客户端。正常的应答仍旧会返回到客户端,只不过 GFW 的欺骗包会很快,相当快,使得客户端不理睬正常的回应包。
但这次不同,从抓包的结果看来,「一问一答」,并没有多余的回应包。即使 DNS 是境外的 8.8.8.8,也是如此。境内的 DNS,尚有别的办法可以进行控制。境外的 DNS,必须是在 DNS 查询 / 回应包的转发路径上对其进行劫持 / 丢弃,才能实现这种效果。

其次,探索一下 GFW 这次这个 DNS 劫持功能的工作模式。
通常而言,要进行 DNS 劫持,GFW 可以有两种基本做法:
  • 劫持 DNS 查询包:截获 DNS 查询包,不把它向目的 DNS 进行转发,然后自己伪造一个 DNS 回应包给客户端发去。
  • 丢弃 DNS 回应包:截获 DNS 回应包,伪造一个 DNS 回应包发给客户端,然后把正确的回应包丢弃,使其不能正常到达客户端。
实际上的情况,可能比这要更复杂一点。比如,丢包的事情,应该是 GFW 的一个状态防火墙完成的。而防火墙的规则添加可能需要一点时间,所以第一次查询时有可能会有正确的回应包漏过。
另外,根据每次都是「一问一答」看来,伪造的 DNS 回应包可能是防火墙规则自动触发。也就是说,DNS 回应包被拦截后,才会伪造一个发给客户端。如果没被拦截,就不会伪造。否则无法解释第一次查询时正确的回应包漏过之时为什么也是「一问一答」。
综合上述情况,并结合 GFW 的部署和需求特点,这次的 DNS 劫持功能应该是采用的第二种工作模式,也就是说对 DNS 回应包进行处理。很显然,对于 GFW 而言:从「非受控区域」过来的数据,才是真正需要控制的「有害数据」。从「受控区域」出去的数据,就算会被判定为「有害」,也没必要进行处理,守株待兔就可以,说不定对方根本就不存在呢。

顺便,对 GFW 的一些技术细节,从这次事件可以有更多的认识。
要完成 DNS 劫持,有一个前提:GFW 可以控制 DNS 包转发路径中的(至少)某个路由器,或者 GFW 自身(的一部分)就是 DNS 包转发路径中串进去的一环。相比之下,如果要做到以前的 DNS 污染,只需要在交换机上旁路接入一台设备,不需要串在路由路径中。
具体而言,从这个 DNS 劫持的功能看来,应该会有三个部件参与:
  • 识别模块:这个可以由一个 IDS 性质的设备来完成。对来自「非受控区域」的 DNS 回应包进行检测。这个完全可以在旁路慢慢做,不影响网络出口的性能。
  • 过滤模块:当识别模块检测到「有害信息」后,会向一个状态防火墙添加一条动态规则。生效不一定很快,但因为是全国性质的,漏也漏不了多少。这条动态规则包括丢弃符合条件的 DNS 回应包,以及驱动欺骗模块去伪造一个 DNS 回应包。这个设备必须串入骨干路由,应该是部署在互联网出口处,基本上必须是一个群集。
  • 欺骗模块:伪造的工作是跟过滤模块联动的,即:丢弃-伪造。这个模块以前应该就存在,部署在旁路上就可以。

回头想想,这些都并不是什么前沿的技术。花不了多少时间我自己都能写出来。目前阻碍这个功能(DNS 劫持)大规模应用的因素,可能主要还是来自性能方面的压力。否则现在对那些敏感域名仍然在大量采用的低效的 DNS 污染早就该换成劫持了。在性能方面而言,用旁路模式当然会好很多。有关人等大概也知道,在 DNS 上无论怎么折腾,也都是锁君子锁不住小人,索性不把宝贵的性能浪费在这里了。

2013-09-09

斯诺登关于 NSA 解密能力爆料的解读

斯诺登最近大概向媒体爆了些料,有不少人被吓着了。比如这篇 文章 一开头就这样写道:
美英三家媒体联合报道称,美国情报机构通过向企业产品注入漏洞等手段,破解 HTTPS、SSL、VPN 等全球互联网主要加密技术,实施监听;美国国家情报总监克拉珀回应称此事「不是新闻」
看起来很吓人对吧?HTTPS、SSL、VPN,这些几乎是我们日常用得最多的翻墙技术手段。如果 NSA 能搞定,那么墙国要山寨过来也就只是时间问题。很多看到的人就是这样推理的。
那么,到底是不是真的有那么吓人呢?

个人觉得,财新网这篇文章的摘要,写得相当的不严谨。不过国内的媒体一贯习惯博人眼球,这样写也很正常。其实如果能认真读完全文,大概不至于被吓得不敢上网。相比之下,《纽约时报》的一篇 报道 就要更为准确一些:
最新披露的文件显示,美国国家安全局(National Security Agency,简称 NSA)在长期的加密技术秘密战争中占了上风,它利用超级计算机、技术花招、法院指令和幕后劝说,对互联网时代保护日常通讯隐私的主要工具造成了损害。
这段话里面,明确提到了这么几个手段,我觉得基本上可以比较准确地概括全文的内容:
  • 超级计算机:也就是硬来,霸王硬上弓,利用超级计算机 + 分布式计算的强大计算能力,暴力破解猜密码。这个没啥好怕的。你要是能让政府动用举国之力来对付你,你大概也不会因为这些事情而害怕了,多少会是个英雄 / 领袖什么的吧?换句话说,要是在中国,找几个人把你关起来拷问,大概成本会低很多,估计也更合领导的意。不小心弄死了参照 李旺阳 处理就行。
  • 技术花招:也就是第一篇文章所提到的,利用(甚至主动引入)产品、协议、服务的漏洞,或者植入软件 / 硬件木马,试图在加密前或解密后获取到信息。既然是叫做「花招」,那么就是一些旁门左道的东西,有用是有用,但并不是说整个 Internet 的安全体系就此崩塌了,防漏堵缺就可以了。
  • 法院指令:要求企业交出密钥或解密后的明文,或者获得访问权限。在美国这算事儿,在天朝大伙儿应该都习惯了吧?没什么好害怕的。
  • 幕后劝说:相对于「法院指令」,其实也就是红脸和白脸的区别而已。我觉得在天朝根本不需要什么「幕后」劝说。所以也一样,没什么好怕的。
所以,看吧。NSA 也不是说真的拥有了什么颠覆性的力量。现有的 Internet 安全体系还在,强如 NSA 也只能绕着边儿想办法。谍报机关嘛,真逼急了啥办法不会想?真没必要自个儿吓自个儿。

2013-09-06

一例 C000001D 错误的分析

公司客服收到用户反映,说我们的软件使用到某个功能的时候,报了一个错误。错误信息只有「External exception C000001D」这么一段文字。

搜一下 C000001D,很容易就能知道对应的含义是 STATUS_ILLEGAL_INSTRUCTION,也就是说程序使用了当前 CPU 所不支持的指令集。我们自己的程序并没有使用太新的指令集,但有一些第三方的接口库可就未必了。由于功能基本上是计算密集型的,所以这些第三方的库如果没注意编译开关,完全有可能造成这种情况。

让客服电话采集了一下用户的硬件信息,果不出所料:AMD Athlon XP 3000+。根据维基百科的 资料 显示,2003 年面市,这是一款可以称得上老旧的 CPU。支持的指令集:MMX、SSE、3DNow,并不算多,关键是没有 SSE2

为什么会怀疑到 SSE2 上面呢?因为前不久刚看了一篇博文,说 Win8 需要 CPU 支持 SSE2 才能安装。这说明 SSE2 所能提供的,已经几乎是现在开发的新软件所必需的基本能力了。另外很多编译器已经默认把 SSE2 优化给打开了。也难怪——这年头,还有谁在用 Pentium III 吗?

总之,合理怀疑之后,先来看看是不是这么一回事。这种事情如果要通过正常途径去沟通,不见得效果好。说不定那个当初负责编译出这个库的程序员早换工作了。就算人还在,编译选项和指令集之间的关系搞不清的程序员大有人在。问还不如自己动手看。以下是用 dumpbin 对其中一个第三方 DLL 库反汇编出来的某个函数的部分代码:
1001314E: 66 0F 6F 06        movdqa      xmm0,xmmword ptr [esi]
10013152: 66 0F 6F 4E 10     movdqa      xmm1,xmmword ptr [esi+10h]
10013157: 66 0F 6F 56 20     movdqa      xmm2,xmmword ptr [esi+20h]
1001315C: 66 0F 6F 5E 30     movdqa      xmm3,xmmword ptr [esi+30h]
10013161: 66 0F 7F 07        movdqa      xmmword ptr [edi],xmm0
10013165: 66 0F 7F 4F 10     movdqa      xmmword ptr [edi+10h],xmm1
1001316A: 66 0F 7F 57 20     movdqa      xmmword ptr [edi+20h],xmm2
1001316F: 66 0F 7F 5F 30     movdqa      xmmword ptr [edi+30h],xmm3
10013174: 66 0F 6F 66 40     movdqa      xmm4,xmmword ptr [esi+40h]
10013179: 66 0F 6F 6E 50     movdqa      xmm5,xmmword ptr [esi+50h]
1001317E: 66 0F 6F 76 60     movdqa      xmm6,xmmword ptr [esi+60h]
10013183: 66 0F 6F 7E 70     movdqa      xmm7,xmmword ptr [esi+70h]
10013188: 66 0F 7F 67 40     movdqa      xmmword ptr [edi+40h],xmm4
1001318D: 66 0F 7F 6F 50     movdqa      xmmword ptr [edi+50h],xmm5
10013192: 66 0F 7F 77 60     movdqa      xmmword ptr [edi+60h],xmm6
10013197: 66 0F 7F 7F 70     movdqa      xmmword ptr [edi+70h],xmm7
1001319C: 8D B6 80 00 00 00  lea         esi,[esi+00000080h]
100131A2: 8D BF 80 00 00 00  lea         edi,[edi+00000080h]
100131A8: 49                 dec         ecx
100131A9: 75 A3              jne         1001314E
SSE2 的指令集可以参见 这里。其实看到 movdqa 就已经很明白了。这个 DLL 库的确用了 SSE2,那么,报错就是很正常的事情。

在分析这个问题的时候,我花了一点时间,希望能找到一个能够列出程序所使用的指令集的静态分析工具,但没有找到答案。当然,就这次的情况而言,我能通过 XMM 寄存器很容易地找到并筛选出 SSE2 的指令。但要是能有一个自动化工具,就更好了。也许还是有这种工具的,只是我目前还不知道吧。如果有谁知道,还望不吝告知。