PHP 利用 opcache getshell
PHP 利用 opcache getshell
opcache 是php7 自带的缓存引擎,它会编译php的脚本,然后在内存中生成对应的字节码。然后当每次访问同一个页面时,就不用再次编译解释对应php脚本,从而达到提升性能的效果。
默认情况下,opcache将编译php文件生成的字节码存储在内存中,但是也可以修改php.ini添加opcache.file_cache
的值,当内存要满了的时候将生成的字节码存储在指定的文件夹中。
而我们通过opcache getshell 就是通过上传文件或者任意文件写覆盖opcache的缓存二进制文件,从而getshell。
实现要求
如果opcache将缓存文件放在内存中,我们就无法通过覆盖文件做了。所以必须要求php.ini中opcache.file_cache_only
的值为1,这时强制要求将缓存以文件的形式存储。
其次,文件形式的缓存文件存储在指定目录的子目录是有结构的,假设opcache.file_cache
指定的目录为/tmp/opcache
,web目录为/var/www/html
那么首页index.php它存储的结构就为/tmp/opcache/[system_id]/var/www/index.php.bin
。其中system_id是由当前Zend框架和PHP的版本号所组成的,当OPcache首次对这些文件进行缓存处理时,会在文件系统中创建相应的目录。这样为了找到绝对路径,我们就需要一个phpinfo文件实现这个需求。
最后还得关闭时间戳验证opcache.validate_timestamps=0
,否则会验证缓存文件和源文件时间戳导致shell执行失败
实践
我们假设可以以某种方式任意在缓存目录写文件且文件名不变,现在靶机有个名为123.php的文件,在phpinfo中看到opcache.file_cache
的值为tmp/opcache
获得system_id
这个需要phpinfo界面获得信息计算而出, https://github.com/GoSecure/php7-opcache-override 这个工具可以自动将phpinfo界面计算出system_id
首先将phpinfo界面下到本地,再计算system_id

生成恶意二进制缓存文件
二进制缓存文件的头部含有system_id,在本地生成之后,需要手动使用hex编辑器将其修改为上面相同的system_id
首先在本机开启opcache,在同名文件123.php中写入webshell内容并访问,我们就可以在设置的缓存路径中找到,修改其二进制文件,将文件头的system_id修改

getshell
最后上传,访问刚才的123.php即可拿到shell
其他绕过
对于时间戳验证,如果有其他命令注入或者别的利用点可以修改文件时间的可以尝试修改时间。对于wordpress这种框架,有很多文件很长时间间都是没有改过的文件可以直接改为它发布时带有的时间戳。