日期:2016-2-1 浏览次数:4155次

前几天在wooyun上发布了个漏洞:WooYun: PHP safe_mode等安全配置绕过 
这里有一些有意思的地方,主站不方便讨论,发到zone里做一些补充说明。 

1、这个问题不是个新问题,其实就是我去年在zone里发的"PHP FastCGI 的远程利用"这个问题。只是去年的问题场景是远程利用,需要管理员将其配置在外网。当时这个问题提交PHP官方,官方认为这是个个人配置错误的问题,无需修补。这一点我也承认,但是官方没有关注到问题本质,实际上这是两个问题的复合造成的漏洞,一个是fpm本身不知道发起请求的另一方是否真的是webserver,另一个是fpm允许通过这个请求传递参数修改php.ini中的配置。于是这一次我换了一种场景,也就是在云平台或者其他共享主机平台中,允许运行客户提交的脚本,而这个fcgi虽然是在本机的9000端口,不对外,但是也可以利用此问题绕过原本进行安全限制的safe_mode/open_basedir等限制。 

2、disable_functions/disable_classes无法通过此方法进行绕过。这个问题本来想在漏洞提交时候就写明的,但是修改漏洞后不知到为什么wooyun没有审核通过,因此现在的版本中没有附加这个说明。 
在php-fpm.conf中,我们可以看到这样一段话: 

; Defining 'disable_functions' or 'disable_classes' will not 
; overwrite previously defined php.ini values, but will append the new value 
; instead.


也就是说,如果你通过fpm进行修改disable_functions/disable_classes的值,是不会覆盖原有的配置,而只是在原有配置基础上再disable你所添加的函数或者类。 
是不是PHP预先考虑到了这里存在安全问题,才会做的限制?实际上并不是这样。这个和disable_functions/disable_classes的实现方式有关。如果你愿意阅读一下PHP的源代码,会发现在php的实现中,内置函数和内置类其实都是在内存中维护了两个hash列表,存放着函数的地址。在php进程刚开始运行时,就读取了php.ini的配置。这时候就会按照disable_functions/disable_classes的配置,去函数和类的hash列表中删除对应的内容。 

ZEND_API int zend_disable_function(char *function_name, uint function_name_length TSRMLS_DC) /* {{{ */ 

  if (zend_hash_del(CG(function_table), function_name, function_name_length+1)==FAILURE) { 
    return FAILURE; 
  } 
  disabled_function[0].fname = function_name; 
  return zend_register_functions(NULL, disabled_function, CG(function_table), MODULE_PERSISTENT TSRMLS_CC); 
}


因此,如果你后续再用fpm的php_value等方式之类内容去修改disable_functions/disable_classes的值,这时候原有的函数已经被删除了,无法再进行恢复,因此新来的值只能附加上去,而不是恢复->替代。 

3、正如我在1中所说,这个问题的本质是在于“fpm本身不知道发起请求的另一方是否真的是webserver”和“fpm允许通过这个请求传递参数修改php.ini中的配置”。因此这其实是一个架构的问题。由于fcgi守护进程和webserver分离,这是为了架构上增加可伸缩性,方便前端集群和后端PHP解析集群的分离和扩展,这种架构必然存在两端互不知晓和信任的代价(之前那个memcached其实也是类似的架构和问题)。我在发现漏洞的过程中就思考过,如果PHP需要修补这个漏洞,要么只能限制fcgi参数修改php.ini这项功能,或者白名单可以修改的参数。但这是个临时的方案,而且只能解决一个问题。另一个问题也就是“fpm本身不知道发起请求的另一方是否真的是webserver”,最好的解决方法是在fpm中实现对webserver的认证。从而确定请求来源是webserver。但是这涉及到修改fastcgi协议,而协议本身也不是php官方可以去干涉的内容。因此这可能就进入了一个两难的境地。 
于是我把这个问题提交官方后,看到fat提出的修复方法,果不其然也就是这两种方式。可是这是否真的能起效果?我们拭目以待。 

4、关于漏洞中使用到的exp将暂缓公布。由于提交官方后,看起来这一次官方是有修补的意愿,因此暂时不会公布使用的exp代码。待后续官方公布最终处理方式后再行决定。