0x00 概述

202103,网上曝出WordPress Plugin WP Super Cache 1.7.1 Remote Code Execution (Authenticated)漏洞。
该漏洞需要登录wp后台。
这是个典型的”写入配置文件getshell”的例子。

0x01 漏洞分析

WordPress 常用函数trailingslashit():调用untrailingslashit()并在末尾添加 /
untrailingslashit():移除字符串右侧的\和/两个字符。
dirname():函数返回路径中的目录名称部分
realpath():函数返回绝对路径。该函数删除所有符号连接(比如 '/./', '/../' 以及多余的 '/'),并返回绝对路径名。如果失败,该函数返回 FALSE。
basename():函数返回路径中的文件名部分
rtrim():函数移除字符串右侧的空白字符或其他预定义字符。

realpath函数会把结尾的/去掉。
最后传入$cache_path这个字符串,更新后的缓存路径,wp-cache-config.php文件。

$new即更新后的$cache_path,用户可控!
构造:
$cache_path = 'evil_input'; //Added by WP-Cache Manager
首先闭合前面的单引号,再注释掉后面的‘;即可
由于用//注释会被basename()去掉,所以用#来达到注释的效果。
最终payload:

';system($_GET[0]);#

或者:
这个payload也可以

/cache/';system($_GET[0]);?><!--

但是会有很多warning,而且格式混乱了不够美观。

0x02 漏洞重现

env:wordpress5.8+wp super cache1.4.8+phpstudy+php7.0.12+mysql5.5.53

https://wordpress.org/plugins/wp-super-cache/

只关注第31行即可
$cache_path = WP_CONTENT_DIR . '/cache/';

网上某篇分析文章的截图:

首先使用payload:

d:\wordpress_path/cache/';system($_GET['x']);#

发现payload没有写入进wp-cache-config.php,第31行内容没有变化,并且web页面反馈正常。

波折1:不可写?

首先怀疑是写入权限的问题
缓存位置输入框下有这样的提示:

很快排除这个可能,因为:
1:phpstudy是本地用户启动,权限够高。
2:wp super cache插件设置页面也提示wp-content路径可写。
3:尝试使用正常值aaa更新写入成功。

注意到修改成功会有个rename()的warning

波折2:版本问题?

其次想到是否是wp super cache不同版本会有细微的不同处理导致该payload失效,
遂尝试wp super cache 1.7.1,也是一样的效果。
故受版本影响的概率极小,暂时排除版本问题。

波折3:关键代码测试

抠出关键的两段代码,对关键变量进行输出测试。
复制/wp-include/formatting.php和wp-cahce-config.php到测试目录,再稍微修改关键代码即可。

结果发现该payload可以顺利写入,所以依旧没能找到原因,准备大刀阔斧利用phpstorm进行wordpress动态调试了。

波折4:输入处理?

继而想到可能wordpress/wp super cache某地方有做

$_POST[‘wp_cache_location’]

的过滤处理,结合波折2及相关分析,感觉概率极小,故暂时排除。

波折5:逐个排除特殊字符

既然正常值aaa没问题,而payload出现问题,那只可能是payload中的特殊字符有问题了。
先输入单引号,出现报错,可以写入单引号
d:\wordpress_path/cache/'

当输入到

D:\wordpress_path/cache/';system($_GET['])

中括号出现一个单引号,web页面反馈正常,wp-cache-config.php文件31行无变化,写入失败,
两个单引号也一样,那么问题就是在这位置的单引号了,更换payload。
成功payload:

d:\wordpress_path/cache/';system($_GET[0]);#

直接在当前的wp super cache设置页面传参即可
http://127.0.0.1:8899/lsawebtest/vulweb/wordpress/wordpress-v5-8/wp-admin/options-general.php?page=wpsupercache&tab=settings&0=whoami

经测试发现/cache/这个不能改,否则还是没效果。
或者需要改成存在的缓存文件夹(如前面波折1测试生成的aaa文件夹就行)

再回头看看网上某分析文章的代码:

为什么输入了中括号内有单引号还成功就不得而知了。(可能是截图放错了,实际使用的payload是没单引号那个)

0x03 漏洞修复

查看v1.7.4版本,增加了正则替换相关特殊字符为空,暂时没想到绕过方法。

wp-cache-config.php文件格式不对会报错无法rce。
漏洞文件很多地方都调用了这个函数,可能会有不同的构造方法,找找没过滤而且可以控的变量,稍微看了一下暂时没发现可利用点。

0x04 单引号之谜

为何中括号内有单引号就无法更新第31行呢?
推测是$new_cache_path/$dir这个变量并不是构造的恶意代码,而是因为存在单引号所以$dir被赋值为默认的WP_CONTENT_DIR . '/cache/';
所以没经过写入函数wp_cache_replace_line()。
即加了单引号使得这个第一个if为假了。(结合页面反馈正常,判断出第二个if没进入也可以辅助证明这一点)

if ( $new_cache_path != $cache_path ) {
            if ( file_exists( $new_cache_path ) == false )
                rename( $cache_path, $new_cache_path );
            $cache_path = $new_cache_path;
            wp_cache_replace_line('^ *\$cache_path', "\$cache_path = '" . $cache_path . "';", $wp_cache_config_file);
        }

找到该变量$cache_path

看来还是要动态调试......
让一切玄学在动态调试前无所遁形!
开始动态调试:
wp_cache_location传值正常!

$_POST['wp_cache_location']
D:\\phpStudy\\WWW\\lsawebtest\\vulweb\\wordpress\\wordpress-v5-8/wp-content/cache/\';system($_GET[\'x\']);#

dirname()后值出现异常!!!
‘];#这个几个字符咋没了???

D:\phpStudy\WWW\lsawebtest\vulweb\wordpress\wordpress-v5-8/wp-content/cache/\';system($_GET[\'x

接着经过realpath()后返回了false使得$dir为false从而赋值为默认的WP_CONTENT_DIR . '/cache/'

所以无法进入第一个if也就无法进入

wp_cache_replace_line('^ *\$cache_path', "\$cache_path = '" . $cache_path . "';", $wp_cache_config_file);

最后便没有修改第31行$cache_path = WP_CONTENT_DIR . '/cache/';
和前面分析的基本一致!
那么dirname()后,’];#这个几个字符咋没了???
是因为加了转义的\,最后一个\在x\’]这个位置,所以dirname()判断最后一个单引号之前为目录了。(’];#成了文件名)
至于\怎么加的,不深究了。

0x05 结语

1.不要过于相信网上的一些漏洞分析和payload。
2.逐步排查,排除了所有的不可能,剩下的无论多么难以置信,那就是真相。
3.保持冷静,注意细节。
4.payload越精简越好,尽量避免特殊字符。
5.遇到阻碍,放松一下过段时间再分析可能就解决了。

0x06 参考资料

https://www.exploit-db.com/exploits/49718

点击收藏 | 0 关注 | 1
  • 动动手指,沙发就是你的了!
登录 后跟帖