前言
twitter老哥还是nb啊

分析
首先了解下open_basedir的判断方式
| |
获取open_basedir的设定值,与需要判断的路径一起传进php_check_specific_open_basedir
函数有点长,就讲个大概流程php_check_specific_open_basedir()
将basedir的值复制进local_open_basedir
将需要判断的path传入expand_filepath,如果path是绝对路径,则直接赋值给resolved_name,如果是相对路径,则与当前工作目录拼接处理后,赋值给resolved_name
将当前的open_basedir值传入expand_filepath函数,处理方法与上面一样
(expand_filepath的处理过程就不详细分析了,可以自行查看expand_filepath_with_mode())
最后将resolved_basedir和resolved_name进行比较,如果前resolved_name_len一致,则通过open_basedir的检查
会到twitter老哥的poc,首先是使用chdir切到当前目录的子目录,假设当前open_basedir=/var/www/html,使用chdir('img'),因为是子目录,所以通过了open_basedir的检查,所以当前工作目录就是/var/www/html/img。接着就是ini_set("open_basedir", ".."),先看下ini_set的流程
| |
因为设置的name是open_basedir,所以那些检查跟他没关系,跟进zend_alter_ini_entry_ex
zend_alter_ini_entry_ex()
进入in_modify进行对open_basedir的修改,使用gdb调试发现是进入了ZEND_INI_MH(OnUpdateBaseDir)
ZEND_INI_MH(OnUpdateBaseDir)
发现对值进行了check,通过后才会进行更新
所以根据上面check的流程,resolved_name就为当前工作区(/var/www/html/img)+..,最终为/var/www/html;resolved_basedir就为/var/www/html因为是绝对路径。所以reolved_name==resolved_basedir,通过check,于是open_basedir的值就更新为..
接下来是chdir(".."),resolved_name就为当前工作区(/var/www/html/img)+..,最终为/var/www/html;resolved_basedir就为当前工作区(/var/www/html/img)+..,最终为/var/www/html,通过check,工作区更改为/var/www/html
以此类推,慢慢的最终工作区被更改到根目录,resolved_basedir就为"/" + ".." = "/"了,无论怎样的路径都能通过check,open_basedir失去了作用
结语
如果有错误,请指出,一定改正