许多Web脚本语言支持动态执行在运行时生成的代码。这种特性允许开发者创建可根据各种数据和条件动态修改其代码的应用程序。如果用户输入合并到可动态执行的代码中,那么攻击者就可以提交专门设计的输入,破坏原有的数据,指定服务器执行自己的命令,就好像这些命令是由最初的开发者编写的一样。这时,攻击者的第一个目标通常是注入运行操作系统命令的API。
PHP函数eval可用于动态执行在运行时传送给该函数的代码。下面以一个搜索功能为例,该功能允许用户创建保存的搜索,然后在用户界面上以链接的形式动态生成这些搜索。用户使用下面的URL访问该搜索功能:
服务器端应用程序通过动态生成变量来执行这项功能,生成的变量包含在storedsearch参数中指定的名/值对;此处,它创建值为wahh的变量mysearch。
这时,就可以提交专门设计的输入,由eval函数动态执行,从而在服务器端应用程序中注入任意PHP命令。分号字符可用于在单独一个参数中将几个命令连接在一起。例如,要检索文件/etc/password的内容,可以使用file_get_contents或system命令:
注解
Perl语言也包含一个可通过同样的方式加以利用的eval函数。注意,可能需要对分号字符进行URL编码(为%3b),因为一些CGI脚本解析器将它解释为参数分隔符。在传统的ASP中,Execute()执行类似的任务。
在应用程序解析过程中(请参阅第4章了解有关内容),通过调用外部进程或访问文件系统,应该能确定任何Web应用程序与基础操作系统交互的情形。攻击者开始攻击前要探查所有这些功能,寻找命令注入漏洞。然而,实际上,应用程序发出的操作系统命令中可能包含用户提交的任 何数据项,包括每个URL、请求主体参数及cookie。因此,为对应用程序进行全面彻底的测试,必须检查每项应用程序功能中的所有这些数据项。
不同的命令解释器处理shell元字符的方式各不相同。理论上,任何类型的应用程序开发平台或Web服务器可能会调用任何shell解释器,在它自己或任何其他主机的操作系统上运行。因此,不应根据对Web服务器操作系统的了解,对应用程序如何处理元字符做出任何假设。
有两种类型的元字符可用于在一个现有的预先设定的命令中注入一个独立的命令。
字符;|&和换行符可用于将几个命令逐个连接在一起。有些时候,可以成对使用这些字符以达到不同的效果。例如,在Windows命令解释器中,使用&&则第二个命令只有在第一个命令成功执行后才会运行。使用||则总运行第二个命令,无论第一个命令是否成功执行。
和本章开头的示例一样,反引号(`)用于将一个独立的命令包含在最初的命令处理的数据中。把一个注入的命令放在反引号内shell解释器就会执行该命令,并用这个命令的结果代替被包含的文本,然后继续执行得到的命令字符串。
在前面的示例中,可以直接确定是否可以注入命令,并获得注入命令的执行结果,因为应用程序会在响应中立即返回那些结果。然而,在许多情况下,这样做是不可能的。可以注入一个命令,但它不会返回结果,也不会以任何可确定的方式影响应用程序随后的处理过程。或者由于几个命令连接在一起,注入命令的执行结果在执行过程中丢失了。
通常,检测命令注入是否可行的最可靠方法是使用时间延迟推断,类似于前面描述的利用盲目SQL注入时使用的方法。如果一个潜在的漏洞可能存在,那么就可以使用其他方法确定这个漏洞,并获得注入命令的执行结果。