话说公元前202年,垓下,项羽大败,带八百精锐开着疾跑突围,速度之快,跑到后面只有一百多个兵跟上。本来妥妥能跑路,忽然遇到一个分岔路口,迷了路,这时路边田里正好有个老头,项羽就问他江东怎么走,老头:“往左。”项羽照着走,没走多远马蹄就陷进沼泽地,耽误了时间,被汉军追上。“项王至阴陵,迷失道,问一田父,田父绐曰‘左’。左,乃陷大泽中。以故汉追及之。后来有人说:一定是项羽问路不礼貌,所以田父决定教他做人;也有人说:田父是一位智者,不愿看到继续打仗生灵涂炭,所以故意弄死项羽;还有人说:田父其实是刘邦提前安插的间谍……总之,这段历史告诉我们:指路人很重要,可以让你生,也可以让你死,都不知道咋死的。你也许知道,互联网世界里错综复杂,“地名”也就是服务器地址最初都是用IP地址来记录的,比如202.108.22.5,很难记,容易把人搞晕。于是技术大佬们就设计了一套“域名系统”,英文名叫DNS(Domain Name System)。从此,服务器不仅可以拥有IP地址,还可以给自己挂一个“域名”,方便广大网友寻找。比如上面提到的IP地址:202.108.22.5 其实是www.baidu.com服务器IP。当你在互联网世界唱着小曲飙着车,DNS解析服务器就扮演了“田父”的角色。你在浏览器地址栏里输入:www.hornpub.cn,你的电脑或手机会跑去问“田父”。“老头,羊角酒馆(www.hornpub.cn)咋走?”你的设备问。田父(DNS解析服务器)掏出一卷长长的表格,“嗯,查到了,是66.254.114.41,小伙子注意安全。”“得嘞谢谢,好人一生平安。”你的电脑得了地址,径直前往。于是你就打开了网页。即便你感觉不到,但只要你正常上网,每天至少得跟DNS打上几千次交道。无数个DNS解析服务器分布在地球的各个角落,它们就像永不停歇的机器,为全世界人民服务。每时每刻,假如你能俯瞰世界互联网地图,上面都分布着密密麻麻无数个大大小小的“田父”正在为网民们指路。那么问题来了:如果黑客或者坏人盯上田父,会发生什么?2006年,美国最大的DNS域名解析服务商Dyn就被一个宅男用僵尸网络打瘫,那时,无数人同时抬头看向彼此,他们手里的手机、电脑陷入一片空白。Twitter、spotify、netflix、airbnb、github、reddit、Paypal 等等一系列服务相继瘫痪。攻击共来袭三次,每次持续1小时,史称“美国大断网”。其二是黑客对着“田父”一顿忽悠,把它“策反”,或者让它出错,给人瞎指路。也许你看出来了,第一种情况像是原子弹,虽摧毁一切,但充其量让你上不了网,第二种情况却能神不知鬼不觉地把人带进阴沟里。2020年10月,幺哥坐在GeekPwn极棒大赛的观众席,有幸看到一次利用DNS把人带进沟里的技术演示。当时台上评委拿着目标手机,打开一个网站,起初这个网站显示蓝底红字:评委再次输入刚才的网址,网页就变成红色——这意味着目标手机被劫持到黑客的钓鱼网站。整个过程只花了几分钟。这个攻击的精妙之处在于,选手的电脑并不需要跟目标手机连入同一个网络(专业术语叫Off-path)——这意味着可以像全球巡航导弹一样,黑客躲在地球上的任何一个角落动动手指,都能对千里之外的目标发起这种攻击。为了弄懂其中的奥秘,我默默记下选手们的名字,一回到北京,就杀到清华-奇安信网络安全联合研究中心,逮住当时的几个参赛选手一问究竟。技术小哥:“你知道2008年卡明斯基发现的那个震惊全网的DNS重大漏洞吗?我们这次攻击演示相当于重现了当年那个漏洞的攻击场景。”好吧我显然不知道。于是小哥帮我梳理了一下整件事的前后逻辑:2008年,一个叫卡明斯基的研究员小哥发现了DNS系统的重大安全缺陷,震惊业界。有多震惊?卡明斯基当时给另一位技术大佬保罗·维克西(“域名软件之父”)打电话讲完整个经过,保罗吓得不轻:“你…你…可千万千万别再在电话里重复刚才说过的话了!”他怕电话被人窃听。卡明斯基的那次发现被誉为当年最重要的网络安全事件之一。后来微软公司牵头,和十几个厂商、相关单位闷在会议室里讨论,想出一个缓解机制(具体是什么待会儿讲)。十多年过去了,加州大学河滨分校的钱志云教授带着实验室的同学们研究出一套办法,可以绕过当年的那个缓解机制。讲到这个必须多说一嘴,网络安全技术领域经常出现类似的事:研究者先找到一个漏洞,报告给厂商,等厂商把漏洞修复,大家都以为不会再有问题时,诶~研究者们又想出个办法攻破这个修复机制。但是因为疫情的缘故,钱志云教授和同学们这次不方便回国参加2020年极棒大赛,所以找到他们在国内的小伙伴清华奇安信联队,让他们代劳把攻击方式制成实际可用的攻击程序,到极棒大会的舞台展示。这便出现了第二段中的一幕——载入互联网安全史册的DNS攻击重现江湖。为了解释清楚整个过程,我们还是从2008年DNS的第一场雪说起。你在电脑(或手机)的浏览器里输入网址,也就是网站域名,比如www.qianhei.net你的电脑或手机会跑去问你的 ISP(网络服务提供商,移动联通电信之类)的递归DNS服务器:你的机器:“嘿哥们儿,知道www.qianhei.net怎么走吗?”递归DNS服务器翻了翻它的小本本,发现没写,回复说:“我不晓得,但我可以帮你问一下根域名服务器。”
递归DNS服务器:“大哥,请问您知道www.qianhei.net 的IP地址是多少吗?”根DNS服务器通常不会直接回答,而是会告诉他该找谁:“我不晓得,但是我晓得.net域名都是顶级域名服务器大娃管的,你去问大娃吧。”
于是递归DNS服务器又跑去问顶级DNS服务器“大娃”。递归DNS服务器:“喂?是大娃吧?www.qianhei.net的IP地址是多少?”顶级DNS服务器大娃:“不知道,你去问权威服务器二娃吧,他知道,qianhei.net 这一片归他管。”递归DNS服务器:“喂?二娃吧?请问www.qianhei.net的IP地址是多少?”www.qianhei.net这个域名比较简单,所以到这时二娃已经知道它的IP地址了,假如遇到别的更复杂的域名,比如xieyao.zhenshuai.qianhei.net,二娃还会继续踢皮球给三娃、四娃……权威服务器二娃对递归DNS服务器说:“我知道!我知道!www.qianhei.net的IP地址是47.92.24.48……可以把我脖子上的刀可以放下了吗?”递归DNS服务器历经九九八十一难,终于拿到IP地址,递归给你的电脑,于是你的电脑就可以高高兴兴地访问浅黑科技的官网啦。干完活,递归DNS服务器心想:“这要是每次都这么折腾我一遍,岂不是要我老命?”于是它掏出一张纸,把刚才你问的IP地址和域名的对应关系临时记在上面。这张临时用的纸就叫“DNS缓存”,在一定时间内,当有人再问它www.qianhei.net的IP地址,它直接从缓存里找就行,不必再求别人。DNS的基础知识铺垫完毕,现在问题就出现这个缓存上。从理论上来说,如果黑客如果能想办法让DNS服务器把一条错误的DNS解析记录记录到缓存小本本里,在缓存有效的时间里,就能把人导进沟里。到这里,黑客的目标变成了如何把一条恶意的DNS解析信息写进缓存里。一台DNS服务器每天可能会发出和接到成千上万条请求,为了不弄混,它们会给每一条请求安排一个询问单号(QueryID),是一个二进制、16位数的数字(本文为了方便表达就用十进制数字表示了)。
当域名和QueryID、服务器之间通信用的端口号都能对上时,DNS服务器就会欣然接受这一条消息,并写进缓存里,否则会直接舍弃。相信你已经发现了,QueryID和服务器端口号在这里就像是个暗号。然鹅,DNS服务器在最初设计时也许根本没考虑到网络攻击的问题,QueryID是有规律的,就跟吃饭叫号一样,如果上一单的Query是1001,下一单肯定是1002,再下一单就是1003… …每一次操作系统给服务器分配的通信用的临时端口号也同样有规律可循……即便有些DNS服务器用了随机化的QueryID,二进制的16位数字,总共也就2^16=165536种可能性。黑客一个一个去试就行了,行话叫“爆破”——暴力破解。只要能赶在递归DNS服务器收到真正的答复之前,伪装成权威DNS服务器,给递归DNS服务器回复一个错误的答案,并且QueryID、端口号跟域名能对的上号就行。有点像警匪电影里的交易现场,有人冒充其中一方提前到场,跟对方对上暗号,把货物劫走。具体操作时,黑客会在极短的时间,像加特林机枪一样打过去几万数据包,猜测QueryID,但凡有一个能蒙中,并且能抢在真正的回复到达之前,攻击就成功了。此时,递归DNS服务器正在向四娃请求DNS域名解析。递归DNS服务器:“hi,四娃,这里是询问单号886,请问www.qianhei.net的IP地址是多少?”攻击者赶在四娃之前,抢先向递归DNS服务器发出答复。
攻击者的服务器:“我是四娃,这里是询问单号856的回答,www.qianhei.net的IP地址是666.666.666.666(假的地址)”攻击者的服务器:“我是四娃,这里是询问单号857的回答,www.qianhei.net的IP地址是666.666.666.666。”攻击者的服务器:“我是四娃,这里是询问单号885的回答,www.qianhei.net的IP地址是666.666.666.666。”攻击者的服务器:“我是四娃,这里是询问单号886的回答,www.qianhei.net的IP地址是666.666.666.666。”
最后一次终于蒙对了询问单号QueryID——886,于是这条记录会被递归DNS欣然接受,然后写进缓存小本本里。而根据先来后到的原则,真·四娃姗姗来迟的消息会被直接舍弃。至此,你已经学会了如何黑掉单条DNS解析记录缓存。在黑掉单条DNS解析记录缓存的基础上,卡明斯基想到一个更骚的操作——直接冒充权威服务器,接管整个地盘。还是跟刚才差不多的步骤,只不过忽悠的内容和对象变了。不是直接告诉他一个假的IP地址,而是把它忽悠到黑客搭建的DNS服务器上。
黑客抢在根域名服务器之前答复递归DNS服务器,并且把它引导到了一个黑客搭建的权威DNS服务器上。之后,递归DNS服务器会把黑客搭建的DNS服务器误认为是顶级DNS服务器大娃,并且记在小本本里。于是,黑客接替了大娃的工作。当然,黑客也可以冒充其他权威DNS服务器,总之,葫芦娃中出了个叛徒。会议室里,来自微软和其他众多厂商的技术大佬愁眉苦脸,正商量对策。这个问题最头疼之处在于DNS是互联网的基础设施,很多协议、字段都已经定好了,不好随意改动。大家明明知道,只需要把QueryID的位数扩大就可以延长黑客猜出来的时间,让他没法赶在真正的消息到达之前“加塞”,但QueryID没法改——它就像是互联网的铁轨宽度,无数列车每时每刻跑在上面,这时候你说这个宽度不不对,要改?可以,但代价太大。2008年“卡明斯基事件”之后,DNS服务器每次通信都会在1024~65536号端口中随机选一个端口号和对方建立通信连接。还是和之前一样,只有当端口号、QueryID、域名同时匹配才接受对方的消息。这就好比黑帮老大有2500多个电话分机,每次随便用一个电话跟对方交易,如果用36号机发出去消息,就只接受打到36号分机的电话。如果其他分机接到电话,即便能对上暗号,那也肯定有问题。如此一来,黑客同时蒙中端口号、QueryID的概率就是2^16×(165536-1024)=4,227,858,432分之一。攻击所需的时间从一开始的几秒钟变成了十几天,从理论上来说就不可能赶在真消息到达之前“加塞”。“只要有办法在很短的时间内猜中端口号,就可以把攻击需要的时间重新缩短”清华奇安信联队的技术小哥说。2020年前后,加州大学河滨分校的钱志云教授轻抚羽扇微微一笑:不难不难,你有端口随机化,我有侧信道攻击。所谓侧信道攻击,就是旁敲侧击——先找到对方“不经意之间泄露的信息通道”,再通过两件事的关联性来推断出关键信息。其一:听保险柜转动的声音来判断密码,收集保险柜不经易泄露的声音信道,再通过声音-机械位置-密码的关联性来推测出密码。其二:利用显示器、键盘泄露出的无线电波来窃取计算机里的内容,以及利用芯片泄露出来的微弱无线电波来破解其中的密钥。其三:隔壁老王想知道你在不在家,不必敲开你家门看,看看你家水表、电表的走数就能大概判断里头有几个人,再看看门口的垃圾、再看看车库里的车……利用这些不经意泄露出来的信息,再找到信息之间的关联即可。那具体要怎么把DNS服务器通信的随机端口给找出来呢?钱老师发现Linux操作系统有一个机制:默认限制一台服务器在20ms之内最多只能发送50个ICMP包。(记住这个,这是攻击的关键)ICMP包是个啥呢?我们有时候测电脑有没有连上网,测一个服务器或者网站通不通,会“ping一下”,发出的就是ICMP包。此时,递归DNS服务器正用1075号端口和权威DNS服务器“大娃”通信。它们用了一种叫 Connect UDP 的通信方式,通信的端口只对正在通信的服务器开放——这意味着黑客无法从外部直接扫出哪个端口开着。即便向1075号端口发数据包,也会提示该端口是关闭的。首先,黑客把所有可能的端口分组,每一组50个,然后把自己的IP地址伪装成大娃,给递归DNS服务器的1024~1074号端口依次发一个ICMP包,在20ms内完成。“hello?在吗?我是大娃……端口1024在吗?”“hello?在吗?我是大娃……端口1025在吗?”“hello?在吗?我是大娃……端口1026在吗?”“hello?在吗?我是大娃……端口1027在吗?”互联网世界有一个设定,默认情况下,无论是谁给你发一个ICMP包,你都一定会返回给对方一个ICMP包,告诉对方你“在不在”。因为1024~1074号端口全都没开,所以递归DNS服务器会返回50个ICMP包给大娃(由于黑客伪装成大娃的IP,所以目标服务器会把消息返还给大娃,而不是黑客)此时,目标DNS服务器在20ms内的50次ICMP包限制被全部消耗完,当黑客再用自己的IP地址发送一个ICMP包给目标DNS服务器,它就没法回应了。于是黑客可以得出结论:1024~1074号端口一个都没开。“hello?在吗?我是大娃……端口1075在吗?”“hello?在吗?我是大娃……端口1076在吗?”“hello?在吗?我是大娃……端口1077在吗?”“hello?在吗?我是大娃……端口1078在吗?”由于除了1075号之外的其他49个端口都没开,于是目标DNS服务器会回复49个ICMP包。而1075号端口此时已经和大娃建立了Connect UDP连接,所以目标服务器会直接在跟大娃的通信连接里回复大娃:“咦,我俩不是已经建立连接了么,你还问我在不在干啥?”不会消耗ICMP包。由于这次只发了49个ICMP包,所以目标DNS服务器在20ms内还剩一次发ICMP包的机会。这时黑客再用自己的IP地址发一个ICMP包过去,就能得到回应:“不在。”于是,黑客可以判断:1075~1125号之间的某个端口开了。之后再把1075~1125号端口继续分组,用类似方法,逐渐缩小猜测范围,最终就找到目标1075号端口。一旦猜中端口号,就绕开了2008年的那套“端口随机化”的缓解机制,之后再按照卡明斯基的那套方法做就好啦~至此,2008年影响最大的DNS安全事件的攻击手法,以及后续攻破其缓解机制的手法全部呈现在你眼前。清华奇安信联队的一位选手小杨告诉我,尽管理论上听起来的有点复杂,但实际制作攻击程序……更复杂。上面说到的那一套攻击流程,猜端口号也好,猜QueryID也罢,每个步骤都必须完成地恰到好处,慢了,就没法抢在真消息之前加塞,快了,整个步骤就会乱掉,失去效果。为了抢在真正的DNS信息返回之前“加塞”,他们还需要用到各种手段为自己的攻击扩大窗口期。“DNS服务器之间的通讯有一个防护机制,为了防止被人滥用,一旦某个IP请求次数过多,就会被短暂的拉入黑名单。”他告诉我,他们利用这个机制,一边猜端口号和询问单号,一边伪装成目标DNS服务器给权威服务器不停地发请求,让权威DNS服务器把目标DNS服务器给短暂“拉黑”,这样就能“拖住”他们双方之间的通信,为自己的攻击争取更大的窗口期。在演示时,还得考虑丢包、网络波动和舞台上的信号干扰等情况,任何一点风吹草动都可能导致攻击演示现场翻车。“DNS在互联网世界里无处不在。”小杨说,8月份接到攻击演示的任务时,本来他们想了很多种攻击场景。比如劫持收银系统的支付订单,“可以做到你伸出二维码让店员扫,你扣了款,但是店员其实没收到钱,钱进了坏人的口袋。”再比如汽车安全,“你的汽车要更新系统固件,本来应该去官方地址请求,但是黑客可以通过DNS把它劫持到黑客的服务器,给你下发一个留有后门的固件。”类似的方法还可以用到摄像头、门铃、手机APP等各种等各种场景,他们甚至设想过“让所有参会者的健康码都由绿码变成红码,再变回绿码。”他们准备了一套收银系统、摄像头,但是最终主办方考虑到舞台网络环境复杂,以及可能引起不必要的误会(比如不明真相的吃瓜群众看到收银系统被黑,可能以为是设备有漏洞,或者误以为是支付宝或者微信支付出了漏洞,三人成虎,以讹传讹,相当可怕),于是他们最终决定取消这些展示,仅展示了劫持手机访问网站。当然,在展示之前,他们已经提前把漏洞通报给了Linux社区等相关单位和机构。临走前,我问小杨:“当你得知钱老师破了2008年DNS安全事件的缓解机制时,你心情怎么样?激动不?”这对他们司空见惯。他说,研究诸如TCP、HTTP、DNS、CDN之类的底层网络基础协议或设施的安全问题,是他们的日常。“钱老师的团队之前就在极棒舞台上展示过很多次各种破解。2019年,我们清华奇安信联合实验室也出过一个Https的攻击演示。”他说。走出奇安信的大楼,我看到不远处带着头盔的工人叮叮咣咣正在修路,不由地感慨互联网其实也像现实世界一样,很多东西用着用着就老了,旧了,有些基础设施在最初设计时并没有考虑网络安全问题,用着用着问题就暴露出来。所幸,有这么一群白帽子黑客,他能看到网络世界的千疮百孔,也有本事利用这些漏洞获得高人一等的权和利,但他们决定一点一点修复这个世界。
参考资料:
Steve Friedl's Unixwiz.net Tech Tips.《An Illustrated Guide to the Kaminsky DNS Vulnerability》
看雪『Pwn』版主 BDomne.《TCP 的厄运,网络协议侧信道分析及利用 | GeekPwn 重点项目剖析》
最后说两句:
我在文章《亲爱的黑客朋友,下次去GeekPwn极棒比赛记得先烧一炷香》最后留了一个小小的emoji解密题,最后仅SHAPER同学答对,礼物已寄出,答案和推理过程给公众号发个消息“emoji”即可看。