备受打击 接收不了这么菜的自己了 也是在比赛中缺乏信心 几次操作后导致心态慌乱 总的来说 是自己的错误导致了 最后小组的排名不理想 自己还需要很多学习

逻辑漏洞

题目真的不难 自己需要反思
给的是一个thinkphp的框架的网站 在线下赛比赛中 往往需要部署流量监测的脚本 对于这种单入口的cms 在部署流量监测时 只需要找到重要的入口文件 包含流量监测脚本即可 (在比赛时 由于流量脚本的文件夹 权限有点问题 几次包含失败 导致服务挂掉 让自己心态发生了很大变化…)
再说说题目的漏洞 其中的漏洞之一是后台登陆逻辑漏洞
Alt text
存在两个登陆 一个是管理员登陆一个是用户登陆 管理员登陆只会在数据库中查询power为1的字段 的账号密码 即管理员 但是 后台主页面的验证逻辑(我想死…..):

1
2
3
4
5
6
7
8
public function __construct(){
parent::__construct();
if(!Session::have('userId'))
{
return $this->error('plz login first',url('admin/login/index'));
}
}

验证是否存在userid 所以直接导致普通用户登陆 即可拿到进入后台页面…….(没想到)
所以 修补方法:

1
if(!Session::get("userId")!=1){

加上正确的逻辑 验证是不是管理员

getshell

thinkphp5存在一个缓存getshell的洞 主要函数是Cache::set方法 来看看代码 在添加文章后 展示的文章的地方的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public function showArticle()
{
if(!input('?param.articleId'))
{
return $this->error("not input articleId");
}
$articleId = input('param.articleId');
$Map = array('id' => $articleId);
if(cache("?article_".$articleId))
{
$articleData = cache("article_".$articleId);
}
else {
$articleData = ArticleModel::get($Map);
cache('article_'.$articleId, $articleData);
}

其中关键的就是Cache的处理 当输入文章id对应没有缓存是 调用:

1
2
$articleData = ArticleModel::get($Map);
cache('article_'.$articleId, $articleData);

看一下cache的关键代码:

1
2
3
4
5
6
7
8
9
10
if (is_array($options)) {
$expire = isset($options['expire']) ? $options['expire'] : null; //修复查询缓存无法设置过期时间
} else {
$expire = is_numeric($options) ? $options : null; //默认快捷缓存设置过期时间
}
if (is_null($tag)) {
return Cache::set($name, $value, $expire);
} else {
return Cache::tag($tag)->set($name, $value, $expire);
}

在进行一些逻辑判断后 可以到达cache::set方法 其中$name'article_'.$articleId $value为文章数据库中相应数据 在thinkphp5中已知$name我们是可以推算出cache文件名 md5后取前2位为文件夹名 后面部分为文件名 而$value部分为添加文章的内容 此处没做处理 导致 内容可控 缓存getshell产生

防护:
对接收内容进行处理 或对cache文件名做处理 使之不可预测
过程:
先添加文章:
Alt text
预测cache文件地址:
Alt text
Alt text
最后访问效果:
Alt text

最后

真的太菜了……