漏洞介绍
WordPress是一套使用PHP语言开发的博客平台,该平台支持在PHP和MySQL的服务器上架设个人博客网站。而WordPress的文件管理器插件(wp-file-manager)6.9版本之前存在安全漏洞,该漏洞允许远程攻击者上传和执行任意PHP代码。
漏洞范围
WordPress 文件管理器(wp-file-manager)插件 6.0-6.8 版本
漏洞靶场
本次复现使用wp-file-manager 6.0版本
插件下载https://downloads.wordpress.org/plugin/wp-file-manager.6.0.zip
使用CVE-2024-4439的docker-compose.yml
1 | version: '3.8' |
把插件解压到plugins里面,该目录会挂载到容器内的插件目录
在http://127.0.0.1:8080/wp-admin/plugins.php内,把该插件启用一下

漏洞原理
从敏感函数逆向分析
elFinderVolumeLocalFileSystem类
敏感函数 copy 位于 elFinderVolumeLocalFileSystem类 的 _save方法
/wp-content/plugins/wp-file-manager/lib/php/elFinderVolumeLocalFileSystem.class.php
1 | protected function _save($fp, $dir, $name, $stat) |
wp-file-manager/lib/php/elFinderVolumeLocalFileSystem.class.php#L1018-L1044
uri=meta[‘uri’],meta取决于fp
1 | <?php |
path是dir.
这样如果 fp打开的一句话木马,并且path 为可访问 WEB路径,就可以 GetShell
elFinderVolumeDriver类
elFinderVolumeDriver类 的 saveCE方法 调用了 _save方法
1 | protected function saveCE($fp, $dir, $name, $stat) |
wp-file-manager/lib/php/elFinderVolumeDriver.class.php#L3821-L3828
elFinderVolumeDriver类 的 upload方法 调用了 saveCE方法
1 | public function upload($fp, $dst, $name, $tmpname, $hashes = array()) |
wp-file-manager/lib/php/elFinderVolumeDriver.class.php#L2438-L2523
dstpath和name 代表 copy 到的路径,dstpath取决于dst
查看 decode方法
1 | protected function decode($hash) |
wp-file-manager/lib/php/elFinderVolumeDriver.class.php#L3925-L3942
可以看出需要正确的 id 才能得到路径
elFinder类
在 elFinder类 的构造方法可以看到使用了 id
1 | public function __construct($opts) |
在下面添加:
1 | ob_end_flush(); |
直接访问 http://127.0.0.1/wp-content/plugins/wp-file-manager/lib/php/connector.minimal.php 可以看到响应的 id
1 | string(3) "l1_" |
其中 l1_ 是可以用的,也就是 $dst 要为 l1_
elFinder类
elFinderVolumeLocalFileSystem类 是 elFinderVolumeDriver类 的子类
elFinder类 的 upload方法 利用 elFinderVolumeLocalFileSystem类对象 调用了 elFinderVolumeDriver类 的 upload方法
1 | protected function upload($args) |
wp-file-manager/lib/php/elFinder.class.php#L3167-L3432
其中 $volume 就是 elFinderVolumeLocalFileSystem类对象,怎么知道的呢,看构造方法
1 | public function __construct($opts) |
wp-file-manager/lib/php/elFinder.class.php#L541-L813
在下面添加:
1 | ob_end_flush(); |
直接访问 http://127.0.0.1/wp-content/plugins/wp-file-manager/lib/php/connector.minimal.php 可以看到响应的对象
1 | object(elFinderVolumeLocalFileSystem)#4 (61) { |
再看 elFinder类 的 upload方法 是如何得到 elFinderVolumeDriver类 的 upload方法 的参数的
1 | protected function upload($args) |
wp-file-manager/lib/php/elFinder.class.php#L3167-L3472
可以看出来都存在 $args 中
elFinder类 的 exec方法 可以调用 elFinder类 的 upload方法
1 | public function exec($cmd, $args) |
wp-file-manager/lib/php/elFinder.class.php#L1068-L1311
如果 $cmd 为 upload,exec方法 就调用 elFinder类 的 upload方法 了
elFinderConnector类
elFinderConnector类 的 run方法 调用了 exec方法
1 | public function run() |
wp-file-manager/lib/php/elFinderConnector.class.php#L71-L172
可以看出来 POST请求 cmd 为 upload,就会调用 elFinder类 的 upload方法
当同时上传文件时,$args[‘FILES’] 将存储上传的文件的信息
elFinder类
在 elFinder类 可以看到 commandArgsList方法
1 | protected $commands = array( |
wp-file-manager/lib/php/elFinder.class.php#L1031-L1040
思路回到 elFinderConnector类
可以看出来当 POST 请求 cmd 为 upload 并且 target 为 l1_ 时,$args[‘target’] 将等于 l1_
1 | array(18) { |
思路回到 elFinderVolumeLocalFileSystem类
可以看出来当 POST 请求 cmd 为 upload 并且 target 为 l1_ 并且 上传文件 时,copy函数 会将临时文件 保存到 $path 路径
connector.minimal.php
connector.minimal.php 调用了 run方法
1 | $connector = new elFinderConnector(new elFinder($opts)); |
wp-file-manager/lib/php/connector.minimal.php#L177-L178
elFinderVolumeLocalFileSystem类
在 path=this->_joinPath(dir,name); 下面添加:
1 | ob_end_flush(); |
提交复现中的请求包,可以看到响应的一句话木马路径:…/wp-content/plugins/wp-file-manager/lib/files/shell.php
漏洞复现
浏览器访问http://127.0.0.1:8080/wp-content/plugins/wp-file-manager/lib/php/connector.minimal.php
出现下面到的errUnknownCmd说明漏洞存在

1 | POST /wp-content/plugins/wp-file-manager/lib/php/connector.minimal.php HTTP/1.1 |
上传一句话木马成功了之后

连接成功
使用exp
BLY-Coder/Python-exploit-CVE-2020-25213: Python exploit for RCE in Wordpress (github.com)
1 | python3 exploit.py url command |

成功
参考
CVE-2020-25213 WordPress远程代码执行漏洞复现 - Salvere - 博客园 (cnblogs.com)
WordPress wp-file-manager 文件上传漏洞 CVE-2020-25213-腾讯云开发者社区-腾讯云 (tencent.com)