服务咨询热线:

022-88711099

当前位置:

权威黑客知识讲座(二):漏洞的起源

发布时间:2014-11-13 13:43 作者:刘筱影&Evil 访问量:1572

权威黑客知识讲座(二):漏洞的起源

 漏洞,通过非预期方法使用非法输入使程序没有按照既定规则运行,得到神奇的输出结果。

因为漏洞的存在所以黑客才会乐此不疲地开发出对应的精简,高效,优雅的代码来对其进行攻击和检测。漏洞与程序的开发和测试息息相关。

      (一)何为程序

 所谓程序,是以一定输入按照既定规则运行产生预期结果。联系到现实生活中如:

1、烹饪(以一定的原材料按照工序处理产生美食)

2、自驾游(通过驾驶员按照原定路线驶向目的地)

3、足球赛(一群球员按照比赛规则通过运球,传球,射门赢得比赛)等等。

烹饪有菜谱,驾驶有路线图,踢球也有游戏规则,同理计算机也一样。

 由于计算机不懂人类语言,所以当人想与计算机沟通交流时,就要试着学会使用机器语言,然而机器语言对于常人来说非常的复杂且难以理解,机器语言由原始的位和字节码组成,而且随着计算机体系结构的不同而变化。

通常为了给某一个架构的CPU(如Intel X86)编写程序,程序员不得不计算好与每一条指令相对应的值,了解指令之间是如何交互,以及许多其他的底层细节,所以这种晦涩复杂的开发语言注定不会被太多人所掌握。

翻译程序的出现克服了机器语言程序面临的困难,汇编就是典型的机器语言翻译程序(当汇编程序运行时会自动翻译成可识别的代码程序),它使用不同的指令和变量命名取代了生涩的01机器码,然而它却远远不够直观,指令名依然深奥,依然与计算机体系结构密切相关(X86汇编语言的程序无法运行在Sparc处理器上,因为IntelX86与Sparc是截然不同的,程序迁移到其他平台只能全部重写),想要使写出高效的汇编程序依然需要懂得许多关于处理器的底层细节。

<!扫盲:什么是Sparc处理器?—————–

1987年,SUN和TI公司合作开发了RISC微处理器——SPARC。SPARC微处理器最突出的特点就是它的可扩展性,这是业界出现的第一款有可扩展性功能的微处理。SPARC的推出为SUN赢得了高端微处理器市场的领先地位。

Sun是世界上第一个将RISC架构给以量产的厂商(亲们,不要认为Sun只有Java)。为了推动SPARC成为业界标准,并提高全球广泛供应来源,SUN也授权多家半导体厂生产自己的SPARC芯片。SPARC的性能超强,价格也较高,公认在UNIX上的表现杰出。)

同类小知识:

如中国的星载计算机(在卫星上使用的计算机系统),就是用的Sparc处理器。在世界范围内星载计算机系统中所使用的处理器架构只有两种,一种是由美国使用的POWERPC架构,另一种就是欧洲主导的SPARC架构。亲觉得我们会用美国的POWERPC架构吗?

 —————–扫盲结束>

为了进一步解决翻译程序的种种困难,人们把目光转向了可以把高级语言翻译成机器语言的编译程序,高级语言与汇编程序相比更加的直观,而且突破了计算机架构和计算机语言的限制,通过高级语言编写的程序,可以通过编译程序编译成适用于各种体系结构的计算机语言。高级语言拥有了人类认知语言的特征,遵循某种语法规则,拥有良好的可读性。

高级语言往往是把一堆程序指令组织到某一个控制结构中,通过函数来实现具体的功能,程序运行时是通过主函数调用一个个函数方法来完成一系列的操作(比如备考,调用读书,笔记,记忆等函数按照一定顺序进行,最后完成备考行为)。

<!扫盲:什么是主函数?—————–

 1、我们写的程序都要依赖于操作系统运行。

 2、操作系统“规定”了任何程序要想在它肉体上运行必须有个主函数,譬如c++中的main函数

