前言
最近刷小密圈的时候,看到了一个phar漏洞的实例,有点好奇在真实CMS中,这种反序列化如何利用,所以就来分析学习一波。
漏洞分析
phpBB是国外一个非常受欢迎的论坛CMS,3.2.3以下的版本存在phar反序列漏洞,可以在登录管理面板的情况下Get Shell
触发点
漏洞位于\includes\functions_acp.php:validate_config_vars()
内,文件操作函数file_exists的变量$path可控,于是可以触发phar反序列化上传的恶意文件导致RCE
回溯可以找到调用validate_config_vars()的地方,位于includes/acp/acp_attachments.php:main()
此处$cfg_array为外界$Request[‘config’]传入并赋值为数组,可控。$display_vars[‘var’]为系统配置数组。回到validate_config_vars()
将传入的$config_vars进行遍历,然后再去判断$cfg_array()中是否存在系统配置数组键名的值,以及配置数组是否存在$config_definition[‘validate’],满足这两个条件之后开始对后者分割为数组,取其第一项为switch语句判断的值。通读全部case分句,找到利用点在wpath
中
1 | if (!$cfg_array[$config_name]) |
这里$path会进行判断$config_definition[‘validate’]是否在wpath、path、rpath、rwpath
之间,判断成功的话前缀就用$phpbb_root_path进行拼接$cfg_array[$config_name],而后者可控。
1 | $phpbb_root_path = (defined('PHPBB_ROOT_PATH')) ? PHPBB_ROOT_PATH : './../'; |
但是在入口文件处,该变量已被赋值为./../
,再与phar://
拼接就不会触发反序列化操作。但是,这里的switch语句在三个case子句中,并没有使用关键词break进行结束循环,反而是继续往下执行,不会执行$path拼接操作。
这三个case为:
- path
- absolute_path
- absolute_path_writable
于是在$display_vars[‘var’]中利用编辑器查找。
找到只有img_imagick
满足条件,在后台控制面板中可以提交phar://路径
提交修改,抓包并断点调试,此处$path被成功赋值,也就是这里可以成功触发反序列化,但是仍需要上传恶意文件并且拿到路径,才能利用
POP链
利用插件Guzzle中一个类的析构方法作为跳板vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php
在文件执行完成之后调用save(),很明显其中有file_put_contents()函数,假如俩个参数均可控就能写入Webshell。回溯其变量,$filename明显可控,而后者先是遍历$this,调用getExpires()和getDiscard(),然后转换为数组传入$json[]。FileCookieJar类
是继承于CookieJar类
,跟进父类
这里再遍历的时候实例化了一个SetCookie()类,然后调用setCookie(),跟进
这个方法首先根据RFC 6265检查cookie是否有效,然后解决与之前设置的cookie的冲突,最后设置Cookie,于是Json同样可控,所以file_put_contents()的两个参数只要设置变量,均可控,构造POC
1 |
|
已经成功构造了恶意phar文件,需要一处可以上传的地方
上传点
正好前台发帖处有个富文本编辑器可以上传附件
上传一个图片然后断点调试,可以找到处理文件上传的地方phpbb/plupload/plupload.php:handle_upload()
这里用了分片上传的处理逻辑,首先获取分片的数量,假如小于2就直接返回;否则进入多分片处理。然后依次获取上传时name、chunk、fileupload
的值,获取文件目录,然后进入处理文件路径的函数temporary_filepath()
中,继续跟进
这里的路径是用四个变量给拼起来的,依次来看:
- $this->temporary_directory,通过Debug发现是
./files/plupload
- $this->config[‘plupload_salt’],这个配置项是存在数据库中的。幸运的是可以通过控制面板备份数据库获取该值
25223c5f29aeb6111e86dce71db3a2a9
- md5($file_name),file_name是文件上传时传入的,可控
- \phpbb\files\filespec::get_extension($file_name),文件后缀名,依旧可控
所以可以完全成功拼接出上传之后的文件路径了,继续回到handle_upload(),进入了另一个函数,继续跟进
经过一系列的判断之后,进入了fopen()中,也就是刚刚的路径拼接.part
后缀名作为临时文件,所以在上传文件的时候设置块数量为2,服务器就会一直等待第二块文件上传所以就不会删除临时文件
可以计算出临时文件路径和phar协议为
1 | ./files/plupload/25223c5f29aeb6111e86dce71db3a2a9_241aa215217fce83198ac3f187256b6bzip.part |
Getshell
既然已经知道了恶意文件的路径,就直接用phar协议去加载它触发反序列化
然后访问写入的shell.php
总结
虽然POP链调用比较简单,但是利用起来还是比较复杂的,文件上传之后找临时文件位置的思路还是不错。
Reference
https://blog.ripstech.com/2018/phpbb3-phar-deserialization-to-remote-code-execution/