今年是二战胜利70周年,国家特定选了一天放假以示纪念。想到二战,就一定免不了想到Blitzkrieg。这个词是英语Lightning的德语翻译,中文意思是闪电战、闪击战或者电击战。二战的德军装甲部队,就是依靠Blitzkrieg横扫了西欧平原,东欧平原也扫了一半。
二战中的Blitzkrieg,自有军事和历史学家去研究。不过既然战争是一种攻防对抗,安全也是一种攻防对抗,那么战争中用得到的Blitzkrieg,安全里是不是也能借鉴这种思想呢?
为了防止纸上谈兵,在回答之前,我们先来了解Blitzkrieg究竟是一种怎样的思想。被誉为Blitzkrieg之父的德国人古德里安出的回忆录里谈到对Blitzkrieg的理解,大致可以归纳为“集中使用装甲部队突袭敌军防线,突破防线后直插后方的要害部位,使敌军整个防御体系瘫痪”。Blitzkrieg之所以叫闪电战,一个正是因为“快”如闪电,天下武功,唯快不破,另一个则是因为被击中了会像触电一般浑身瘫痪而丧失抵抗能力。
现在市面很多教授方法的书,脑洞开得很大,譬如说“刘备教你企业管理”,将历史上或者小说中的刘备说过的话,硬套进现代企业管理的框架里,这就出了本噱头很大的书。但我认为,Blitzkrieg的这两个因素,是不太好硬套进安全里的,毕竟老祖宗创造“削足适履”本意不是用来难为高考学生的。Blitzkrieg首先强调“集中”和“突袭”,在军事中自然是符合“集中兵力”和“出其不意”的战争哲学,虽然在某些层面,譬如说对资源的集中使用和针对人性弱点的攻击,在安全上也能勉强找到交集,要扯一本两百多页的快餐书倒也可以,但圈子就绕得有些远了。这里我要谈的,是Blitzkrieg的第二点,也就是突破防线后瘫痪整个防御体系。这一点,在安全攻防,特别是漏洞利用中使用得非常多。前面我们聊过几篇文章的UAF,UAF是一种时下很潮的漏洞类型,我认为成因本质是野指针,这一点,反对的同学不少,毕竟情感上确实不好接受。我们做漏洞研究的,很容易就会形成一种观感,觉得“漏洞”是一种具有完全行为能力的独立个体,和其它代码以及BUG是完全不同的。可是,真的如此吗?
现在安全火了,满世界都是安全攻防安全攻防,各种漏洞漫天飞,可有没有哪篇文章愿意平心静气坐下来,谈谈安全到底攻什么,又防什么呢?防黑客吗,就是不让那些成天关在黑屋子里对着五六个亮着的屏幕噼噼啪啪敲键盘的宅男偷看我们的QQ密码?现在新闻也常常报道安全的消息,譬如说某某又泄露了多少用户数据,谁谁又被盗刷了一百多万人民币,但云云种种背后,到底攻防的是什么呢?是权限。具体一点,是访问和使用的权限。计算机的作用是资源管理,那计算机安全就是资源访问和使用的权限,互联网的作用是信息传递,那互联网安全就是信息访问和使用的权限。要攻的,就是取得权限,要防的,则是防止取得权限。至于漏洞,不过是黑客利用系统中存在的一些问题、BUG、或者其它乱七八糟的“特色功能”,来取得权限的手段而已。
漏洞从来只是手段,而不是目的。漏洞的定义太广了,只要能用来取得权限的任何东西都可以称之为漏洞。所以可以预见,眼下遍地开花的漏洞库一定会出现白帽和厂家为了是否是漏洞以及漏洞的安全威胁等级撕逼,而且将一直撕到地老天荒:因为这里有一个悖论,厂家只认亲眼看到能偷到东西的权限,而白帽却只能站在门外大喊这个权限可以偷到东西。
回到Blitzkrieg。现在假定我们已经找到了一个漏洞,譬如说UAF类型,作为白帽工作到此就算结束了,可是对于写exploit大概还有十万八千里的距离。UAF本质是野指针,理论上野指针是可以读写指向的地址的,但我们找到的这枚UAF到底是可读还是可写亦或是可读可写,取决于我们对这枚指针的使用权限。某大牛曾告诉我,UAF类型的漏洞一年能刷上百个,写居多读居少,可读可写的大概比中彩票的几率要高一点点。统计的可靠性我就不做担保了,不过有一点是绝对的,那就是找到的这枚UAF能够提供的权限,距离想要的权限通常还有十万八千里。
那怎办呢?这里就可以用到Blitzkrieg了,突破一点,也就是取得一点权限,然后利用这一点权限,瘫痪整套防御体系。
还是以UAF为例子。假设我们拿到的这枚是最大众脸的可写型UAF漏洞,野指针的可写性不难想象,根本就是一根筋,指向哪块内存地址就只能写哪块内存地址,可写的范围与指针类型有关。这个权限太小了,可写的范围太窄,又不能读,我是厂家肯定不会为这种小权限买单。所以要“提权”,和渗透测试那种狭义的提权有点像,是要扩大一点权限。
在IE6下,我们通常通过写JS的字符串对象的数据结构来提权。这个版本的JS的字符串类型,数据结构十分简单,首先是占32字节的对象头,接着是占4字节的变量,用来保存字符串长度,这个变量很重要,姑且命名为strlen,最后就是字符串内容。在C语言中,如果输出一段字符串,只有读取到00才停止,IE的作者显然觉得这种规定太没有节操了,如果末尾的00被抹掉,那岂不是可以一直读下去,拥有整块内存的可读权限了(当然是理论上,实际内存里是非常多00的,也就是实际只能输出到下一次碰到00为止)?于是加了一条限制,就是必须小于strlen。但这条约束效力非常微弱,现在我们既然有了枚可写的UAF漏洞,只要将这个strlen改成很大,就拥有了以字符串地址为开头,偏移strlen大小的整块内存的可读权限。
可能有同学会问,既然指针的可写范围极小,恰好写到内存(具体是堆)中某个字符串结构的概率岂不是随便拍一巴掌正巧打中蚊子还低?确实,单个命中的概率极低,因此SkyLined提出HeapSpray技术,中文通常译为堆喷射技术,来解决这一问题。HeapSpray的论文有好几千字,不过中心思想很简单,就是大量申请字符串对象,算是对概率论中大数定理的一种应用。这就好比让空中飞满了蚊子,那么随便一巴掌也就很可能打中一只了。
HeapSpray已经提出有十年了,IE自然已经推出不少新的机制来防御,于是后来发展出更为精准可以绕过cookie的堆风水,以及TK教主半年前公开的价值十万美金的点穴攻击。方式各有不同,但走的都是Blitzkrieg的套路,也即先突破一点,用某个漏洞获取某些局部的小权限,然后通过攻击某个敏感的数据结构来提权,最终瘫痪IE的整套防御体系。当然了,Blitzkrieg的思路不仅限于UAF,也不仅限于IE,譬如对付DEP(DataExecutionPrevention)构成的防御体系,流行的思路也是一些利用没有经过DEP保护的小点构造ROP(ReturnOrientedProgramming)链,这玩意名字很玄乎,至今好像也没个大家都接受的中文翻译,但其实就是一条用ret指令串起来的执行流。执行流中的这些指令无论哪个单拎出来都特别人畜无害,但组合起来却威力无穷,譬如拼成调用VirtualProtect的指令流,或者执行shell命令,都可以达到关掉DEP,从而使整套防御体系形同虚设的目的。
本文内容所提及均为本地测试或经过目标授权同意,旨在提供教育和研究信息,内容已去除关键敏感信息和代码,以防止被恶意利用。文章内提及的漏洞均已修复,作者不鼓励或支持任何形式的非法行为。