3、主函数既是程序的入口,又是程序的出口

4、否则你以为你写的程序如果不按照规范来在操作系统的地盘上真能运行?

—————–扫盲结束>

 (二)漏洞入侵程序

黑客发起攻击往往是通过漏洞入侵程序。

我们知道程序是遵守某种确定的执行流程的一组复杂规则,这些规则最终告诉计算机应该做什么,程序理论上想要按照既定规则运行,甚至考虑到了安全因素,但由于设计本身的缺陷或是程序运行环境的不足,程序运行的结果往往达不到预期甚至是不可预计的错误。

温馨举例:(赵本山小品《捐助》中,赵以为自己按了3000,但是看错了小数点,导致捐了三万出去,程序只会严格按照规则运行,疏忽往往造成非预期的后果)。

多数情况程序员写出的代码都不能准确反映他的意图,如栅栏柱错误(要建造100英尺长的栅栏,每10英尺打一根柱子,很多人第一反映是打10根,但正确答案是需要11根),栅栏柱说明设计者搞错了计算的是数据项而不是数据项间隔,很多时候直觉会给人带来不可预期的错误。

当类似栅栏柱的错误相当隐蔽的存在于程序中,如果按照既定规则和输入进行似乎一切都会很顺利,测试也一切正常,但一旦程序接受了非法的输入,错误的结果会影响整个逻辑导致程序崩溃,在程序受到攻击时,这种错误往往会使一个看似牢不可破的安全程序瞬间崩塌。

举个openSSH的例子,OpenSSH的设计之初是为了替代不安全的未加密的服务(如telnet,rsh,rcp),理论上它代表着安全的终端通信程序,然而就是这个安全程序中存在着及其典型的栅栏柱错误,OpenSSH中有一段代码包含如下if语句:

if(id<0||id>channels_alloc){……}

正确的应该是:

if(id<0||id>=channels_alloc){……}

(请仔细看两句话的区别)

设计的初衷是“如果id大于0或者大于等于channels_alloc则执行下面的操作”,然后却写成了“如果id大于0或者大于channels_alloc则执行下面的操作”,这个疏忽使程序存在被进一步攻击的可能,所有普通用户的认证和登陆都可以获得系统的全部管理权限。显然这不符合OpenSSH这种号称安全程序的初衷,然而计算机只会忠实执行,即使这并不是设计者的本意。

另外一种常见的安全漏洞常常发生在快速更改以扩展程序功能的场景中。

软件本身不可不免的会面临变更升级,然后在带来功能扩展的同时又加大了程序的复杂度,也就不可避免的增加了风险。

举个微软IIS的例子,IIS为用户提供静态的和交互的Web内容,为了完成这项功能就不得不允许用户读写并执行特定目录中的程序和文件,但是这种功能必须限定在那些特定目录下。如果没有加以限制,用户就可以完全控制系统,从安全角度出发,显然这是不可接受的。所以程序中就应该设计有路径检测代码,以阻止用户使用反斜杠字符通过目录树反向退回进入其他目录。

类似程序的漏洞,如IPC$,准确定位这个不应归于系统漏洞,仅仅是为了方便管理员的维护,然而却屡屡被黑客利用加以入侵。蠕虫代码利用Unicode的转换漏洞破坏Web页面(%5c可以转换成反斜杠,用其避开路径检查就可以遍历目录)。

经过以上的介绍相信大家对漏洞应该有了直观的认识,希望大家在通读本文之后能够思考一下你手头程序所面临的安全风险。对应栅栏柱考虑边界测试,对应功能扩展考虑监控风险。要知道做一个合格的安全程序员,你不应只局限于写代码,更多的精力应关注测试,甚至是代码管理(变更管理,风险管理等)。

最后给大家留个思考题,思考一下,前一阵特别火的心脏出血和bash漏洞是怎么产生的。

 

本文作者:

logo

  刘筱影

 六年安全领域实战经验,某上市公司安全运维专家

 微博:http://weibo.com/lxyevil