在我对软件及其所驱动的工具的攻击生涯中,许多同事认为我采用了一种不符合标准的方法。对于这种说法,我颇感诧异。对我而言,我所采用的方法不仅符合逻辑,而且简单明了。反之,我觉得那些学院派采用的方法对于现实世界的应用程序而言显得过于抽象,难以获得普遍的成功。这些看上去更常规的方法几乎不成章法,没有抓住问题的焦点,甚至完全背道而驰。这些方法往往需要花费数百小时进行逆向工程和应用程序跟踪,才可能在精力耗尽之前发现它们所存在的漏洞。
现在,请不要采用这种错误的方法。我并没有诅咒前面所提到的技巧,事实上我同意它们是发现和利用漏洞的关键工具。但是,我相信可以采用一些捷径,并从另一个视角封装、改进甚至绕过这些方法。
在本章中,我将讨论这些另外的视角,看看它们是如何帮助我们深入到那些被称为安全专家的开发人员的思维中。
为什么要深入到开发人员的思维之中呢?原因有很多,但是在本章中,我们将把注意力集中在对代码的创建过程以及对编写代码的人们所施加的各种约束上。从安全的角度出发,这种问题常常会产生并不是最理想的系统。理解了代码完成时所处的环境、心理和哲学框架之后,我们更容易发现系统中包含可能被攻击者所利用的漏洞的区域。在适当的时候,我会和大家分享一些逸闻作为例子,对一些理念问题进行探讨。
在过去几年里,我的精力集中在大规模的环境,例如大公司、政府机构以及它们的各种附属机构,甚至是州政府。虽然有许多要素也适用于更小的环境,甚至适用于个人,但我喜欢从更广的角度展示这些问题,展现更广阔的社会画面。当然,用这种更为粗犷的画笔作画需要进行一些归纳,读者可能会发现有些情况与这些例子存在冲突。由于篇幅的限制,我并不会举出这方面的反例。
本章的目标并不是强调特定的技术,而是讨论一些导致安全脆弱性的环境和心理情况。对技术实现者所受到的外部影响和限制进行考虑是非常重要的,可以更好地理解这些脆弱性在逻辑上是如何产生的。虽然这对于攻击方而言是一种好玩的智力游戏,但是如果防守方也参与到这个游戏中,就需要考虑一些新的因素:1) 防止可能会导致攻击的错误,2) 使用与攻击者相同的游戏技巧并采用相同的操作方式。此时,这个安全游戏才是我心中最美丽的。
我所讨论的理念可以分为三类:习得性无助和无从选择、验证陷阱和功能锁定。在安全的设计和实现中,这并不是影响因素的安全列表,但它可以作为一个起点,鼓励我们进一步发现自己在系统中所创建或依赖的潜在安全危险。
1.1 习得性无助和无从选择
社会学家和心理学家发现人类和其他动物存在一种现象,这种现象称为习得性无助。它来源于个人在实现自己的目标或者摆脱坏习惯时屡次遭受的挫折。最终,动物们会采取极端的毁灭性措施,就是从内心深处放弃尝试。即使在出现了实现目标的机会或者存在逃脱的良机时,动物们也会表现得很消极,无法利用这些机会。
为了证明即使是资深和理智的软件工程师也会受这个畏缩毛病的影响,我将描述一个由于向后兼容所导致的不良安全性的例子。
向后兼容是现有的技术部署一直存在的一个问题。发现新的技术,并需要部署到不兼容的(甚至在本质上不同的)现有解决方案中。
在系统演化的每个时刻,开发商需要决定是否必须结束现有解决方案的生命,还是提供一条迁移路径或者设计一种方法允许遗留解决方案能够与现代解决方案共存。这样的决定在商业和技术的角度上往往存在很大的分歧。但是,决定通常是从商业的角度作出的,开发人员和工程师必须照办(注1)。出现这种情况时,负责创建实际实现方案的人们就会产生这样一个印象,就是决定已经作出,他们只要照章办理就可以了,不需要进一步的评估或考虑。
想象一下有这样一个决策,在进行技术替换时要求维护与旧技术的兼容。管理层进一步决定,以后不会再向遗留解决方案提供进一步的开发或支持工作,这是为了鼓励现有的顾客迁移到新的替代解决方案。
尽管这种决策在许多方面向开发过程施加了压力(涉及安全问题),但是当一个解决方案(通常是新技术)比其他解决方案更为安全时,无疑会更加引人注目。事实上,新技术的开发常常明确要求满足更高的安全需求,但是仍然必须支持旧技术。在这种情况下会产生什么安全问题呢?
实现向后兼容可以采取不同的方法,有些方法较之其他方法更为安全。但是,一旦开发人员理解了需要让更旧、更缺乏安全的技术继续存活时,那些常常可以缓解这种风险的解决方案往往就不在考虑之列。焦点集中在新技术上,遗留技术将在最大限度地减少遗留效果的情况下被嵌入到新技术中(或反过来)。总之,实际新技术的开发队伍通常并不是开发遗留代码的队伍,他们的最终目标是想方设法移植遗留解决方案,是不是这样呢?
最直接的解决方案是对新技术的健壮性和安全强度作出妥协,以匹配遗留解决方案。在本质上就是允许现代技术和遗留技术共存。当开发人员在迁移遗留代码的漏洞时想不出可以做什么(或更糟,想不出应该做什么)时,就出现了习得性无助。遗留代码对他们施加了压力,他们觉得这不应该在他们的职责范围之内(即使把新技术降低到旧技术的水平而影响了它的安全性)。对于公司的决策,他们觉得不知道做什么好,感觉力不从心。
1.1.1 实例:Microsoft是如何允许L0phtCrack的
数年前,为了帮助系统管理员发现漏洞,我编写了一个密码破解工具,用于恢复Microsoft的用户密码。当时,这个工具称为L0phtCrack,后来重命名为LC5。再后来,Symantec(得到了它的版权)担心违反国际武器限制公约(ITAR)而将它停用了。(注2)网络和技术书籍上有许多文章描述了L0phtCrack的工作原理,但没人关注它为什么会起作用。L0phtCrack所利用的Microsoft Windows的漏洞可能会产生什么影响呢?
事实上,这个工具直接利用了Windows的加密程序的实现和使用中所存在的大量问题。所有这些问题都源于各种版本的Windows(直到Vista)中继续使用的遗留LAN Manager(LANMAN)的散列函数。它的散列表示形式尽管基于已经成熟的数据加密标准(DES),但并没有包含salt。另外,LANMAN中的密码不区分大小写。这个函数把14个字符(或更短)的密码分解为2个7字节的值,每个值根据同一个键进行加密,并连接在一起。当我于20世纪90年代后期在BugTraq的一个帖子上描述这个问题时,基本的加密序列是(见图1-1):
图1-1 LANMAN旧算法的总结
如果密码小于14个字符,就用null字符填满,以便为密码保留14个字符的空间。反之,如果密码大于14个字符,就将它截断。 把14个字符的密码转换为大写形式,并把它分割成7个字符的两半。注意,如果原密码为7个或更少的字符,那么后半部分总是7个null字符。 把7个字符的每半部分转换为一个8字节的检校DES键。 使用前面所提到的每个键对一个已知的常量(“KGS!@#$%”)进行DES加密。 把两个输出连接在一起,形成LM_HASH表示形式。
由于许多技术上的原因,这种选择组合存在问题。
Windows NT的开发人员意识到了LANMAN散列的脆弱性,并使用一种更健壮的算法进行密码信息的存储,称为NT散列。它维护字符的大小写情况,允许密码长于14个字符,并使用更现代的MD4信息摘录产生它的16字节散列值。
遗憾的是,Windows系统在每个密码的更健壮版本旁边继续存储更脆弱的版本,并在用户每次登录时同时在网络上发送这两个版本。在网络上,更脆弱的16字节LANMAN散列值和更健壮的16字节NT散列值都会经历下面的过程,如图1-2所示:
图1-2 在网络上同时处理LANMAN和NT散列
用null字符把散列值填充为21个字节。 把21字节的结果分割为3个7字节的子部分。 把每个7字节的子部分转换为8字节的检校DES键。 使用前面所提及的DES键,对一个8字节的挑战口令(challenge)进行加密,它在网络上发送时是可见的。 把步骤4的3个8字节输出连接在一起,创建一个将通过网络发送的24字节表示形式。
当然,Microsoft希望他们的所有顾客都升级到更新版本的Windows,但是不敢切断使用旧版本的顾客,甚至不敢用新的散列函数对旧版本进行更新。由于密码是网络的一个关键部分,他们不得不假设在可预见的将来,不理解新散列函数的旧系统可以继续连接到使用更安全的散列函数的新系统。
如果登录两端的系统都是使用新散列函数的新系统,就可以使用更健壮的NT散列执行实际的身份认证。但是,在发送更健壮的新散列表示形式时,必须同时发送更旧、更脆弱的LANMAN散列版本。
由于最大限度地照顾了向后兼容,而忽视了它所产生的复杂后果,Microsoft完全破坏了更新的安全技术所带来的技术优点。
L0phtCrack利用了脆弱的LANMAN密码的编码形式,并根据它的结果破解存储在它旁边的更健壮的NTLM表示形式。即使用户选择了长于14个字符的密码,对LANMAN散列的破解仍然要提供前14个字符,只剩下很少一部分需要通过推断或穷举来猜测。和LANMAN不同,NT散列区分大小写。但是,一旦脆弱的版本被破解之后,最多只要尝试2x次(其中x是密码字符串的长度)就可以推断出NT散列的密码大小写情况,因为每个字符最多只有2种选择(大写或小写)。记住,x小于或等于14,因此对于穷举法来说是小意思。
尽管NTLM网络认证引入了一个挑战,可以扮演支持salt机制的角色,但它的输出仍然包含了太多可以被攻击者看到并利用的信息。16个字节的原散列中只有2个字节进入第3个7字节部分。类似,散列值的前半部分中只有1个字节(第8个)进入第2个7字节部分。
想象一下,如果原密码是7个字符或更短(对于粗心的用户,情况很可能是这样)的情况。在LANMAN散列中,第2组的7个输入字节都是null字符,因此输出散列中第9~16字节将总是相同的值。这个情况进一步随着NTLM算法而传播。至少,它并没有设法确定24字节的NTLM认证响应中的最后8个字节是否来自一个短于8个字符的密码。
简而言之,新的现代安全解决方案的问题来自于遗留系统的脆弱LANMAN密码,因此把整体安全性能降低到最小公分母的水平。过了没多久,在接收到太多的负面安全报道之后,Microsoft引入了在默认情况下只发送一种(或另一种)散列值的功能,而不是两者都发送。后来,他们甚至停止了在本地系统中同时存储LANMAN散列值和NT散列值的做法。
1.1.2 密码和身份认证可以从一开始就做得更好
我讲述这个L0phtCrack故事是为了强调一个常见的安全问题。有许多理由支持多种安全实现,即使其中一种被认为优于其他方案。但是如前所述,在许多情况下,这样做的原因是为了支持向后兼容。如果对遗留系统的支持被认为是非常重要的,可以预计在协议和服务方面将会出现相当数量的冗余。
站在安全的角度,现在问题变成了如何在实现向后兼容的同时不降低新系统的安全性。Microsoft的幼稚解决方案嵌入了所有可能性中许多不好的东西:它把不安全的散列值和更安全的散列值存储在一起,通过网络传输这两种散列的表示形式(即使在不需要的情况下),这就为攻击者提供了便利。
记住,习得性无助就是指一个人得出结论,他已经无能为力或者无法通过学习来解决,而不是想方设法对手头上的情况进行实际分析。换句话说,有人告诉你已经没有希望,并且你相信他的原因也仅仅是因为他说“不行”。在工程任务中,习得性无助可以由处于明显权威位置的人们所作的陈述、对向后兼容(或遗留顾客的要求)的消极抵触以及成本或财政压力(预想或真实)而产生。
Microsoft相信遗留系统非常重要,足以阻止废弃这些系统。为此,他们决定继续支持LM散列。
但是,他们采取了第二个关键的步骤,在选择处理遗留系统和现代系统交互的协议问题时迫使新系统同时与当前协议和遗留协议进行对话,而没有考虑遗留系统的安全问题。其实,他们可以要求遗留系统对一些支持登录所需要的函数进行修补,作为遗留系统的最后升级。也许这个解决方案被拒绝的原因是它可能会设置一个危险的前提条件,就是要求支持一些他们已经声称结束了生命的系统。类似,他们可以选择当新旧系统都可以与更现代、更健壮的函数进行对话时,就不在网络上同时发送新旧散列值。这可以帮助他们的旗舰“新技术”同时提供实际的和预想的安全。
最终,由于媒体和顾客对安全脆弱性的持久抱怨,另外也由于像L0phtCrack这样的攻击工具的出现,Microsoft决定让它们的系统避免传递更脆弱的LANMAN散列表示形式。它显示了生产商应该选择一条不同的起始路径,允许终端用户根据自己的安全需求来配置系统。反之,如果相信确实需要遗留系统,必须简单地把它们和新产品放在一起,并让所有的系统把标准降低到最小公分母的水平,终端用户就会成为牺牲品。这是开发商内部设计人员和实现人员的习得性无助的一个例子。
Microsoft并不孤单
为了避免让读者觉得我是专门找Microsoft的茬,我提供了下面这些平等机会(并且可能具有冒犯性)的评论。
在20世纪90年代中期至晚期,Microsoft在市场和媒体上所持的立场是它的系统比Unix更安全。Internet上的服务器大多是Unix系统,Microsoft试图打入这个市场。众所周知,占据公共Internet上的绝大部分系统的各种Unix操作系统已经发现了许多安全漏洞。但是,很少有人从Internet的角度对Microsoft的Windows NT 4.0的安全性进行探索。这是因为NT 4.0系统在网络上只占据了很少一部分的市场份额。
从本质上说,Microsoft的立场就是“我们是安全的,因为我们不是Unix”。但是直到Windows操作系统的Vista版本,Microsoft才真正拥有了具有强大、现代的安全行为的操作系统。Vista存在一些问题,但主要不是安全方面的问题。因此,当NT 4.0作为新产品出现时,Microsoft把矛头对准了Unix,在各种安全问题上对Unix横加指责。后来,情况掉了个头,人们开始指责Microsoft所存在的各种安全问题。现在,Microsoft实际上提供了一种拥有许多强大的安全组件的操作系统,还有哪一家值得挑剔呢?请看Apple。
在历史上,Apple Computer的市场策略与Microsoft有些相似。正如Microsoft以它们并不是Unix为由吹嘘自己的安全性一样,Apple的市场和用户部门声称它们的OS X平台能够更有效地抵御各种攻击和病毒,但所持的理由也仅仅是它们不是Windows。仔细查看了OS X的内核和userland空间之后,我可能断定它还是存在许多安全漏洞(不论是远程还是本地)需要指出和修正。和Microsoft刚开始提供NT时一样,Apple也享受了一段蜜月期。它很少成为攻击目标,因为它的市场份额非常小。但是,随着它的市场份额不断扩大,可以预想它所受到的攻击也会不断增加……
1.1.3 客户的习得性无助—无从选择
正如我们所看到的那样,Microsoft在向后兼容方面作出的选择所导致的不良安全问题可能会让他们的顾客在环境、技术能力以及接受改变的意愿方面产生自暴自弃的观点(不管是否正当)。我把当前网络上的另一个(甚至更大的)安全问题归因于开发商的习得性无助和顾客的无从选择这两个因素的结合。大量的审查显示,大多数网络交换机的生产商有意把交换机设计为“失败时打开”而不是“失败时关闭”。交换机用于在数据链路层上的系统之间移动数据包。在这种情况下,“失败时关闭”意味着设备要么关闭并停止发挥作用,或者以一种“安全的”方式停止操作。这样,数据就不会通过存在问题的系统被传递。反之,“失败时打开”意味着系统停止执行任何智能功能,而是盲目地发送它从所有端口所接收到的数据包(注3)。
在本质上,“失败时打开”的交换机相当于把自身变成了一个哑的集线器。如果只想消极地嗅探自己并不想要的网络交通,那么哑的集线器可能正是我们所需要的。功能正常的交换机试图只把流量发送到合适的目的地。
许多机构觉得消极的网络嗅探并不是实实在在的威胁,因为许多交换机都是这样运行的。但在当前,把一个嗅探器连接到一个被交换的LAN并观察自己不应该看到的数据是极为常见的做法,常常会导致该机构的网络部门的极度惊奇。他们并没有意识到生产商不惜一切代价避免连接断开的决定(很可能是害怕顾客由于间歇性中断而产生的狂怒),因此当交换机在遇到缺陷、安全攻击或者对某些数据包的处理缺乏明确的指令等事件时,就把交换机恢复到哑的广播模式。换句话说,生产商安静地为他们的顾客作出了最适合顾客的决定。
我相信如果顾客能够决定哪种方式更适合自己的利益,无疑会让他们处于更加有利的位置。虽然对于装配线而言,让交换机在失败时打开无疑要比在失败时关闭更合适,但也有一些情况下交换机用于分离重要的流量并隔离内部的域和系统。在这种情况下,对于顾客而言,最好的方式就是交换机在失败时关闭并发送一个警报。顾客至少应该拥有选择的权力。
在这里,我们讨论了生产商所面临的习得性无助以及顾客的无法选择。习得性无助来自于生产商对于它能够教育顾客并让顾客获得选择权这个价值所采取的消极态度。它与前面所讨论的遗留系统的兼容性解决方案有相似之处。生产商相信为顾客提供这种额外的可配置性只会让顾客感到困惑,使顾客把事情搞砸或者向生产商拨打大量的服务支持电话。
顾客的无从选择是可以理解的:顾客是从信誉良好的生产商那里购买外观漂亮的系统,当时一切看上去都很顺利。但这种无从选择并不是把系统的实用性降低到不利的程度。是不是必须要让一个系统在任何环境下都可以工作而降低它的安全性?协议是否盲目地允许遗留版本的系统在较弱的安全级别上进行交互?当系统不知所措时,它是否应该恢复到扮演哑的遗留设备的角色?这些情况常常是由于习得性无助所致。
1.2 确认陷阱
大约1997年8月的某天,我和Hobbit(我的一位朋友,是一位非凡的黑客(注4))与Microsoft的一位执行官和一位资深工程师(注5)共进晚餐。他们想知道我们为什么能够这么轻而易举地在Microsoft的产品中找到这么多的缺陷。虽然有些细节记得不是特别清楚了,但我相信当时我们是非常诚恳地进行了回答,表示我们的方法是向系统输入一些随机的垃圾。这是一种简明的缺陷和安全测试技巧,有时称为“模糊(fuzzing)”,现在主要的计算机科学出版物都记录了这种方法。但是,当时“黑客”社区还没有普遍采用模糊方法。
我们告诉这位工程师,我们对于Windows在面临垃圾输入时如此频繁地遭到失败而颇为吃惊。接着,我们又问他们执行了哪些类型的健壮性测试,因为适当的QA(质量保证)应该包含坏输入测试,这种测试应该能够发现我们所找到的许多令系统和应用程序崩溃的情况。
这位工程师的回答是他们在所有的产品执行了充分的可用性测试,但是并没有执行试图使产品崩溃的测试。这个答案揭示了问题的原因。Microsoft在努力保证良好的用户体验的同时并没有考虑不良的用户或环境。
例如,开发Microsoft Word的队伍将根据各种可接受的输入格式(Word、Word Perfect、 RTF、普通文本等)对文件解析器进行测试。他们并不会对那些可以通过手工创建的但绝不会由可兼容的字处理程序产生的各种预期格式的变型进行测试。但是,恶意攻击者可以用预期格式的不良版本以及随机的垃圾对这些系统进行测试。
当我们在晚餐上询问那些资深的Microsoft代表为什么不发送恶意数据或提供不良文件作为输入对他们的产品进行测试时,他们的答案是:“用户为什么要这样做呢?”当他们看到任何人可以按照有意让软件失败的方法与软件的一部分进行交互时,显得非常的震惊和沮丧。
他们从来没有考虑过他们的应用程序可能被部署在恶意环境中。这种善良的观点来自于另一个可能被恶意攻击者所利用的心理特征:确认陷阱。
1.2.1 概念简介
Microsoft的产品测试的目的是为了确认他们对软件行为的信任,而不是为了打击这种信任。软件架构师和工程师经常会遇到这种盲点。在1968年的一篇论文中,Peter Wason指出“为了获得正确的解决方案,有必要产生一种意愿,就是试图推翻假设,并对那些常常确信是正确的直观想法进行测试”(注6)。他通过一个简单的智力测试演示了确认陷阱。
找一些人并通知他们正在进行一个小实验。我们将向参与者提供一个整数数列,它们遵循一个规则,参与者的任务就是猜出这个规则。为了确定这个规则,参与者可以说出另外的数列,然后我们告诉他这个数列是否符合这个未知的规则。当参与者认为他已经猜中了这个规则时,就可以把它说出来。
这个规则实际上非常简单,就是递增的数列。但是我们先不把它说出来。
我们最初提供的数列是2、4和6。
此时,其中一位参与者提出了数列8、10和12。我们应该告诉他8、10和12确实遵循这个规则。另一位参与者可能提出1、3和5。同样,我们告诉他数列1、3和5也遵循这个规则。
当人们看到初始数列2、4和6时,会注意到一个显而易见的关系,就是每个后续的数都比前一个数大2。当他们提出匹配的数列时,可能会让它满足这种关系,但这完全只是他们自己的想法,与我们的秘密规则无关。当他们所提出的数列得到证实时,会进一步驱使他们确信自己原先的猜测是正确的,而不是想方设法否定自己的猜测。
现在,我们可以把这个秘密规则想象为一个接受输入的软件规则,并把这个小实验的参与者想象为软件测试人员,他们相信所有用户的输入都应该按2递增。他们并不会测试其他数列,例如1、14和9076(更不用提像-55、-30和0这样的数列了)。因此,系统最终肯定会接受没有经过测试的输入,这很可能导致系统的崩溃。
为什么会出现确认陷阱?事实上我们都倾向于自己的猜测是正确的而不是错误的。虽然按照严格的逻辑要求,应该用不遵循自己的假设的数列(例如10、9、8)对这个假设(即所有的输入必须是偶数,或者必须按2递增)进行测试,但是试图增强自己的假设而不是驳斥它却是人类的天性。
“这部分软件是否按预想的工作?”这个问题不仅需要用我们所倾向的方式进行测试,而且要用怪异的、恶意的和随机的方法进行测试。但是,内部软件测试很少会重建常规的终端用户和恶意对手很可能对软件进行这类输入的这个真实场景。
1.2.2 分析师确认陷阱
考虑一位在一个三字母机构(如CIA、FBI)工作的情报分析师。这位分析师希望创建有效、实用的分析报告,以提升她的职业地位。这位分析师从多个来源采集信息,包括她以前所创建的报告。接着,她把这些报告提交给自己的上司。这个过程看上去很简单,但实际上包含了一个潜在的确认陷阱。在她的上司审阅她的工作之前,很可能上司以前也是一位分析师,并且创建了一些报告,并被现在这位分析师作为参考材料。换句话说,输入决策的创建者同时又是决策的审阅者的情况并非罕见。
显然,分析师会产生一种倾向,就是把她的报告与上司的报告保持一致,而不是与之相悖。她很可能会有意识地这样做,特别是当她试图在该社区或机构内获得更好的职业生涯时。当然,她也有可能是无意识地这样做,就像前面Wason的3个升序数字例子一样。至少,这家机构的结构和信息基础形成了一个很强的自增强反馈循环的可能性。
我个人遇到过两个例子,人们认识到确认陷阱的存在,并积极工作以确保不会陷入其中。毫不惊奇的是,这两个例子都涉及用情报分析场景引起我注意的相同人们,他们证实了我对情报报告中经常出现这种错误的怀疑。
1.2.3 陈腐的威胁模型
在上届总统任职期间,我担任了政府部门的一个关键人员小组的顾问。我的重要任务之一是对有些人所收到的关于网络功能(包括攻击性和防御性)的报告发表自己的看法,并指出报告中的哪些研究领域有效或者具有前途。我常常不得不指出,最初的报告在对手模型和技术方面的不准确达到了令人痛心疾首的程度。报告中所描述的技术、策略和功能与具有良好的经济能力和高度的工作动力的对手可能采用的技术相比实在差得太远。报告中所描述的许多只有强有力的国家级对手才有可能使用的技术和策略对于当前的网络发烧友而言只是雕虫小技。
这些报告试图理解网络威胁是如何演变的,但它们却是根据以前的技术进行推断的,显得毫无新意。技术已经发展了,但模型却没有发展,仍然远远落后于现实。因此这些报告所描述的场景对于过去的某个时期而言可能是准确的归纳,但对于当前而言却是过时的和不准确的。这正是确认陷阱的特点。因此,这些需要我进行评论的报告就是由于与前面所提到的分析师陷阱相似的情况下产生的。
1.2.4 正确理解功能
随着L0pht对安全的成功破坏以及像L0phtCrack这样的工具变得广为人知,政府不得不对我们的队伍勉强产生了一点兴趣,希望理解我们能够做些什么。我勉强答应邀请白宫的一群人参观我们的工作,并向他们简单介绍了我们的情况。不得不说,L0pht成员们对于一大群政府代表的来访感到不安,但最终我和其他成员成功说服了每个人,允许这些“政府人员”来到我们的“秘密”地点。
当晚,在会议结束并共进晚餐之后,我陪同政府代表们走到停车场并向他们道别,然后看着他们走向自己的汽车,以确保他们全都离开。当我看到他们停下来悄悄谈话时,心里就疑神疑鬼的。
我快步走到人群中,冲着他们嚷道:“你们不能这样!回到办公室以后,你们想说什么秘密都可以。我们之所以让你们参观,是因为对你们抱有极大的信任。因此,我想知道你们刚才在讨论什么!”这打断了他们的谈话。也许是酒精的作用,使我有勇气对这群颇有身份的人们说出这番话。也许,当时我不知道更好的做法是什么。
我想这番话让他们呆住了。这五个人都是政府高级职员,每个人都把目光投向其中一个人,这个人看上去像是其中地位最高的。他回过头直接注视着我,并解释道:“我们只是在讨论你们是怎么做出这些东西的……”
“您的意思是?”我继续追问。
他回答道:“我们收到的所有报告都表示,你们在这里所完成的功能,如果没有国家的财政支持,是不可能成功的。”我的答复是我们已经向他们证明,我们在没有得到任何资助的情况下已经完成了这些工作(应当注意,低估那些失去面子的好奇的人们的能量是极大的疏忽)。“我们进一步怀疑,”他说道:“有没有任何政府已经采纳了你们的方法或者试图‘雇用’你们?”我很快用我习惯的风格答复道:“没有。至少我还没有注意到。但是您如果愿意,可以成为第一个,我们愿意接受邀请……”
即使我试图摆出幽默的架势,但我们还是不欢而散。
尽管双方都心怀疑虑,并且双方由于立场差异巨大而导致沟通困难,但政府还是明白了我们的成果确实是一些业余发烧友在几乎没有得到任何资助的情况下在业余时间完成的。
这些访问者就是从各个三字母机构接受报告的人。他们意识到这些机构的职业阶梯很容易导致确认偏见。他们被这些机构的官员所说服,以为我们的成果需要大量的资助,只有特定类型的对手才可能实现。因此,他们采取了大胆的步骤,对我们进行了登门拜访,这样他们可能会抵制向他们所灌输的一些基本信仰。他们的步子迈得真是够大的,竟然造访我们隐秘的L0pht基地。但是,他们最终修正了对手发动恐怖的网络攻击真正所需要的条件的假设。
遗憾的是,很多人并不是像他们一样能够或愿意寻找令自己不安的证据来否定自己的假设。在测试软件和系统时,考虑工程师、开发人员和测试人员可能工作的环境以及他们可能具有的先入为主的想法是非常重要的。当涉及应用程序要求做什么以及什么样的输入可能会有意或出乎意料地对它们造成威胁时,这方面的考虑就显得格外重要。
1.3 功能锁定
功能锁定表示无法看到超出某些东西的常见用法范围的其他用法。这与第一印象的概念有点相似,即第一次接触到信息时(例如一篇新闻报告的偏向性标题或起诉方对案件的陈述)所留下的印象,常常会永远地影响听众对这种信息接下来的感知。
当有人提到“锤子”时,一般人首先想到的是一种用于造房子的实用工具。很少有人在听到锤子时立即把它与一种攻击性武器联系在一起。类似,人们在听到“火焰喷射器”这个词时脑海里立即会浮现一幅军事武器的图像,很晚(即使有的话)才有可能想到它是一种通过先发制人的燃烧策略防止火势蔓延的消防工具。
功能锁定就是指不能理解一种工具的最常见用法或“默认”用法之外的其他用法。如果一个人认为一种工具只有一种可能的用法时,我们就把它称为“锁定”。
考虑口袋里的一把零钱中的一枚二角五分硬币。如果有人问你打算怎么使用这枚硬币,你首先的想法很可能是用它来买东西。但是,人们当然也可以把它派到其他用场:
●
用来抛硬币,以决定应该怎么做某样事情。 把它当做起子,例如撬开蛤蜊。 投掷物,用来击中别人。 防止门关闭的垫片。 作为具有美学价值和历史价值的收藏品。
如果忽略这些其他功能,很可能会通过想不到的方式让你感到吃惊,例如有人可能会提出购买你的旧硬币,或者当你把一个硬币送给你家的小孩之后,他却用力把它砸在你的后脑上。
1.3.1 安全位置的潜在风险
既然对功能锁定已经有了一个基本的理解,现在读者可能会疑惑它是如何与计算机和网络产生关联的。
许多人把诸如漏洞扫描器和反病毒软件这样的安全产品看成是能够增加系统或组织安全性的工具。但是,如果这只是你的唯一观点,就有可能遇到功能锁定问题。这类技术的每一个都可能非常复杂,由数千行代码组成。在一个环境中引进它们同时也引进了很大的出现新的漏洞和攻击表面的可能性。
以早年的漏洞扫描器为例,我在自己所在公司的内部网络上设置了一些特殊的系统。这些系统是恶意服务器,目的是攻击当前大多数流行的漏洞扫描器中的客户端漏洞。当时我并没有意识到客户端的漏洞攻击在几年后的恶意软件感染中将会非常频繁地出现。
例如,ISS扫描器将连接到一个远程系统上的指名服务(finger service),以收集远程系统信息。但是,这个扫描软件在它的其中一个安全测试中出现了一个典型问题:这个程序没有检查返回信息的长度,而是盲目地把它复制到一个固定长度的缓冲区。这就在程序堆栈上产生了一种很普通的缓冲区溢出。知道了这个扫描器的这个弱点,并且知道了这个扫描器所运行的系统架构之后,我对恶意服务器进行了设置,以攻击这个漏洞。
当我所在的公司将要接受年度审核时,作为审核者的评估工作的一部分,将从审核者所带入并连接到公司内部网络的笔记本电脑上运行网络漏洞扫描。当这个扫描器最终遇到我的其中一个恶意服务器时,扫描系统本身由于扫描软件的这个漏洞而遭到攻击。
这常常导致很幽默的场景,它为公司的领导层提供了一些借口回应审核人员。由于被攻击的审核系统通常要对多个客户进行审核,因此我们可以用这个审核系统所暴露的其他公司的审核信息来忽悠他们。公司的领导层可以理直气壮地声称,在我们的内部系统中所找到的漏洞(隐藏在防火墙和其他防御技术的后面)相比审核人员向竞争对手泄露敏感信息而言实在算不上什么风险,而且它本身很可能是审核人员所使用的“安全软件”所造成的。功能锁定可能导致人们忘了安全检查软件本身的安全。
遗憾的是,现代的反病毒软件已经被发现包含了各种类型的常见编程漏洞,例如局部缓冲区溢出、未检查的执行功能以及在自动更新活动中缺乏认证等。因此,安全软件也可能为攻击者开启大门,而不是起到防御作用。
前面的例子是功能锁定的简单例子,可以归结于我在习得性无助这一节中所讨论的无从选择。但是,还存在更为微妙的例子。
1.3.2 降低成本与未来收益:ISP实例
安全的最大阻碍来自公司高层对安全需求的负面认识。其中有些认识代表了功能锁定。
几个月前,在著名的分布式拒绝服务攻击Internet上主要服务供应商和商业实体(包括eBay、CNN、Yahoo!),并导致它们临时关闭前,(注7)我曾有机会为一家一级ISP分析骨干路由器配置。经过这些核心路由器的IP流量的主体是TCP流量,特别是HTTP通信。UDP所占据的比例要少得多,至于ICMP则少得可怜。我很惊奇地发现,这些路由器对流量缺乏任何控制,只是采用了一些最低限度的过滤器,以防止某些形式的对这些路由器本身的未授权访问。但是,当我建议对核心路由器的配置进行更改,侧重于保护这家ISP的顾客时,这下轮到公司的领导感到惊奇了,他们立即告诉我此事绝不可行。
两种思维在这里发生了冲突。ISP并不想冒着减少它们的核心路由器吞吐量的风险,如果它们使用了任何类型的具有实质意义的包过滤器,就会发生这种情况。总之,ISP的业务是销售带宽,顾客把它看成是吞吐量。当系统把数据包从A点移动到B点时,就不得不花费额外的时间决定如何处理每个数据包,因此路由器的行为和最终的吞吐量会受到负面影响。
而且,此时不论是ISP还是它的顾客都无法忍受任何负面效果。管理层可以理解可能会发生针对它们的路由器的攻击,但他们愿意等待,在发生这种情况时再对它进行处理。他们觉得在没有出现问题的时候花钱是件浪费的事情,虽然未来出现问题时所需要的花费可能大于现在积极预防问题发生所需要的开销。此外,对顾客的攻击则不在他们的考虑范围。
相反,站在我的角度,尽管当时还没有发生广泛的DDoS攻击事件(事实上,当时还不存在DDoS这个词),但我还是意识到了不仅针对ISP的服务器而且针对背后的顾客的网络资源饿死型攻击的可能性。我知道对顾客的攻击将很难被诊断,并且难以快速作出反应,但是我完全无法说服ISP。事实上,我不得不从商业的角度理解他们的想法。他们对自己的系统不需要进一步采取安全措施的理由多少是符合逻辑的。
(Randy V. Sabett所编写的第12章也讨论了安全是成本而不是收益的问题。)
在大规模的DDoS攻击之后的某个时刻,我有幸被邀请参加在白宫的椭圆办公室所举行的圆桌会议,所坐的位置距离克林顿总统只有几个座位之遥。这个会议的目的是讨论政府和行业如何应对最近的DDoS攻击以及接下来应该做些什么?
在会议上,我再次感到吃惊。商业部门的领导层所表达的主要担心是这些攻击可能会导致政府介入,并对它们的行业进行调控。看上去,他们实际上对于理解或处理当前的技术问题并没有什么兴趣。
我开始渐渐明白,ISP固守一种概念,他们觉得政府在这些事物上的干预很可能会对他们的收益产生负面影响。他们与我在前几个月所遇到的那家拒绝在它们的核心路由器上采用包过滤器的大型ISP具有相同的概念:安全需要花钱,并且只能预防未来潜在的损失。他们从来没有从安全也可能制造收益这个角度去思考问题。
在会议之后,我重新约见了几个月前打过交道的那家大型ISP的执行官。我告诉他,我理解他为什么做出这样的安全决策,并要求他真心回答后来在我脑海里萦绕的一个问题。我要求他假设我并不是站在安全的角度问这个问题的。反之,假设我已经指出ISP可以协商承诺访问速率(Commited Access Rate),根据这些新的确定性更好地规划利用率,并最终使每台关键服务器服务更多的顾客。而且,他们可以使用这个方案为他们所销售的新类型的服务提供不同的记账和报告功能。过滤和测量可以防止用户不合理地占用带宽,但任何客户端所发现有用的网路被封锁或变慢是可以通过不同服务水平来满意解决的。
但是,作为回报,这种过滤可以极大地降低外部恶意因素对带宽的不正当占用。我的问题是—这会不会是一个更好的方法?
他的回答是一声响亮的“是”,因为这家公司把这个方法看成是一个机会,认识到它可能带来的更多收益,而不仅仅是把它看成是与安全姿态相关联的日常开支。
我从这个事情中认识到,我(包括安全领域的绝大多数实干家)受到“安全只是它自己的事情,它并没有被看成是一个不同目标的副产品”这个功能锁定的困扰。正如经常被事实所证明的那样,构建高效和具有良好定义的需求也可以增强安全。
1.3.3 降低成本与未来收益:能源实例
我的工作有一部分涉及详细检查各家电力公司的后端控制系统,有时候还包括石油公司的后端系统。我评估了它们与其他系统和网络的相互联系是如何被保护和跟踪的。令人吃惊的是,石油和电力行业虽然使用了相似的系统和协议,但它们在配置和安全方面的操作和运行存在极大的差别。
换种礼貌的说法,电力公司的网络是一团糟。电力控制系统和网络可以通过公共的Internet访问。用于通用的系统由许多任务所共享,文字处理和其他日常工作与那些关键的功能混杂在一起,后者应该局限于专用的系统内部,以防止操作的潜在干扰和破坏。在好几个地方,系统和网络的布局随心所欲,根本没有考虑过优化的甚至是准确的操作。实现者在完成一项任务之后就转移到另一项工作。许多电力控制网络、电力信息网络和公司LAN没有配备防火墙或阻塞点。从安全的角度出发,所有这些因素结合在一起,可能导致恶意入侵者潜入后大搞破坏,包括操纵或破坏电力的生产和传输过程所使用的物理组件。
相反,我所观察的几个近海石油系统虽然也利用了类似的SCADA系统,却采取了不同的配置和操作方式。电力控制和信息网络严格与公司的LAN分享。大多数关键系统进行了正确的设置,使它们的结果和状态由一个管理系统进行处理,然后用一种类似二极管的风格把信息推向更高的分析系统。简洁和高效的网络图导致物理世界中的SCADA和DCS系统可以被清晰、整洁地实现,包括对访问的限制,有效地提高了安全性。在许多场合,组件是自定义的系统,被设计和配置用来执行特定的功能(注8)。
电力和石油公司之间的反差令我感到好奇和困惑。仿佛是命运的安排,我的职位使我能够与电力公司、石油公司和政府部门的高级技术人员一起开会讨论这个主题。
在会议中,首先令我感到惊奇的是来自电力系统以及电力系统监管和结算组织的人们,他们并没有反驳我对他们的网络和系统的不良(或者说完全不存在的)安全所作出的论断。这令我感到吃惊,因为电力公司在公开场合总是否认它们存在任何网络系统风险。在会议中,他们指出了一些已经正确地实现了安全的例子,但他们承认这些例子只是例外,并不是普遍现象。
我的第二个惊奇来自石油公司,他们表示根本没有站在安全的角度设计他们的系统。尽管安全非常重要,但它并不是正确配置系统的商业推动力。主要的推动力来自它们的直接竞争对手的压力。
如果A公司在关键组件操作的效率能够比B公司高出5%,经过一段时间之后,增加的操作能力或减少的开销可以使A公司赚得大笔的钱。提高这种效率的例子包括:
●
系统的强制分离,防止关键系统由于管理和报告请求所执行的查询而增加额外的延迟。 利用特殊用途的专门完成特定任务的系统替换通用目的的非优化系统。
这些效率改进措施同时也改善了安全。第一个措施在网络和系统中创建了强大、干净和可实施的边界。第二个措施使系统的表面区域变小,从而增加了攻击的难度。
可实施的网络和系统边界的效果显而易见,但更小的表面区域这个情况则值得稍加解释。想象一个具有默认配置的通用目的的系统。默认配置可能已经有几个配置并正在运行的服务,以及许多正在执行的协助用户处理的后台进程。这就允许用最大数量的设置对系统进行部署,并最大限度地减少重新配置的数量。系统的生产商希望这样的系统具有更广的功能,因为这样可以使安装更为方便。
但是,这并不意味着默认设置对于消费者主体都是优化的,只不过是可以接受而已。在默认设置中,每个正在运行的服务都是一个攻击表面,可能会遭到攻击。与此类似的是客户应用程序可能由于来自被盗用或虚假的服务器的恶意输入而被盗用。系统所运行的服务和客户应用程序越多,系统的攻击表面就越大,被远程或本地盗用的可能性也就越大。
虽然具有较大的攻击表面不是件好事情,但是石油公司所关心的基本缺点实际上是系统的性能不够理想。对于每个正在运行的程序,包括服务器所提供的服务以及本地应用程序,处理时间是由内核和CPU贡献的。如果有许多正在运行的应用程序,系统就不得不为它们划分时间片,这是一种本身就会消耗资源的内核活动。
但是,如果正在运行的应用程序数量很少,那么每个应用程序可以拥有更多数量的CPU时间片,实现更佳的性能。对系统进行瘦身的一种简单方法是删除多余的服务和应用程序,对系统进行优化,使它尽可能以最专一的方式运行。另一种方法是系统部署为专门实现特定的功能,不提供运行不相关任务的功能。这些策略在我已经检查过的近海石油公司中使用,以便最大限度地提高性能,并因此增加了利润。
为什么电力企业不采取与石油公司相同的做法呢?首先,电力公司是受控制的垄断企业。这个行业并不存在什么竞争,因此它们就没有动力设计优化和严格结构化的环境。
人们可能忍不住假设如果取消对电力行业的控制,把电力公司放在竞争环境中会不会提高它们的效率并因此提高它们的安全性(按照与石油公司相同的路径)。但是,事态的发展恰好相反。当电力公司放松管制时,它们意识到需要采取削减成本的措施以保持竞争力。结果,它们的第一个步骤就是削减劳动力。它们让更少的人维护和操作相同数量的本地和远程系统(常常通过远程访问技术),把注意力集中在每天都要进行的操作,而不是高瞻远瞩地看到长期的需要。这通常是提高效率或安全的不佳方案。
石油公司的故事证实了我在1.3.2一节中对ISP所作的评论。大多数组织把安全看成是一种令人不快的成本,至少到目前为止它们大都是这样想的。按照这种方式实现的安全很可能是不充分或糟糕的。但是,如果有的公司将网络和系统的功能进行优化和流水化,以实现特定的商业目的,那么它们常常可以以副产品的形式实现优质的安全。同样,安全专业人员可以把克服他们对安全的功能锁定作为一个崇高的目标,直到觉得安全本身值得花费大量的资金,而不是把安全看成是一种偶然的副产品。
1.4 小结
在本章中,我提供了一些经典的安全失败的例子,并在脱离工具、实践和个人决策的情况下对它们进行跟踪,以探索如何进行思考的基本原则。我们可以采用与自然倾向相反的更明智方式应用我们的资源,以提高安全性。
●
我们可以保证最初的决定并不会影响创造性的思维,以克服习得性无助和无从选择。 我们可以寻找不同人群的输入并强制自己试图推翻自己的假设,以克服确认陷阱。 我们可以通过寻求工具的替代用法并通过其他路径来实现目标,以克服功能锁定。
所有这些都需要实践。但是对它们进行实践的机会每天都会出现。如果更多的人致力于此,这种常常称为非比寻常的方法将越来越不稀奇。
上传的附件: