命令执行漏洞 - 0x 代码注入漏洞原因
当应用在调用一些能将字符串转化成代码的函数(如php中的eval)时,没有考虑用户是否能控制这个字符串,将造成代码注入漏洞。
几种常用语言,都有将字符串转化成代码去执行的相关函数,如:
PHP:eval、assert
Javascript:eval
Vbscript: Execute、Eval
Python:exec
Java:Java中没有类似php中eval 函数这种直接可以将字符串转化为代码执行的函数,但是有反射机制,并且有各种基于反射机制的表达式引擎,如:OGNL、SpEL、MVEL等,这些都能造成代码执行漏洞
应用有时候会考虑灵活性、简洁性,在代码中调用eval之类的函数去处理。如phpcms中很常用的string2array 函数:
function string2array($data) {if($data == '') return array();@eval("\$array = $data;");return $array;}
PHP中能造成代码注入的主要函数: eval
、 preg_replace + /e模式
、assert
用的一般就是前两者,CMS中很少用到assert的,至于一些偏门函数就更少了,用的情况仅限于留后门。 常见用法也有如下一些:
eval("\$ret = $data;"); eval("\$ret = deal('$data');"); eval("\$ret = deal("$data");"); preg_replace('/<data>(.*)</data>/e', '$ret = "\\1";'); preg_replace("/\s*\[php\](.+?)\[\/php\]\s*/ies", "\\1", $_GET['h']); ?>
第一个就是刚才之前说phpcms 的,通常$data不会直接来自POST或GET变量(要不也太水了),但通过一些二次漏洞很可能能够造出代码执行(如SQL注入)。 第二个是将$data使用一个函数(deal)处理后再赋值给$ret。那么,传参的方式就很重要了。第二个用的是单引号传参,那么我们只能先闭合单引号,之后才能注入代码。如果应用全局做了addslashes或GPC=on的话,就不能够注入代码了。 第三个与第二个类似,但使用的是双引号传参。双引号在代码中有个很重要的特性,它能解析其中的函数,如我们传入${phpinfo()}
,phpinfo将会被执行,而得到的返回值作为参数传入deal 函数。这个时候,我们就不用考虑闭合引号的事了。 第四个是preg_replace函数的误用,这种用法出现的情况是最多的,也是因为preg_replace第二个参数中,包裹正则结果\\1的是双引号,通过第三个中的方式,也能执行任意代码。
注意,第五个示例中包裹\\1 的可以是双引号或者单引号,都可以造成命令执行,提交 h=[php]phpinfo()[/php]
。
php curly syntax: ${`ls`} 它将执行花括号内的代码,并将结果替换回去。