前言
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
失去了作用
结语
如果有错误,请指出,一定改正